1
0
mirror of https://github.com/zitadel/zitadel.git synced 2025-03-31 17:52:17 +00:00

fix: push events ()

* fix: push events instead of aggregates

* fix: tests

* try without aggregate methods and with aggregate methods

* fix: change push aggregate to push events

* fix: change push aggregate to push events

* fix: change push aggregate to push events

* fix: change push aggregate to push events

* fix: change push aggregate to push events

* fix: change push aggregate to push events

* fix: change push aggregate to push events

* fix: change push aggregate to push events

* fix: change push aggregate to push events

* fix: change push aggregate to push events

* fix: client secret

* fix: query eventtypes

* fix: query eventtypes

* fix: eventstore index

* fix: index

* fix: merge new eventstore

* fix: remove unnecessary todos

* fix: remove unnecessary todos

Co-authored-by: Fabiennne <fabienne.gerschwiler@gmail.com>
This commit is contained in:
Silvan 2021-02-18 14:48:27 +01:00 committed by GitHub
parent 027a6386c0
commit 00fec8830a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
187 changed files with 3000 additions and 2161 deletions
cmd/zitadel
internal
api/oidc
eventstore/v2
v2/command
command.goiam.goiam_idp_config.goiam_idp_config_model.goiam_idp_oidc_config.goiam_idp_oidc_config_model.goiam_member.goiam_member_model.goiam_model.goiam_policy_label.goiam_policy_label_model.goiam_policy_login.goiam_policy_login_factors_model.goiam_policy_login_model.goiam_policy_mail_template.goiam_policy_mail_template_model.goiam_policy_mail_text.goiam_policy_mail_text_model.goiam_policy_org_iam.goiam_policy_org_iam_model.goiam_policy_password_age.goiam_policy_password_age_model.goiam_policy_password_complexity.goiam_policy_password_complexity_model.goiam_policy_password_lockout.goiam_policy_password_lockout_model.goidp_config_model.gokey_pair.gokey_pair_model.goorg.goorg_domain.goorg_domain_model.goorg_idp_config.goorg_idp_config_model.goorg_idp_oidc_config.goorg_idp_oidc_config_model.goorg_member.goorg_member_model.goorg_model.goorg_policy_label.goorg_policy_label_model.goorg_policy_login.goorg_policy_login_factors_model.goorg_policy_login_model.goorg_policy_mail_template.goorg_policy_mail_template_model.goorg_policy_mail_text.goorg_policy_mail_text_model.goorg_policy_org_iam.goorg_policy_org_iam_model.goorg_policy_password_age.goorg_policy_password_age_model.goorg_policy_password_complexity.goorg_policy_password_complexity_model.goorg_policy_password_lockout.goorg_policy_password_lockout_model.goproject.goproject_application.goproject_application_model.goproject_application_oidc.goproject_application_oidc_model.goproject_grant.goproject_grant_member.goproject_grant_member_model.goproject_member.goproject_member_model.goproject_model.goproject_role.goproject_role_model.gosetup.gosetup_step1.gosetup_step10.gosetup_step11.gosetup_step2.gosetup_step3.gosetup_step4.gosetup_step5.gosetup_step6.gosetup_step7.gosetup_step8.gosetup_step9.gounique_constraints_model.gouser.gouser_grant.gouser_grant_model.gouser_human.gouser_human_address.gouser_human_address_model.go

@ -15,7 +15,7 @@ SystemDefaults:
IncludeLowerLetters: true
IncludeUpperLetters: true
IncludeDigits: true
IncludeSymbols: true
IncludeSymbols: false
InitializeUserCode:
Length: 6
Expiry: '72h'

@ -89,7 +89,7 @@ func (o *OPStorage) CreateToken(ctx context.Context, req op.TokenRequest) (_ str
userAgentID = authReq.AgentID
applicationID = authReq.ApplicationID
}
resp, err := o.command.CreateUserToken(ctx, authReq.UserOrgID, userAgentID, applicationID, req.GetSubject(), req.GetAudience(), req.GetScopes(), o.defaultAccessTokenLifetime) //PLANNED: lifetime from client
resp, err := o.command.AddUserToken(ctx, authReq.UserOrgID, userAgentID, applicationID, req.GetSubject(), req.GetAudience(), req.GetScopes(), o.defaultAccessTokenLifetime) //PLANNED: lifetime from client
if err != nil {
return "", time.Time{}, err
}

@ -1,86 +1,66 @@
package eventstore
type Aggregater interface {
//ID returns the aggreagte id
ID() string
//KeyType returns the aggregate type
Type() AggregateType
//Events returns the events which will be pushed
Events() []EventPusher
//ResourceOwner returns the organisation id which manages this aggregate
// resource owner is only on the inital push needed
// afterwards the resource owner of the previous event is taken
ResourceOwner() string
//Version represents the semantic version of the aggregate
Version() Version
}
import (
"context"
"github.com/caos/zitadel/internal/api/authz"
)
type aggregateOpt func(*Aggregate)
//NewAggregate is the default constructor of an aggregate
// opts overwrite values calculated by given parameters
func NewAggregate(
ctx context.Context,
id string,
typ AggregateType,
resourceOwner string,
version Version,
opts ...aggregateOpt,
) *Aggregate {
return &Aggregate{
id: id,
typ: typ,
resourceOwner: resourceOwner,
version: version,
events: []EventPusher{},
a := &Aggregate{
ID: id,
Typ: typ,
ResourceOwner: authz.GetCtxData(ctx).OrgID,
Version: version,
}
for _, opt := range opts {
opt(a)
}
return a
}
//WithResourceOwner overwrites the resource owner of the aggregate
// by default the resource owner is set by the context
func WithResourceOwner(resourceOwner string) aggregateOpt {
return func(aggregate *Aggregate) {
aggregate.ResourceOwner = resourceOwner
}
}
//AggregateFromWriteModel maps the given WriteModel to an Aggregate
func AggregateFromWriteModel(
wm *WriteModel,
typ AggregateType,
version Version,
) *Aggregate {
return &Aggregate{
id: wm.AggregateID,
typ: typ,
resourceOwner: wm.ResourceOwner,
version: version,
events: []EventPusher{},
ID: wm.AggregateID,
Typ: typ,
ResourceOwner: wm.ResourceOwner,
Version: version,
}
}
//Aggregate is the basic implementation of Aggregater
type Aggregate struct {
id string `json:"-"`
typ AggregateType `json:"-"`
events []EventPusher `json:"-"`
resourceOwner string `json:"-"`
version Version `json:"-"`
}
//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
}
//ID implements Aggregater
func (a *Aggregate) ID() string {
return a.id
}
//KeyType 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
//ID is the unique identitfier of this aggregate
ID string `json:"-"`
//Typ is the name of the aggregate.
Typ AggregateType `json:"-"`
//ResourceOwner is the org this aggregates belongs to
ResourceOwner string `json:"-"`
//Version is the semver this aggregate represents
Version Version `json:"-"`
}

@ -5,6 +5,8 @@ import (
)
type EventPusher interface {
//Aggregate is the metadata of an aggregate
Aggregate() Aggregate
// EditorService is the service who wants to push the event
EditorService() string
//EditorUser is the user who wants to push the event
@ -30,10 +32,8 @@ type EventReader interface {
//KeyType is the type of the event
Type() EventType
AggregateID() string
AggregateType() AggregateType
ResourceOwner() string
AggregateVersion() Version
Aggregate() Aggregate
Sequence() uint64
CreationDate() time.Time
}

@ -9,15 +9,14 @@ import (
"github.com/caos/zitadel/internal/eventstore/v2/repository"
)
//BaseEvent represents the minimum metadata of an event
type BaseEvent struct {
aggregateID string `json:"-"`
aggregateType AggregateType `json:"-"`
EventType EventType `json:"-"`
EventType EventType
resourceOwner string `json:"-"`
aggregateVersion Version `json:"-"`
sequence uint64 `json:"-"`
creationDate time.Time `json:"-"`
aggregate Aggregate
sequence uint64
creationDate time.Time
//User is the user who created the event
User string `json:"-"`
@ -35,59 +34,51 @@ func (e *BaseEvent) EditorUser() string {
return e.User
}
//KeyType implements EventPusher
//Type implements EventPusher
func (e *BaseEvent) Type() EventType {
return e.EventType
}
func (e *BaseEvent) AggregateID() string {
return e.aggregateID
}
func (e *BaseEvent) AggregateType() AggregateType {
return e.aggregateType
}
func (e *BaseEvent) ResourceOwner() string {
return e.resourceOwner
}
func (e *BaseEvent) AggregateVersion() Version {
return e.aggregateVersion
}
//Sequence is an upcounting unique number of the event
func (e *BaseEvent) Sequence() uint64 {
return e.sequence
}
//CreationDate is the the time, the event is inserted into the eventstore
func (e *BaseEvent) CreationDate() time.Time {
return e.creationDate
}
//Aggregate represents the metadata of the event's aggregate
func (e *BaseEvent) Aggregate() Aggregate {
return e.aggregate
}
//BaseEventFromRepo maps a stored event to a BaseEvent
func BaseEventFromRepo(event *repository.Event) *BaseEvent {
return &BaseEvent{
aggregateID: event.AggregateID,
aggregateType: AggregateType(event.AggregateType),
aggregateVersion: Version(event.Version),
EventType: EventType(event.Type),
creationDate: event.CreationDate,
sequence: event.Sequence,
resourceOwner: event.ResourceOwner,
Service: event.EditorService,
User: event.EditorUser,
aggregate: Aggregate{
ID: event.AggregateID,
Typ: AggregateType(event.AggregateType),
ResourceOwner: event.ResourceOwner,
Version: Version(event.Version),
},
EventType: EventType(event.Type),
creationDate: event.CreationDate,
sequence: event.Sequence,
Service: event.EditorService,
User: event.EditorUser,
}
}
func NewBaseEventForPush(ctx context.Context, typ EventType) *BaseEvent {
svcName := service.FromContext(ctx)
//NewBaseEventForPush is the constructor for event's which will be pushed into the eventstore
// the resource owner of the aggregate is only used if it's the first event of this aggregateroot
// afterwards the resource owner of the first previous events is taken
func NewBaseEventForPush(ctx context.Context, aggregate *Aggregate, typ EventType) *BaseEvent {
return &BaseEvent{
aggregate: *aggregate,
User: authz.GetCtxData(ctx).UserID,
Service: svcName,
Service: service.FromContext(ctx),
EventType: typ,
}
}
func NewBaseEventForPushWithResourceOwner(ctx context.Context, typ EventType, resourceOwner string) *BaseEvent {
svcName := service.FromContext(ctx)
return &BaseEvent{
User: authz.GetCtxData(ctx).UserID,
Service: svcName,
EventType: typ,
resourceOwner: resourceOwner,
}
}

@ -36,67 +36,56 @@ func (es *Eventstore) Health(ctx context.Context) error {
return es.repo.Health(ctx)
}
//PushAggregate pushes the aggregate and reduces the new events on the aggregate
func (es *Eventstore) PushAggregate(ctx context.Context, writeModel queryReducer, aggregate Aggregater) error {
events, err := es.PushAggregates(ctx, aggregate)
if err != nil {
return err
}
writeModel.AppendEvents(events...)
return writeModel.Reduce()
}
//PushAggregates maps the events of all aggregates to an eventstore event
// based on the pushMapper
func (es *Eventstore) PushAggregates(ctx context.Context, aggregates ...Aggregater) ([]EventReader, error) {
events, uniqueConstraints, err := es.aggregatesToEvents(aggregates)
//PushEvents pushes the events in a single transaction
// an event needs at least an aggregate
func (es *Eventstore) PushEvents(ctx context.Context, pushEvents ...EventPusher) ([]EventReader, error) {
events, constraints, err := eventsToRepository(pushEvents)
if err != nil {
return nil, err
}
err = es.repo.Push(ctx, events, uniqueConstraints...)
err = es.repo.Push(ctx, events, constraints...)
if err != nil {
return nil, err
}
return es.mapEvents(events)
}
func (es *Eventstore) aggregatesToEvents(aggregates []Aggregater) ([]*repository.Event, []*repository.UniqueConstraint, error) {
events := make([]*repository.Event, 0, len(aggregates))
uniqueConstraints := make([]*repository.UniqueConstraint, 0)
for _, aggregate := range aggregates {
for _, event := range aggregate.Events() {
data, err := eventData(event)
if err != nil {
return nil, nil, err
}
events = append(events, &repository.Event{
AggregateID: aggregate.ID(),
AggregateType: repository.AggregateType(aggregate.Type()),
ResourceOwner: aggregate.ResourceOwner(),
EditorService: event.EditorService(),
EditorUser: event.EditorUser(),
Type: repository.EventType(event.Type()),
Version: repository.Version(aggregate.Version()),
Data: data,
})
if event.UniqueConstraints() != nil {
for _, constraint := range event.UniqueConstraints() {
uniqueConstraints = append(uniqueConstraints,
&repository.UniqueConstraint{
UniqueType: constraint.UniqueType,
UniqueField: constraint.UniqueField,
Action: uniqueConstraintActionToRepository(constraint.Action),
ErrorMessage: constraint.ErrorMessage,
},
)
}
}
func eventsToRepository(pushEvents []EventPusher) (events []*repository.Event, constraints []*repository.UniqueConstraint, err error) {
events = make([]*repository.Event, len(pushEvents))
for i, event := range pushEvents {
data, err := eventData(event)
if err != nil {
return nil, nil, err
}
events[i] = &repository.Event{
AggregateID: event.Aggregate().ID,
AggregateType: repository.AggregateType(event.Aggregate().Typ),
ResourceOwner: event.Aggregate().ResourceOwner,
EditorService: event.EditorService(),
EditorUser: event.EditorUser(),
Type: repository.EventType(event.Type()),
Version: repository.Version(event.Aggregate().Version),
Data: data,
}
if len(event.UniqueConstraints()) > 0 {
constraints = append(constraints, uniqueConstraintsToRepository(event.UniqueConstraints())...)
}
}
return events, uniqueConstraints, nil
return events, constraints, nil
}
func uniqueConstraintsToRepository(constraints []*EventUniqueConstraint) (uniqueConstraints []*repository.UniqueConstraint) {
uniqueConstraints = make([]*repository.UniqueConstraint, len(constraints))
for i, constraint := range constraints {
uniqueConstraints[i] = &repository.UniqueConstraint{
UniqueType: constraint.UniqueType,
UniqueField: constraint.UniqueField,
Action: uniqueConstraintActionToRepository(constraint.Action),
ErrorMessage: constraint.ErrorMessage,
}
}
return uniqueConstraints
}
//FilterEvents filters the stored events based on the searchQuery

@ -31,7 +31,7 @@ func (a *testAggregate) Events() []EventPusher {
}
func (a *testAggregate) ResourceOwner() string {
return "ro"
return "caos"
}
func (a *testAggregate) Version() Version {
@ -47,13 +47,14 @@ type testEvent struct {
data func() interface{}
}
func newTestEvent(description string, data func() interface{}, checkPrevious bool) *testEvent {
func newTestEvent(id, description string, data func() interface{}, checkPrevious bool) *testEvent {
return &testEvent{
description: description,
data: data,
shouldCheckPrevious: checkPrevious,
BaseEvent: *NewBaseEventForPush(
service.WithService(authz.NewMockContext("resourceOwner", "editorUser"), "editorService"),
NewAggregate(authz.NewMockContext("caos", "adlerhurst"), id, "test.aggregate", "v1"),
"test.event",
),
}
@ -69,7 +70,7 @@ func (e *testEvent) UniqueConstraints() []*EventUniqueConstraint {
func testFilterMapper(event *repository.Event) (EventReader, error) {
if event == nil {
return newTestEvent("hodor", nil, false), nil
return newTestEvent("testID", "hodor", nil, false), nil
}
return &testEvent{description: "hodor", BaseEvent: *BaseEventFromRepo(event)}, nil
}
@ -129,7 +130,7 @@ func Test_eventstore_RegisterFilterEventMapper(t *testing.T) {
mapper: testFilterMapper,
},
res: res{
event: newTestEvent("hodor", nil, false),
event: newTestEvent("testID", "hodor", nil, false),
mapperCount: 1,
},
},
@ -145,7 +146,7 @@ func Test_eventstore_RegisterFilterEventMapper(t *testing.T) {
mapper: testFilterMapper,
},
res: res{
event: newTestEvent("hodor", nil, false),
event: newTestEvent("testID", "hodor", nil, false),
mapperCount: 2,
},
},
@ -165,7 +166,7 @@ func Test_eventstore_RegisterFilterEventMapper(t *testing.T) {
mapper: testFilterMapper,
},
res: res{
event: newTestEvent("hodor", nil, false),
event: newTestEvent("testID", "hodor", nil, false),
mapperCount: 2,
},
},
@ -215,6 +216,7 @@ func Test_eventData(t *testing.T) {
name: "data as json bytes",
args: args{
event: newTestEvent(
"id",
"hodor",
func() interface{} {
return []byte(`{"piff":"paff"}`)
@ -230,6 +232,7 @@ func Test_eventData(t *testing.T) {
name: "data as invalid json bytes",
args: args{
event: newTestEvent(
"id",
"hodor",
func() interface{} {
return []byte(`{"piffpaff"}`)
@ -245,6 +248,7 @@ func Test_eventData(t *testing.T) {
name: "data as struct",
args: args{
event: newTestEvent(
"id",
"hodor",
func() interface{} {
return struct {
@ -262,6 +266,7 @@ func Test_eventData(t *testing.T) {
name: "data as ptr to struct",
args: args{
event: newTestEvent(
"id",
"hodor",
func() interface{} {
return &struct {
@ -279,6 +284,7 @@ func Test_eventData(t *testing.T) {
name: "no data",
args: args{
event: newTestEvent(
"id",
"hodor",
func() interface{} {
return nil
@ -294,6 +300,7 @@ func Test_eventData(t *testing.T) {
name: "invalid because primitive",
args: args{
event: newTestEvent(
"id",
"hodor",
func() interface{} {
return ""
@ -309,6 +316,7 @@ func Test_eventData(t *testing.T) {
name: "invalid because pointer to primitive",
args: args{
event: newTestEvent(
"id",
"hodor",
func() interface{} {
var s string
@ -325,6 +333,7 @@ func Test_eventData(t *testing.T) {
name: "invalid because invalid struct for json",
args: args{
event: newTestEvent(
"id",
"hodor",
func() interface{} {
return struct {
@ -355,7 +364,8 @@ func Test_eventData(t *testing.T) {
func TestEventstore_aggregatesToEvents(t *testing.T) {
type args struct {
aggregates []Aggregater
aggregates []Aggregate
events []EventPusher
}
type res struct {
wantErr bool
@ -369,18 +379,14 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
{
name: "one aggregate one event",
args: args{
aggregates: []Aggregater{
&testAggregate{
id: "1",
events: []EventPusher{
newTestEvent(
"",
func() interface{} {
return nil
},
false),
events: []EventPusher{
newTestEvent(
"1",
"",
func() interface{} {
return nil
},
},
false),
},
},
res: res{
@ -392,7 +398,7 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -402,24 +408,21 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
{
name: "one aggregate multiple events",
args: args{
aggregates: []Aggregater{
&testAggregate{
id: "1",
events: []EventPusher{
newTestEvent(
"",
func() interface{} {
return nil
},
false),
newTestEvent(
"",
func() interface{} {
return nil
},
false),
events: []EventPusher{
newTestEvent(
"1",
"",
func() interface{} {
return nil
},
},
false),
newTestEvent(
"1",
"",
func() interface{} {
return nil
},
false),
},
},
res: res{
@ -431,7 +434,7 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -441,7 +444,7 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -451,18 +454,14 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
{
name: "invalid data",
args: args{
aggregates: []Aggregater{
&testAggregate{
id: "1",
events: []EventPusher{
newTestEvent(
"",
func() interface{} {
return `{"data":""`
},
false),
events: []EventPusher{
newTestEvent(
"1",
"",
func() interface{} {
return `{"data":""`
},
},
false),
},
},
res: res{
@ -472,35 +471,28 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
{
name: "multiple aggregates",
args: args{
aggregates: []Aggregater{
&testAggregate{
id: "1",
events: []EventPusher{
newTestEvent(
"",
func() interface{} {
return nil
},
false),
newTestEvent(
"",
func() interface{} {
return nil
},
false),
events: []EventPusher{
newTestEvent(
"1",
"",
func() interface{} {
return nil
},
},
&testAggregate{
id: "2",
events: []EventPusher{
newTestEvent(
"",
func() interface{} {
return nil
},
true),
false),
newTestEvent(
"1",
"",
func() interface{} {
return nil
},
},
false),
newTestEvent(
"2",
"",
func() interface{} {
return nil
},
true),
},
},
res: res{
@ -513,7 +505,7 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -523,7 +515,7 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -535,7 +527,7 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -546,8 +538,7 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
es := &Eventstore{}
events, _, err := es.aggregatesToEvents(tt.args.aggregates)
events, _, err := eventsToRepository(tt.args.events)
if (err != nil) != tt.res.wantErr {
t.Errorf("Eventstore.aggregatesToEvents() error = %v, wantErr %v", err, tt.res.wantErr)
return
@ -613,7 +604,7 @@ func (repo *testRepo) LatestSequence(ctx context.Context, queryFactory *reposito
func TestEventstore_Push(t *testing.T) {
type args struct {
aggregates []Aggregater
events []EventPusher
}
type fields struct {
repo *testRepo
@ -631,18 +622,14 @@ func TestEventstore_Push(t *testing.T) {
{
name: "one aggregate one event",
args: args{
aggregates: []Aggregater{
&testAggregate{
id: "1",
events: []EventPusher{
newTestEvent(
"",
func() interface{} {
return nil
},
false),
events: []EventPusher{
newTestEvent(
"1",
"",
func() interface{} {
return nil
},
},
false),
},
},
fields: fields{
@ -655,7 +642,7 @@ func TestEventstore_Push(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -671,24 +658,21 @@ func TestEventstore_Push(t *testing.T) {
{
name: "one aggregate multiple events",
args: args{
aggregates: []Aggregater{
&testAggregate{
id: "1",
events: []EventPusher{
newTestEvent(
"",
func() interface{} {
return nil
},
false),
newTestEvent(
"",
func() interface{} {
return nil
},
false),
events: []EventPusher{
newTestEvent(
"1",
"",
func() interface{} {
return nil
},
},
false),
newTestEvent(
"1",
"",
func() interface{} {
return nil
},
false),
},
},
fields: fields{
@ -701,7 +685,7 @@ func TestEventstore_Push(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -711,7 +695,7 @@ func TestEventstore_Push(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -730,35 +714,28 @@ func TestEventstore_Push(t *testing.T) {
{
name: "multiple aggregates",
args: args{
aggregates: []Aggregater{
&testAggregate{
id: "1",
events: []EventPusher{
newTestEvent(
"",
func() interface{} {
return nil
},
false),
newTestEvent(
"",
func() interface{} {
return nil
},
false),
events: []EventPusher{
newTestEvent(
"1",
"",
func() interface{} {
return nil
},
},
&testAggregate{
id: "2",
events: []EventPusher{
newTestEvent(
"",
func() interface{} {
return nil
},
true),
false),
newTestEvent(
"1",
"",
func() interface{} {
return nil
},
},
false),
newTestEvent(
"2",
"",
func() interface{} {
return nil
},
true),
},
},
fields: fields{
@ -772,7 +749,7 @@ func TestEventstore_Push(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -782,7 +759,7 @@ func TestEventstore_Push(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -794,7 +771,7 @@ func TestEventstore_Push(t *testing.T) {
Data: []byte(nil),
EditorService: "editorService",
EditorUser: "editorUser",
ResourceOwner: "ro",
ResourceOwner: "caos",
Type: "test.event",
Version: "v1",
},
@ -814,18 +791,14 @@ func TestEventstore_Push(t *testing.T) {
{
name: "push fails",
args: args{
aggregates: []Aggregater{
&testAggregate{
id: "1",
events: []EventPusher{
newTestEvent(
"",
func() interface{} {
return nil
},
false),
events: []EventPusher{
newTestEvent(
"1",
"",
func() interface{} {
return nil
},
},
false),
},
},
fields: fields{
@ -841,18 +814,14 @@ func TestEventstore_Push(t *testing.T) {
{
name: "aggreagtes to events mapping fails",
args: args{
aggregates: []Aggregater{
&testAggregate{
id: "1",
events: []EventPusher{
newTestEvent(
"",
func() interface{} {
return `{"data":""`
},
false),
events: []EventPusher{
newTestEvent(
"1",
"",
func() interface{} {
return `{"data":""`
},
},
false),
},
},
fields: fields{
@ -881,7 +850,7 @@ func TestEventstore_Push(t *testing.T) {
t.FailNow()
}
_, err := es.PushAggregates(context.Background(), tt.args.aggregates...)
_, err := es.PushEvents(context.Background(), tt.args.events...)
if (err != nil) != tt.res.wantErr {
t.Errorf("Eventstore.aggregatesToEvents() error = %v, wantErr %v", err, tt.res.wantErr)
}
@ -1313,13 +1282,13 @@ func compareEvents(t *testing.T, want, got *repository.Event) {
t.Helper()
if want.AggregateID != got.AggregateID {
t.Errorf("wrong aggregateID got %q want %q", want.AggregateID, got.AggregateID)
t.Errorf("wrong aggregateID got %q want %q", got.AggregateID, want.AggregateID)
}
if want.AggregateType != got.AggregateType {
t.Errorf("wrong aggregateType got %q want %q", want.AggregateType, got.AggregateType)
t.Errorf("wrong aggregateType got %q want %q", got.AggregateType, want.AggregateType)
}
if !reflect.DeepEqual(want.Data, got.Data) {
t.Errorf("wrong data got %s want %s", string(want.Data), string(got.Data))
t.Errorf("wrong data got %s want %s", string(got.Data), string(want.Data))
}
if want.EditorService != got.EditorService {
t.Errorf("wrong editor service got %q want %q", got.EditorService, want.EditorService)

@ -7,6 +7,7 @@ import (
"testing"
"time"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/eventstore/v2/repository"
"github.com/caos/zitadel/internal/eventstore/v2/repository/sql"
@ -15,34 +16,13 @@ import (
// ------------------------------------------------------------
// User aggregate start
// ------------------------------------------------------------
type UserAggregate struct {
eventstore.Aggregate
FirstName string
}
func NewUserAggregate(id string) *UserAggregate {
return &UserAggregate{
Aggregate: *eventstore.NewAggregate(
id,
"test.user",
"caos",
"v1",
),
}
}
func (rm *UserAggregate) Reduce() error {
for _, event := range rm.Aggregate.Events() {
switch e := event.(type) {
case *UserAddedEvent:
rm.FirstName = e.FirstName
case *UserFirstNameChangedEvent:
rm.FirstName = e.FirstName
}
}
return nil
func NewUserAggregate(id string) *eventstore.Aggregate {
return eventstore.NewAggregate(
authz.NewMockContext("caos", "adlerhurst"),
id,
"test.user",
"v1",
)
}
// ------------------------------------------------------------
@ -55,14 +35,13 @@ type UserAddedEvent struct {
FirstName string `json:"firstName"`
}
func NewUserAddedEvent(firstName string) *UserAddedEvent {
func NewUserAddedEvent(id string, firstName string) *UserAddedEvent {
return &UserAddedEvent{
FirstName: firstName,
BaseEvent: eventstore.BaseEvent{
Service: "test.suite",
User: "adlerhurst",
EventType: "user.added",
},
BaseEvent: *eventstore.NewBaseEventForPush(
context.Background(),
NewUserAggregate(id),
"user.added"),
}
}
@ -97,14 +76,13 @@ type UserFirstNameChangedEvent struct {
FirstName string `json:"firstName"`
}
func NewUserFirstNameChangedEvent(firstName string) *UserFirstNameChangedEvent {
func NewUserFirstNameChangedEvent(id, firstName string) *UserFirstNameChangedEvent {
return &UserFirstNameChangedEvent{
FirstName: firstName,
BaseEvent: eventstore.BaseEvent{
Service: "test.suite",
User: "adlerhurst",
EventType: "user.firstName.changed",
},
BaseEvent: *eventstore.NewBaseEventForPush(
context.Background(),
NewUserAggregate(id),
"user.firstname.changed"),
}
}
@ -137,13 +115,12 @@ type UserPasswordCheckedEvent struct {
eventstore.BaseEvent `json:"-"`
}
func NewUserPasswordCheckedEvent() *UserPasswordCheckedEvent {
func NewUserPasswordCheckedEvent(id string) *UserPasswordCheckedEvent {
return &UserPasswordCheckedEvent{
BaseEvent: eventstore.BaseEvent{
Service: "test.suite",
User: "adlerhurst",
EventType: "user.password.checked",
},
BaseEvent: *eventstore.NewBaseEventForPush(
context.Background(),
NewUserAggregate(id),
"user.password.checked"),
}
}
@ -171,13 +148,12 @@ type UserDeletedEvent struct {
eventstore.BaseEvent `json:"-"`
}
func NewUserDeletedEvent() *UserDeletedEvent {
func NewUserDeletedEvent(id string) *UserDeletedEvent {
return &UserDeletedEvent{
BaseEvent: eventstore.BaseEvent{
Service: "test.suite",
User: "adlerhurst",
EventType: "user.deleted",
},
BaseEvent: *eventstore.NewBaseEventForPush(
context.Background(),
NewUserAggregate(id),
"user.deleted"),
}
}
@ -213,18 +189,18 @@ func (rm *UsersReadModel) AppendEvents(events ...eventstore.EventReader) {
switch e := event.(type) {
case *UserAddedEvent:
//insert
user := NewUserReadModel(e.AggregateID())
user := NewUserReadModel(e.Aggregate().ID)
rm.Users = append(rm.Users, user)
user.AppendEvents(e)
case *UserFirstNameChangedEvent, *UserPasswordCheckedEvent:
//update
_, user := rm.userByID(e.AggregateID())
_, user := rm.userByID(e.Aggregate().ID)
if user == nil {
return
}
user.AppendEvents(e)
case *UserDeletedEvent:
idx, _ := rm.userByID(e.AggregateID())
idx, _ := rm.userByID(e.Aggregate().ID)
if idx < 0 {
return
}
@ -302,11 +278,14 @@ func TestUserReadModel(t *testing.T) {
RegisterFilterEventMapper(UserPasswordCheckedMapper()).
RegisterFilterEventMapper(UserDeletedMapper())
events, err := es.PushAggregates(context.Background(),
NewUserAggregate("1").PushEvents(NewUserAddedEvent("hodor")),
NewUserAggregate("2").PushEvents(NewUserAddedEvent("hodor"), NewUserPasswordCheckedEvent(), NewUserPasswordCheckedEvent(), NewUserFirstNameChangedEvent("ueli")),
NewUserAggregate("2").PushEvents(NewUserDeletedEvent()),
)
events, err := es.PushEvents(context.Background(),
NewUserAddedEvent("1", "hodor"),
NewUserAddedEvent("2", "hodor"),
NewUserPasswordCheckedEvent("2"),
NewUserPasswordCheckedEvent("2"),
NewUserFirstNameChangedEvent("2", "ueli"),
NewUserDeletedEvent("2"))
if err != nil {
t.Errorf("unexpected error on push aggregates: %v", err)
}

@ -2,7 +2,7 @@ package eventstore
import "time"
//MemberReadModel is the minimum representation of a View model.
//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 {
@ -29,10 +29,10 @@ func (rm *ReadModel) Reduce() error {
}
if rm.AggregateID == "" {
rm.AggregateID = rm.Events[0].AggregateID()
rm.AggregateID = rm.Events[0].Aggregate().ID
}
if rm.ResourceOwner == "" {
rm.ResourceOwner = rm.Events[0].ResourceOwner()
rm.ResourceOwner = rm.Events[0].Aggregate().ResourceOwner
}
if rm.CreationDate.IsZero() {

@ -93,7 +93,7 @@ func (factory *SearchQueryBuilder) build() (*repository.SearchQuery, error) {
if factory == nil ||
len(factory.aggregateTypes) < 1 ||
factory.columns.Validate() != nil {
return nil, errors.ThrowPreconditionFailed(nil, "MODEL-tGAD3", "factory invalid")
return nil, errors.ThrowPreconditionFailed(nil, "MODEL-4m9gs", "factory invalid")
}
filters := []*repository.Filter{
factory.aggregateTypeFilter(),

@ -488,7 +488,7 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
}
if !reflect.DeepEqual(query, tt.res.query) {
t.Errorf("NewSearchQueryFactory() = %+v, want %+v", factory, tt.res)
t.Errorf("NewSearchQueryFactory() = %+v, want %+v", factory, tt.res.query)
}
})
}

@ -15,9 +15,8 @@ type WriteModel struct {
//AppendEvents adds all the events to the read model.
// The function doesn't compute the new state of the read model
func (rm *WriteModel) AppendEvents(events ...EventReader) *WriteModel {
func (rm *WriteModel) AppendEvents(events ...EventReader) {
rm.Events = append(rm.Events, events...)
return rm
}
//Reduce is the basic implementaion of reducer
@ -28,10 +27,10 @@ func (wm *WriteModel) Reduce() error {
}
if wm.AggregateID == "" {
wm.AggregateID = wm.Events[0].AggregateID()
wm.AggregateID = wm.Events[0].Aggregate().ID
}
if wm.ResourceOwner == "" {
wm.ResourceOwner = wm.Events[0].ResourceOwner()
wm.ResourceOwner = wm.Events[0].Aggregate().ResourceOwner
}
wm.ProcessedSequence = wm.Events[len(wm.Events)-1].Sequence()

@ -131,3 +131,11 @@ func (r *CommandSide) getIAMWriteModel(ctx context.Context) (_ *IAMWriteModel, e
return writeModel, nil
}
func AppendAndReduce(object interface {
AppendEvents(...eventstore.EventReader)
Reduce() error
}, events ...eventstore.EventReader) error {
object.AppendEvents(events...)
return object.Reduce()
}

@ -2,6 +2,7 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
@ -18,26 +19,24 @@ func (r *CommandSide) GetIAM(ctx context.Context) (*domain.IAM, error) {
return writeModelToIAM(iamWriteModel), nil
}
func (r *CommandSide) setGlobalOrg(ctx context.Context, iamAgg *iam.Aggregate, iamWriteModel *IAMWriteModel, orgID string) error {
func (r *CommandSide) setGlobalOrg(ctx context.Context, iamAgg *eventstore.Aggregate, iamWriteModel *IAMWriteModel, orgID string) (eventstore.EventPusher, error) {
err := r.eventstore.FilterToQueryReducer(ctx, iamWriteModel)
if err != nil {
return err
return nil, err
}
if iamWriteModel.GlobalOrgID != "" {
return caos_errs.ThrowPreconditionFailed(nil, "IAM-HGG24", "Errors.IAM.GlobalOrgAlreadySet")
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-HGG24", "Errors.IAM.GlobalOrgAlreadySet")
}
iamAgg.PushEvents(iam.NewGlobalOrgSetEventEvent(ctx, orgID))
return nil
return iam.NewGlobalOrgSetEventEvent(ctx, iamAgg, orgID), nil
}
func (r *CommandSide) setIAMProject(ctx context.Context, iamAgg *iam.Aggregate, iamWriteModel *IAMWriteModel, projectID string) error {
func (r *CommandSide) setIAMProject(ctx context.Context, iamAgg *eventstore.Aggregate, iamWriteModel *IAMWriteModel, projectID string) (eventstore.EventPusher, error) {
err := r.eventstore.FilterToQueryReducer(ctx, iamWriteModel)
if err != nil {
return err
return nil, err
}
if iamWriteModel.ProjectID != "" {
return caos_errs.ThrowPreconditionFailed(nil, "IAM-EGbw2", "Errors.IAM.IAMProjectAlreadySet")
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-EGbw2", "Errors.IAM.IAMProjectAlreadySet")
}
iamAgg.PushEvents(iam.NewIAMProjectSetEvent(ctx, projectID))
return nil
return iam.NewIAMProjectSetEvent(ctx, iamAgg, projectID), nil
}

@ -2,9 +2,8 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
@ -30,18 +29,19 @@ func (r *CommandSide) AddDefaultIDPConfig(ctx context.Context, config *domain.ID
}
iamAgg := IAMAggregateFromWriteModel(&addedConfig.WriteModel)
iamAgg.PushEvents(
events := []eventstore.EventPusher{
iam_repo.NewIDPConfigAddedEvent(
ctx,
iamAgg,
idpConfigID,
config.Name,
config.Type,
config.StylingType,
),
)
iamAgg.PushEvents(
iam_repo.NewIDPOIDCConfigAddedEvent(
ctx, config.OIDCConfig.ClientID,
ctx,
iamAgg,
config.OIDCConfig.ClientID,
idpConfigID,
config.OIDCConfig.Issuer,
clientSecret,
@ -49,8 +49,13 @@ func (r *CommandSide) AddDefaultIDPConfig(ctx context.Context, config *domain.ID
config.OIDCConfig.UsernameMapping,
config.OIDCConfig.Scopes...,
),
)
err = r.eventstore.PushAggregate(ctx, addedConfig, iamAgg)
}
pushedEvents, err := r.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedConfig, pushedEvents...)
if err != nil {
return nil, err
}
@ -66,14 +71,16 @@ func (r *CommandSide) ChangeDefaultIDPConfig(ctx context.Context, config *domain
return nil, caos_errs.ThrowNotFound(nil, "IAM-4M9so", "Errors.IAM.IDPConfig.NotExisting")
}
changedEvent, hasChanged := existingIDP.NewChangedEvent(ctx, existingIDP.ResourceOwner, config.IDPConfigID, config.Name, config.StylingType)
iamAgg := IAMAggregateFromWriteModel(&existingIDP.WriteModel)
changedEvent, hasChanged := existingIDP.NewChangedEvent(ctx, iamAgg, config.IDPConfigID, config.Name, config.StylingType)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingIDP.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingIDP, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingIDP, pushedEvents...)
if err != nil {
return nil, err
}
@ -89,9 +96,8 @@ func (r *CommandSide) DeactivateDefaultIDPConfig(ctx context.Context, idpID stri
return caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9so", "Errors.IAM.IDPConfig.NotActive")
}
iamAgg := IAMAggregateFromWriteModel(&existingIDP.WriteModel)
iamAgg.PushEvents(iam_repo.NewIDPConfigDeactivatedEvent(ctx, idpID))
return r.eventstore.PushAggregate(ctx, existingIDP, iamAgg)
_, err = r.eventstore.PushEvents(ctx, iam_repo.NewIDPConfigDeactivatedEvent(ctx, iamAgg, idpID))
return err
}
func (r *CommandSide) ReactivateDefaultIDPConfig(ctx context.Context, idpID string) error {
@ -103,9 +109,8 @@ func (r *CommandSide) ReactivateDefaultIDPConfig(ctx context.Context, idpID stri
return caos_errs.ThrowPreconditionFailed(nil, "IAM-5Mo0d", "Errors.IAM.IDPConfig.NotInactive")
}
iamAgg := IAMAggregateFromWriteModel(&existingIDP.WriteModel)
iamAgg.PushEvents(iam_repo.NewIDPConfigReactivatedEvent(ctx, idpID))
return r.eventstore.PushAggregate(ctx, existingIDP, iamAgg)
_, err = r.eventstore.PushEvents(ctx, iam_repo.NewIDPConfigReactivatedEvent(ctx, iamAgg, idpID))
return err
}
func (r *CommandSide) RemoveDefaultIDPConfig(ctx context.Context, idpID string, idpProviders []*domain.IDPProvider, externalIDPs ...*domain.ExternalIDP) error {
@ -117,22 +122,22 @@ func (r *CommandSide) RemoveDefaultIDPConfig(ctx context.Context, idpID string,
return caos_errs.ThrowNotFound(nil, "IAM-4M0xy", "Errors.IAM.IDPConfig.NotExisting")
}
aggregates := make([]eventstore.Aggregater, 0)
iamAgg := IAMAggregateFromWriteModel(&existingIDP.WriteModel)
iamAgg.PushEvents(iam_repo.NewIDPConfigRemovedEvent(ctx, existingIDP.ResourceOwner, idpID, existingIDP.Name))
userAggregates := make([]eventstore.Aggregater, 0)
for _, idpProvider := range idpProviders {
if idpProvider.AggregateID == domain.IAMID {
userAggregates = r.removeIDPProviderFromDefaultLoginPolicy(ctx, iamAgg, idpProvider, true, externalIDPs...)
}
orgAgg := OrgAggregateFromWriteModel(&NewOrgIdentityProviderWriteModel(idpProvider.AggregateID, idpID).WriteModel)
r.removeIDPProviderFromLoginPolicy(ctx, orgAgg, idpID, true)
events := []eventstore.EventPusher{
iam_repo.NewIDPConfigRemovedEvent(ctx, iamAgg, idpID, existingIDP.Name),
}
aggregates = append(aggregates, iamAgg)
aggregates = append(aggregates, userAggregates...)
_, err = r.eventstore.PushAggregates(ctx, aggregates...)
for _, idpProvider := range idpProviders {
if idpProvider.AggregateID == domain.IAMID {
userEvents := r.removeIDPProviderFromDefaultLoginPolicy(ctx, iamAgg, idpProvider, true, externalIDPs...)
events = append(events, userEvents...)
}
orgAgg := OrgAggregateFromWriteModel(&NewOrgIdentityProviderWriteModel(idpProvider.AggregateID, idpID).WriteModel)
orgEvents := r.removeIDPProviderFromLoginPolicy(ctx, orgAgg, idpID, true)
events = append(events, orgEvents...)
}
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}

@ -28,7 +28,16 @@ func NewIAMIDPConfigWriteModel(configID string) *IAMIDPConfigWriteModel {
func (wm *IAMIDPConfigWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.IDPConfigAddedEventType,
iam.IDPConfigChangedEventType,
iam.IDPConfigDeactivatedEventType,
iam.IDPConfigReactivatedEventType,
iam.IDPConfigRemovedEventType,
iam.IDPOIDCConfigAddedEventType,
iam.IDPOIDCConfigChangedEventType,
)
}
func (wm *IAMIDPConfigWriteModel) AppendEvents(events ...eventstore.EventReader) {
@ -84,7 +93,7 @@ func (wm *IAMIDPConfigWriteModel) AppendAndReduce(events ...eventstore.EventRead
func (wm *IAMIDPConfigWriteModel) NewChangedEvent(
ctx context.Context,
resourceOwner,
aggregate *eventstore.Aggregate,
configID,
name string,
stylingType domain.IDPConfigStylingType,
@ -102,7 +111,7 @@ func (wm *IAMIDPConfigWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changeEvent, err := iam.NewIDPConfigChangedEvent(ctx, resourceOwner, configID, oldName, changes)
changeEvent, err := iam.NewIDPConfigChangedEvent(ctx, aggregate, configID, oldName, changes)
if err != nil {
return nil, false
}

@ -17,8 +17,10 @@ func (r *CommandSide) ChangeDefaultIDPOIDCConfig(ctx context.Context, config *do
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-67J9d", "Errors.IAM.IDPConfig.AlreadyExists")
}
iamAgg := IAMAggregateFromWriteModel(&existingConfig.WriteModel)
changedEvent, hasChanged, err := existingConfig.NewChangedEvent(
ctx,
iamAgg,
config.IDPConfigID,
config.ClientID,
config.Issuer,
@ -34,13 +36,13 @@ func (r *CommandSide) ChangeDefaultIDPOIDCConfig(ctx context.Context, config *do
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingConfig.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingConfig, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingConfig, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToIDPOIDCConfig(&existingConfig.OIDCConfigWriteModel), nil
}

@ -71,11 +71,18 @@ func (wm *IAMIDPOIDCConfigWriteModel) Reduce() error {
func (wm *IAMIDPOIDCConfigWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.IDPOIDCConfigAddedEventType,
iam.IDPOIDCConfigChangedEventType,
iam.IDPConfigReactivatedEventType,
iam.IDPConfigDeactivatedEventType,
iam.IDPConfigRemovedEventType)
}
func (wm *IAMIDPOIDCConfigWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
idpConfigID,
clientID,
issuer,
@ -114,7 +121,7 @@ func (wm *IAMIDPOIDCConfigWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false, nil
}
changeEvent, err := iam.NewIDPOIDCConfigChangedEvent(ctx, idpConfigID, changes)
changeEvent, err := iam.NewIDPOIDCConfigChangedEvent(ctx, aggregate, idpConfigID, changes)
if err != nil {
return nil, false, err
}

@ -2,6 +2,7 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"reflect"
"github.com/caos/zitadel/internal/errors"
@ -14,37 +15,38 @@ import (
func (r *CommandSide) AddIAMMember(ctx context.Context, member *domain.Member) (*domain.Member, error) {
addedMember := NewIAMMemberWriteModel(member.UserID)
iamAgg := IAMAggregateFromWriteModel(&addedMember.MemberWriteModel.WriteModel)
err := r.addIAMMember(ctx, iamAgg, addedMember, member)
event, err := r.addIAMMember(ctx, iamAgg, addedMember, member)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedMember, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedMember, pushedEvents...)
if err != nil {
return nil, err
}
return memberWriteModelToMember(&addedMember.MemberWriteModel), nil
}
func (r *CommandSide) addIAMMember(ctx context.Context, iamAgg *iam_repo.Aggregate, addedMember *IAMMemberWriteModel, member *domain.Member) error {
func (r *CommandSide) addIAMMember(ctx context.Context, iamAgg *eventstore.Aggregate, addedMember *IAMMemberWriteModel, member *domain.Member) (eventstore.EventPusher, error) {
//TODO: check if roles valid
if !member.IsValid() {
return caos_errs.ThrowPreconditionFailed(nil, "IAM-GR34U", "Errors.IAM.MemberInvalid")
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-GR34U", "Errors.IAM.MemberInvalid")
}
err := r.eventstore.FilterToQueryReducer(ctx, addedMember)
if err != nil {
return err
return nil, err
}
if addedMember.State == domain.MemberStateActive {
return errors.ThrowAlreadyExists(nil, "IAM-sdgQ4", "Errors.IAM.Member.AlreadyExists")
return nil, errors.ThrowAlreadyExists(nil, "IAM-sdgQ4", "Errors.IAM.Member.AlreadyExists")
}
iamAgg.PushEvents(iam_repo.NewMemberAddedEvent(ctx, iamAgg.ID(), member.UserID, member.Roles...))
return nil
return iam_repo.NewMemberAddedEvent(ctx, iamAgg, member.UserID, member.Roles...), nil
}
//ChangeIAMMember updates an existing member
@ -64,15 +66,12 @@ func (r *CommandSide) ChangeIAMMember(ctx context.Context, member *domain.Member
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-LiaZi", "Errors.IAM.Member.RolesNotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingMember.MemberWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewMemberChangedEvent(ctx, member.UserID, member.Roles...))
events, err := r.eventstore.PushAggregates(ctx, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, iam_repo.NewMemberChangedEvent(ctx, iamAgg, member.UserID, member.Roles...))
if err != nil {
return nil, err
}
existingMember.AppendEvents(events...)
if err = existingMember.Reduce(); err != nil {
err = AppendAndReduce(existingMember, pushedEvents...)
if err != nil {
return nil, err
}
@ -89,9 +88,8 @@ func (r *CommandSide) RemoveIAMMember(ctx context.Context, userID string) error
}
iamAgg := IAMAggregateFromWriteModel(&m.MemberWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewMemberRemovedEvent(ctx, iamAgg.ID(), userID))
return r.eventstore.PushAggregate(ctx, m, iamAgg)
_, err = r.eventstore.PushEvents(ctx, iam_repo.NewMemberRemovedEvent(ctx, iamAgg, userID))
return err
}
func (r *CommandSide) iamMemberWriteModelByID(ctx context.Context, userID string) (member *IAMMemberWriteModel, err error) {

@ -50,5 +50,10 @@ func (wm *IAMMemberWriteModel) Reduce() error {
func (wm *IAMMemberWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.MemberWriteModel.AggregateID).ResourceOwner(wm.ResourceOwner)
AggregateIDs(wm.MemberWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.MemberAddedEventType,
iam.MemberChangedEventType,
iam.MemberRemovedEventType)
}

@ -25,10 +25,6 @@ func NewIAMWriteModel() *IAMWriteModel {
}
}
func (wm *IAMWriteModel) AppendEvents(events ...eventstore.EventReader) {
wm.WriteModel.AppendEvents(events...)
}
func (wm *IAMWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
@ -50,11 +46,14 @@ func (wm *IAMWriteModel) Reduce() error {
func (wm *IAMWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.ProjectSetEventType,
iam.GlobalOrgSetEventType,
iam.SetupStartedEventType,
iam.SetupDoneEventType)
}
func IAMAggregateFromWriteModel(wm *eventstore.WriteModel) *iam.Aggregate {
return &iam.Aggregate{
Aggregate: *eventstore.AggregateFromWriteModel(wm, iam.AggregateType, iam.AggregateVersion),
}
func IAMAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate {
return eventstore.AggregateFromWriteModel(wm, iam.AggregateType, iam.AggregateVersion)
}

@ -3,6 +3,7 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
@ -11,31 +12,33 @@ import (
func (r *CommandSide) AddDefaultLabelPolicy(ctx context.Context, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) {
addedPolicy := NewIAMLabelPolicyWriteModel()
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.LabelPolicyWriteModel.WriteModel)
err := r.addDefaultLabelPolicy(ctx, nil, addedPolicy, policy)
event, err := r.addDefaultLabelPolicy(ctx, iamAgg, addedPolicy, policy)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToLabelPolicy(&addedPolicy.LabelPolicyWriteModel), nil
}
func (r *CommandSide) addDefaultLabelPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMLabelPolicyWriteModel, policy *domain.LabelPolicy) error {
func (r *CommandSide) addDefaultLabelPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, addedPolicy *IAMLabelPolicyWriteModel, policy *domain.LabelPolicy) (eventstore.EventPusher, error) {
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return err
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LabelPolicy.AlreadyExists")
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LabelPolicy.AlreadyExists")
}
iamAgg.PushEvents(iam_repo.NewLabelPolicyAddedEvent(ctx, policy.PrimaryColor, policy.SecondaryColor))
return iam_repo.NewLabelPolicyAddedEvent(ctx, iamAgg, policy.PrimaryColor, policy.SecondaryColor), nil
return nil
}
func (r *CommandSide) ChangeDefaultLabelPolicy(ctx context.Context, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) {
@ -47,20 +50,20 @@ func (r *CommandSide) ChangeDefaultLabelPolicy(ctx context.Context, policy *doma
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "IAM-0K9dq", "Errors.IAM.LabelPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.PrimaryColor, policy.SecondaryColor)
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.PrimaryColor, policy.SecondaryColor)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToLabelPolicy(&existingPolicy.LabelPolicyWriteModel), nil
}

@ -42,11 +42,15 @@ func (wm *IAMLabelPolicyWriteModel) Reduce() error {
func (wm *IAMLabelPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.LabelPolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.LabelPolicyAddedEventType,
iam.LabelPolicyChangedEventType)
}
func (wm *IAMLabelPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
primaryColor,
secondaryColor string,
) (*iam.LabelPolicyChangedEvent, bool) {
@ -60,7 +64,7 @@ func (wm *IAMLabelPolicyWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewLabelPolicyChangedEvent(ctx, changes)
changedEvent, err := iam.NewLabelPolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -25,11 +25,11 @@ func (r *CommandSide) getDefaultLoginPolicy(ctx context.Context) (*domain.LoginP
func (r *CommandSide) AddDefaultLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
addedPolicy := NewIAMLoginPolicyWriteModel()
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.WriteModel)
err := r.addDefaultLoginPolicy(ctx, nil, addedPolicy, policy)
event, err := r.addDefaultLoginPolicy(ctx, iamAgg, addedPolicy, policy)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
_, err = r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
@ -37,50 +37,49 @@ func (r *CommandSide) AddDefaultLoginPolicy(ctx context.Context, policy *domain.
return writeModelToLoginPolicy(&addedPolicy.LoginPolicyWriteModel), nil
}
func (r *CommandSide) addDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMLoginPolicyWriteModel, policy *domain.LoginPolicy) error {
func (r *CommandSide) addDefaultLoginPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, addedPolicy *IAMLoginPolicyWriteModel, policy *domain.LoginPolicy) (eventstore.EventPusher, error) {
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return err
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LoginPolicy.AlreadyExists")
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LoginPolicy.AlreadyExists")
}
iamAgg.PushEvents(iam_repo.NewLoginPolicyAddedEvent(ctx, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType))
return nil
return iam_repo.NewLoginPolicyAddedEvent(ctx, iamAgg, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType), nil
}
func (r *CommandSide) ChangeDefaultLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
existingPolicy := NewIAMLoginPolicyWriteModel()
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel)
err := r.changeDefaultLoginPolicy(ctx, iamAgg, existingPolicy, policy)
event, err := r.changeDefaultLoginPolicy(ctx, iamAgg, existingPolicy, policy)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToLoginPolicy(&existingPolicy.LoginPolicyWriteModel), nil
}
func (r *CommandSide) changeDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, existingPolicy *IAMLoginPolicyWriteModel, policy *domain.LoginPolicy) error {
func (r *CommandSide) changeDefaultLoginPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, existingPolicy *IAMLoginPolicyWriteModel, policy *domain.LoginPolicy) (eventstore.EventPusher, error) {
err := r.defaultLoginPolicyWriteModelByID(ctx, existingPolicy)
if err != nil {
return err
return nil, err
}
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return caos_errs.ThrowNotFound(nil, "IAM-M0sif", "Errors.IAM.LoginPolicy.NotFound")
return nil, caos_errs.ThrowNotFound(nil, "IAM-M0sif", "Errors.IAM.LoginPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType)
if !hasChanged {
return caos_errs.ThrowPreconditionFailed(nil, "IAM-5M9vdd", "Errors.IAM.LoginPolicy.NotChanged")
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-5M9vdd", "Errors.IAM.LoginPolicy.NotChanged")
}
iamAgg.PushEvents(changedEvent)
return nil
return changedEvent, nil
}
func (r *CommandSide) AddIDPProviderToDefaultLoginPolicy(ctx context.Context, idpProvider *domain.IDPProvider) (*domain.IDPProvider, error) {
@ -94,12 +93,14 @@ func (r *CommandSide) AddIDPProviderToDefaultLoginPolicy(ctx context.Context, id
}
iamAgg := IAMAggregateFromWriteModel(&idpModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewIdentityProviderAddedEvent(ctx, idpProvider.IDPConfigID, domain.IdentityProviderType(idpProvider.Type)))
if err = r.eventstore.PushAggregate(ctx, idpModel, iamAgg); err != nil {
pushedEvents, err := r.eventstore.PushEvents(ctx, iam_repo.NewIdentityProviderAddedEvent(ctx, iamAgg, idpProvider.IDPConfigID, idpProvider.Type))
if err != nil {
return nil, err
}
err = AppendAndReduce(idpModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToIDPProvider(&idpModel.IdentityProviderWriteModel), nil
}
@ -113,64 +114,61 @@ func (r *CommandSide) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Contex
return caos_errs.ThrowNotFound(nil, "IAM-39fjs", "Errors.IAM.LoginPolicy.IDP.NotExisting")
}
aggregates := make([]eventstore.Aggregater, 0)
iamAgg := IAMAggregateFromWriteModel(&idpModel.IdentityProviderWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewIdentityProviderRemovedEvent(ctx, idpProvider.IDPConfigID))
events := []eventstore.EventPusher{
iam_repo.NewIdentityProviderRemovedEvent(ctx, iamAgg, idpProvider.IDPConfigID),
}
userAggregates := r.removeIDPProviderFromDefaultLoginPolicy(ctx, iamAgg, idpProvider, false, cascadeExternalIDPs...)
aggregates = append(aggregates, iamAgg)
aggregates = append(aggregates, userAggregates...)
_, err = r.eventstore.PushAggregates(ctx, aggregates...)
userEvents := r.removeIDPProviderFromDefaultLoginPolicy(ctx, iamAgg, idpProvider, false, cascadeExternalIDPs...)
events = append(events, userEvents...)
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}
func (r *CommandSide) removeIDPProviderFromDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, idpProvider *domain.IDPProvider, cascade bool, cascadeExternalIDPs ...*domain.ExternalIDP) []eventstore.Aggregater {
func (r *CommandSide) removeIDPProviderFromDefaultLoginPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, idpProvider *domain.IDPProvider, cascade bool, cascadeExternalIDPs ...*domain.ExternalIDP) []eventstore.EventPusher {
var events []eventstore.EventPusher
if cascade {
iamAgg.PushEvents(iam_repo.NewIdentityProviderCascadeRemovedEvent(ctx, idpProvider.IDPConfigID))
return nil
events = append(events, iam_repo.NewIdentityProviderCascadeRemovedEvent(ctx, iamAgg, idpProvider.IDPConfigID))
} else {
events = append(events, iam_repo.NewIdentityProviderRemovedEvent(ctx, iamAgg, idpProvider.IDPConfigID))
}
iamAgg.PushEvents(iam_repo.NewIdentityProviderRemovedEvent(ctx, idpProvider.IDPConfigID))
userAggregates := make([]eventstore.Aggregater, 0)
for _, idp := range cascadeExternalIDPs {
userAgg, _, err := r.removeHumanExternalIDP(ctx, idp, true)
userEvent, err := r.removeHumanExternalIDP(ctx, idp, true)
if err != nil {
logging.LogWithFields("COMMAND-4nfsf", "userid", idp.AggregateID, "idp-id", idp.IDPConfigID).WithError(err).Warn("could not cascade remove externalidp in remove provider from policy")
continue
}
userAggregates = append(userAggregates, userAgg)
events = append(events, userEvent)
}
return userAggregates
return events
}
func (r *CommandSide) AddSecondFactorToDefaultLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType) (domain.SecondFactorType, error) {
secondFactorModel := NewIAMSecondFactorWriteModel()
iamAgg := IAMAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
err := r.addSecondFactorToDefaultLoginPolicy(ctx, nil, secondFactorModel, secondFactor)
event, err := r.addSecondFactorToDefaultLoginPolicy(ctx, iamAgg, secondFactorModel, secondFactor)
if err != nil {
return domain.SecondFactorTypeUnspecified, err
}
if err = r.eventstore.PushAggregate(ctx, secondFactorModel, iamAgg); err != nil {
if _, err = r.eventstore.PushEvents(ctx, event); err != nil {
return domain.SecondFactorTypeUnspecified, err
}
return secondFactorModel.MFAType, nil
}
func (r *CommandSide) addSecondFactorToDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, secondFactorModel *IAMSecondFactorWriteModel, secondFactor domain.SecondFactorType) error {
func (r *CommandSide) addSecondFactorToDefaultLoginPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, secondFactorModel *IAMSecondFactorWriteModel, secondFactor domain.SecondFactorType) (eventstore.EventPusher, error) {
err := r.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
if err != nil {
return err
return nil, err
}
if secondFactorModel.State == domain.FactorStateActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LoginPolicy.MFA.AlreadyExists")
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LoginPolicy.MFA.AlreadyExists")
}
iamAgg.PushEvents(iam_repo.NewLoginPolicySecondFactorAddedEvent(ctx, domain.SecondFactorType(secondFactor)))
return nil
return iam_repo.NewLoginPolicySecondFactorAddedEvent(ctx, iamAgg, secondFactor), nil
}
func (r *CommandSide) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType) error {
@ -183,38 +181,35 @@ func (r *CommandSide) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Conte
return caos_errs.ThrowNotFound(nil, "IAM-3M9od", "Errors.IAM.LoginPolicy.MFA.NotExisting")
}
iamAgg := IAMAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewLoginPolicySecondFactorRemovedEvent(ctx, domain.SecondFactorType(secondFactor)))
return r.eventstore.PushAggregate(ctx, secondFactorModel, iamAgg)
_, err = r.eventstore.PushEvents(ctx, iam_repo.NewLoginPolicySecondFactorRemovedEvent(ctx, iamAgg, secondFactor))
return err
}
func (r *CommandSide) AddMultiFactorToDefaultLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType) (domain.MultiFactorType, error) {
multiFactorModel := NewIAMMultiFactorWriteModel()
iamAgg := IAMAggregateFromWriteModel(&multiFactorModel.MultiFactoryWriteModel.WriteModel)
err := r.addMultiFactorToDefaultLoginPolicy(ctx, iamAgg, multiFactorModel, multiFactor)
event, err := r.addMultiFactorToDefaultLoginPolicy(ctx, iamAgg, multiFactorModel, multiFactor)
if err != nil {
return domain.MultiFactorTypeUnspecified, err
}
if err = r.eventstore.PushAggregate(ctx, multiFactorModel, iamAgg); err != nil {
if _, err = r.eventstore.PushEvents(ctx, event); err != nil {
return domain.MultiFactorTypeUnspecified, err
}
return domain.MultiFactorType(multiFactorModel.MultiFactoryWriteModel.MFAType), nil
return multiFactorModel.MultiFactoryWriteModel.MFAType, nil
}
func (r *CommandSide) addMultiFactorToDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, multiFactorModel *IAMMultiFactorWriteModel, multiFactor domain.MultiFactorType) error {
func (r *CommandSide) addMultiFactorToDefaultLoginPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, multiFactorModel *IAMMultiFactorWriteModel, multiFactor domain.MultiFactorType) (eventstore.EventPusher, error) {
err := r.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
if err != nil {
return err
return nil, err
}
if multiFactorModel.State == domain.FactorStateActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-3M9od", "Errors.IAM.LoginPolicy.MFA.AlreadyExists")
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-3M9od", "Errors.IAM.LoginPolicy.MFA.AlreadyExists")
}
iamAgg.PushEvents(iam_repo.NewLoginPolicyMultiFactorAddedEvent(ctx, domain.MultiFactorType(multiFactor)))
return nil
return iam_repo.NewLoginPolicyMultiFactorAddedEvent(ctx, iamAgg, multiFactor), nil
}
func (r *CommandSide) RemoveMultiFactorFromDefaultLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType) error {
@ -227,9 +222,8 @@ func (r *CommandSide) RemoveMultiFactorFromDefaultLoginPolicy(ctx context.Contex
return caos_errs.ThrowNotFound(nil, "IAM-3M9df", "Errors.IAM.LoginPolicy.MFA.NotExisting")
}
iamAgg := IAMAggregateFromWriteModel(&multiFactorModel.MultiFactoryWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewLoginPolicyMultiFactorRemovedEvent(ctx, domain.MultiFactorType(multiFactor)))
return r.eventstore.PushAggregate(ctx, multiFactorModel, iamAgg)
_, err = r.eventstore.PushEvents(ctx, iam_repo.NewLoginPolicyMultiFactorRemovedEvent(ctx, iamAgg, multiFactor))
return err
}
func (r *CommandSide) defaultLoginPolicyWriteModelByID(ctx context.Context, writeModel *IAMLoginPolicyWriteModel) (err error) {

@ -39,7 +39,10 @@ func (wm *IAMSecondFactorWriteModel) Reduce() error {
func (wm *IAMSecondFactorWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.WriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.LoginPolicySecondFactorAddedEventType,
iam.LoginPolicySecondFactorRemovedEventType)
}
type IAMMultiFactorWriteModel struct {
@ -75,5 +78,8 @@ func (wm *IAMMultiFactorWriteModel) Reduce() error {
func (wm *IAMMultiFactorWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.WriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.LoginPolicyMultiFactorAddedEventType,
iam.LoginPolicyMultiFactorRemovedEventType)
}

@ -46,11 +46,15 @@ func (wm *IAMLoginPolicyWriteModel) Reduce() error {
func (wm *IAMLoginPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.LoginPolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.LoginPolicyAddedEventType,
iam.LoginPolicyChangedEventType)
}
func (wm *IAMLoginPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
allowUsernamePassword,
allowRegister,
allowExternalIDP,
@ -77,7 +81,7 @@ func (wm *IAMLoginPolicyWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewLoginPolicyChangedEvent(ctx, changes)
changedEvent, err := iam.NewLoginPolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -3,6 +3,7 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
@ -11,34 +12,35 @@ import (
func (r *CommandSide) AddDefaultMailTemplate(ctx context.Context, policy *domain.MailTemplate) (*domain.MailTemplate, error) {
addedPolicy := NewIAMMailTemplateWriteModel()
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.MailTemplateWriteModel.WriteModel)
err := r.addDefaultMailTemplate(ctx, nil, addedPolicy, policy)
event, err := r.addDefaultMailTemplate(ctx, iamAgg, addedPolicy, policy)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToMailTemplatePolicy(&addedPolicy.MailTemplateWriteModel), nil
}
func (r *CommandSide) addDefaultMailTemplate(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMMailTemplateWriteModel, policy *domain.MailTemplate) error {
func (r *CommandSide) addDefaultMailTemplate(ctx context.Context, iamAgg *eventstore.Aggregate, addedPolicy *IAMMailTemplateWriteModel, policy *domain.MailTemplate) (eventstore.EventPusher, error) {
if !policy.IsValid() {
return caos_errs.ThrowPreconditionFailed(nil, "IAM-fm9sd", "Errors.IAM.MailTemplate.Invalid")
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-fm9sd", "Errors.IAM.MailTemplate.Invalid")
}
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return err
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-5n8fs", "Errors.IAM.MailTemplate.AlreadyExists")
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-5n8fs", "Errors.IAM.MailTemplate.AlreadyExists")
}
iamAgg.PushEvents(iam_repo.NewMailTemplateAddedEvent(ctx, policy.Template))
return nil
return iam_repo.NewMailTemplateAddedEvent(ctx, iamAgg, policy.Template), nil
}
func (r *CommandSide) ChangeDefaultMailTemplate(ctx context.Context, policy *domain.MailTemplate) (*domain.MailTemplate, error) {
@ -54,19 +56,20 @@ func (r *CommandSide) ChangeDefaultMailTemplate(ctx context.Context, policy *dom
return nil, caos_errs.ThrowNotFound(nil, "IAM-2N8fs", "Errors.IAM.MailTemplate.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.Template)
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.MailTemplateWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.Template)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-3nfsG", "Errors.IAM.MailTemplate.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.MailTemplateWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToMailTemplatePolicy(&existingPolicy.MailTemplateWriteModel), nil
}

@ -43,11 +43,15 @@ func (wm *IAMMailTemplateWriteModel) Reduce() error {
func (wm *IAMMailTemplateWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.MailTemplateWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.MailTemplateAddedEventType,
iam.MailTemplateChangedEventType)
}
func (wm *IAMMailTemplateWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
template []byte,
) (*iam.MailTemplateChangedEvent, bool) {
changes := make([]policy.MailTemplateChanges, 0)
@ -57,7 +61,7 @@ func (wm *IAMMailTemplateWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewMailTemplateChangedEvent(ctx, changes)
changedEvent, err := iam.NewMailTemplateChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -3,6 +3,7 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
@ -11,45 +12,45 @@ import (
func (r *CommandSide) AddDefaultMailText(ctx context.Context, policy *domain.MailText) (*domain.MailText, error) {
addedPolicy := NewIAMMailTextWriteModel(policy.MailTextType, policy.Language)
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.MailTextWriteModel.WriteModel)
err := r.addDefaultMailText(ctx, nil, addedPolicy, policy)
event, err := r.addDefaultMailText(ctx, iamAgg, addedPolicy, policy)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToMailTextPolicy(&addedPolicy.MailTextWriteModel), nil
}
func (r *CommandSide) addDefaultMailText(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMMailTextWriteModel, mailText *domain.MailText) error {
func (r *CommandSide) addDefaultMailText(ctx context.Context, iamAgg *eventstore.Aggregate, addedPolicy *IAMMailTextWriteModel, mailText *domain.MailText) (eventstore.EventPusher, error) {
if !mailText.IsValid() {
return caos_errs.ThrowPreconditionFailed(nil, "IAM-3n8fs", "Errors.IAM.MailText.Invalid")
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-3n8fs", "Errors.IAM.MailText.Invalid")
}
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return err
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-9o0pM", "Errors.IAM.MailText.AlreadyExists")
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-9o0pM", "Errors.IAM.MailText.AlreadyExists")
}
iamAgg.PushEvents(
iam_repo.NewMailTextAddedEvent(
ctx,
mailText.MailTextType,
mailText.Language,
mailText.Title,
mailText.PreHeader,
mailText.Subject,
mailText.Greeting,
mailText.Text,
mailText.ButtonText),
)
return nil
return iam_repo.NewMailTextAddedEvent(
ctx,
iamAgg,
mailText.MailTextType,
mailText.Language,
mailText.Title,
mailText.PreHeader,
mailText.Subject,
mailText.Greeting,
mailText.Text,
mailText.ButtonText), nil
}
func (r *CommandSide) ChangeDefaultMailText(ctx context.Context, mailText *domain.MailText) (*domain.MailText, error) {
@ -65,8 +66,10 @@ func (r *CommandSide) ChangeDefaultMailText(ctx context.Context, mailText *domai
return nil, caos_errs.ThrowNotFound(nil, "IAM-2N8fs", "Errors.IAM.MailText.NotFound")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.MailTextWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(
ctx,
iamAgg,
mailText.MailTextType,
mailText.Language,
mailText.Title,
@ -79,14 +82,14 @@ func (r *CommandSide) ChangeDefaultMailText(ctx context.Context, mailText *domai
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-m9L0s", "Errors.IAM.MailText.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.MailTextWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToMailTextPolicy(&existingPolicy.MailTextWriteModel), nil
}

@ -43,11 +43,15 @@ func (wm *IAMMailTextWriteModel) Reduce() error {
func (wm *IAMMailTextWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.MailTextWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.MailTextAddedEventType,
iam.MailTextChangedEventType)
}
func (wm *IAMMailTextWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
mailTextType,
language,
title,
@ -79,7 +83,7 @@ func (wm *IAMMailTextWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewMailTextChangedEvent(ctx, mailTextType, language, changes)
changedEvent, err := iam.NewMailTextChangedEvent(ctx, aggregate, mailTextType, language, changes)
if err != nil {
return nil, false
}

@ -3,6 +3,7 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
@ -11,30 +12,31 @@ import (
func (r *CommandSide) AddDefaultOrgIAMPolicy(ctx context.Context, policy *domain.OrgIAMPolicy) (*domain.OrgIAMPolicy, error) {
addedPolicy := NewIAMOrgIAMPolicyWriteModel()
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.WriteModel)
err := r.addDefaultOrgIAMPolicy(ctx, nil, addedPolicy, policy)
event, err := r.addDefaultOrgIAMPolicy(ctx, iamAgg, addedPolicy, policy)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToOrgIAMPolicy(addedPolicy), nil
}
func (r *CommandSide) addDefaultOrgIAMPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMOrgIAMPolicyWriteModel, policy *domain.OrgIAMPolicy) error {
func (r *CommandSide) addDefaultOrgIAMPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, addedPolicy *IAMOrgIAMPolicyWriteModel, policy *domain.OrgIAMPolicy) (eventstore.EventPusher, error) {
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return err
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-Lk0dS", "Errors.IAM.OrgIAMPolicy.AlreadyExists")
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-Lk0dS", "Errors.IAM.OrgIAMPolicy.AlreadyExists")
}
iamAgg.PushEvents(iam_repo.NewOrgIAMPolicyAddedEvent(ctx, policy.UserLoginMustBeDomain))
return nil
return iam_repo.NewOrgIAMPolicyAddedEvent(ctx, iamAgg, policy.UserLoginMustBeDomain), nil
}
func (r *CommandSide) ChangeDefaultOrgIAMPolicy(ctx context.Context, policy *domain.OrgIAMPolicy) (*domain.OrgIAMPolicy, error) {
@ -46,19 +48,20 @@ func (r *CommandSide) ChangeDefaultOrgIAMPolicy(ctx context.Context, policy *dom
return nil, caos_errs.ThrowNotFound(nil, "IAM-0Pl0d", "Errors.IAM.OrgIAMPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.UserLoginMustBeDomain)
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PolicyOrgIAMWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.UserLoginMustBeDomain)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PolicyOrgIAMWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToOrgIAMPolicy(existingPolicy), nil
}

@ -42,10 +42,16 @@ func (wm *IAMOrgIAMPolicyWriteModel) Reduce() error {
func (wm *IAMOrgIAMPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.PolicyOrgIAMWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.OrgIAMPolicyAddedEventType,
iam.OrgIAMPolicyChangedEventType)
}
func (wm *IAMOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLoginMustBeDomain bool) (*iam.OrgIAMPolicyChangedEvent, bool) {
func (wm *IAMOrgIAMPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
userLoginMustBeDomain bool) (*iam.OrgIAMPolicyChangedEvent, bool) {
changes := make([]policy.OrgIAMPolicyChanges, 0)
if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
changes = append(changes, policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain))
@ -53,7 +59,7 @@ func (wm *IAMOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLo
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewOrgIAMPolicyChangedEvent(ctx, changes)
changedEvent, err := iam.NewOrgIAMPolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -3,6 +3,7 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
@ -11,31 +12,33 @@ import (
func (r *CommandSide) AddDefaultPasswordAgePolicy(ctx context.Context, policy *domain.PasswordAgePolicy) (*domain.PasswordAgePolicy, error) {
addedPolicy := NewIAMPasswordAgePolicyWriteModel()
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.WriteModel)
err := r.addDefaultPasswordAgePolicy(ctx, nil, addedPolicy, policy)
event, err := r.addDefaultPasswordAgePolicy(ctx, iamAgg, addedPolicy, policy)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPasswordAgePolicy(&addedPolicy.PasswordAgePolicyWriteModel), nil
}
func (r *CommandSide) addDefaultPasswordAgePolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMPasswordAgePolicyWriteModel, policy *domain.PasswordAgePolicy) error {
func (r *CommandSide) addDefaultPasswordAgePolicy(ctx context.Context, iamAgg *eventstore.Aggregate, addedPolicy *IAMPasswordAgePolicyWriteModel, policy *domain.PasswordAgePolicy) (eventstore.EventPusher, error) {
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return err
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-Lk0dS", "Errors.IAM.PasswordAgePolicy.AlreadyExists")
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-Lk0dS", "Errors.IAM.PasswordAgePolicy.AlreadyExists")
}
iamAgg.PushEvents(iam_repo.NewPasswordAgePolicyAddedEvent(ctx, policy.ExpireWarnDays, policy.MaxAgeDays))
return iam_repo.NewPasswordAgePolicyAddedEvent(ctx, iamAgg, policy.ExpireWarnDays, policy.MaxAgeDays), nil
return nil
}
func (r *CommandSide) ChangeDefaultPasswordAgePolicy(ctx context.Context, policy *domain.PasswordAgePolicy) (*domain.PasswordAgePolicy, error) {
@ -47,15 +50,17 @@ func (r *CommandSide) ChangeDefaultPasswordAgePolicy(ctx context.Context, policy
return nil, caos_errs.ThrowNotFound(nil, "IAM-0oPew", "Errors.IAM.PasswordAgePolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.ExpireWarnDays, policy.MaxAgeDays)
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PasswordAgePolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.ExpireWarnDays, policy.MaxAgeDays)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PasswordAgePolicyWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}

@ -42,10 +42,17 @@ func (wm *IAMPasswordAgePolicyWriteModel) Reduce() error {
func (wm *IAMPasswordAgePolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.PasswordAgePolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.PasswordAgePolicyAddedEventType,
iam.PasswordAgePolicyChangedEventType)
}
func (wm *IAMPasswordAgePolicyWriteModel) NewChangedEvent(ctx context.Context, expireWarnDays, maxAgeDays uint64) (*iam.PasswordAgePolicyChangedEvent, bool) {
func (wm *IAMPasswordAgePolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
expireWarnDays,
maxAgeDays uint64) (*iam.PasswordAgePolicyChangedEvent, bool) {
changes := make([]policy.PasswordAgePolicyChanges, 0)
if wm.ExpireWarnDays != expireWarnDays {
changes = append(changes, policy.ChangeExpireWarnDays(expireWarnDays))
@ -56,7 +63,7 @@ func (wm *IAMPasswordAgePolicyWriteModel) NewChangedEvent(ctx context.Context, e
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewPasswordAgePolicyChangedEvent(ctx, changes)
changedEvent, err := iam.NewPasswordAgePolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -3,6 +3,7 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
@ -22,35 +23,36 @@ func (r *CommandSide) getDefaultPasswordComplexityPolicy(ctx context.Context) (*
func (r *CommandSide) AddDefaultPasswordComplexityPolicy(ctx context.Context, policy *domain.PasswordComplexityPolicy) (*domain.PasswordComplexityPolicy, error) {
addedPolicy := NewIAMPasswordComplexityPolicyWriteModel()
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.WriteModel)
err := r.addDefaultPasswordComplexityPolicy(ctx, iamAgg, addedPolicy, policy)
events, err := r.addDefaultPasswordComplexityPolicy(ctx, iamAgg, addedPolicy, policy)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, events)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPasswordComplexityPolicy(&addedPolicy.PasswordComplexityPolicyWriteModel), nil
}
func (r *CommandSide) addDefaultPasswordComplexityPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMPasswordComplexityPolicyWriteModel, policy *domain.PasswordComplexityPolicy) error {
func (r *CommandSide) addDefaultPasswordComplexityPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, addedPolicy *IAMPasswordComplexityPolicyWriteModel, policy *domain.PasswordComplexityPolicy) (eventstore.EventPusher, error) {
if err := policy.IsValid(); err != nil {
return err
return nil, err
}
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return err
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-Lk0dS", "Errors.IAM.PasswordComplexityPolicy.AlreadyExists")
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-Lk0dS", "Errors.IAM.PasswordComplexityPolicy.AlreadyExists")
}
iamAgg.PushEvents(iam_repo.NewPasswordComplexityPolicyAddedEvent(ctx, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol))
return nil
return iam_repo.NewPasswordComplexityPolicyAddedEvent(ctx, iamAgg, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol), nil
}
func (r *CommandSide) ChangeDefaultPasswordComplexityPolicy(ctx context.Context, policy *domain.PasswordComplexityPolicy) (*domain.PasswordComplexityPolicy, error) {
@ -66,18 +68,19 @@ func (r *CommandSide) ChangeDefaultPasswordComplexityPolicy(ctx context.Context,
return nil, caos_errs.ThrowNotFound(nil, "IAM-0oPew", "Errors.IAM.PasswordAgePolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol)
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PasswordComplexityPolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PasswordComplexityPolicyWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPasswordComplexityPolicy(&existingPolicy.PasswordComplexityPolicyWriteModel), nil
}

@ -42,11 +42,15 @@ func (wm *IAMPasswordComplexityPolicyWriteModel) Reduce() error {
func (wm *IAMPasswordComplexityPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.PasswordComplexityPolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.PasswordComplexityPolicyAddedEventType,
iam.PasswordComplexityPolicyChangedEventType)
}
func (wm *IAMPasswordComplexityPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
minLength uint64,
hasLowercase,
hasUppercase,
@ -73,7 +77,7 @@ func (wm *IAMPasswordComplexityPolicyWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewPasswordComplexityPolicyChangedEvent(ctx, changes)
changedEvent, err := iam.NewPasswordComplexityPolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -3,6 +3,7 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
@ -11,12 +12,15 @@ import (
func (r *CommandSide) AddDefaultPasswordLockoutPolicy(ctx context.Context, policy *domain.PasswordLockoutPolicy) (*domain.PasswordLockoutPolicy, error) {
addedPolicy := NewIAMPasswordLockoutPolicyWriteModel()
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.WriteModel)
err := r.addDefaultPasswordLockoutPolicy(ctx, nil, addedPolicy, policy)
event, err := r.addDefaultPasswordLockoutPolicy(ctx, iamAgg, addedPolicy, policy)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
@ -24,18 +28,16 @@ func (r *CommandSide) AddDefaultPasswordLockoutPolicy(ctx context.Context, polic
return writeModelToPasswordLockoutPolicy(&addedPolicy.PasswordLockoutPolicyWriteModel), nil
}
func (r *CommandSide) addDefaultPasswordLockoutPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMPasswordLockoutPolicyWriteModel, policy *domain.PasswordLockoutPolicy) error {
func (r *CommandSide) addDefaultPasswordLockoutPolicy(ctx context.Context, iamAgg *eventstore.Aggregate, addedPolicy *IAMPasswordLockoutPolicyWriteModel, policy *domain.PasswordLockoutPolicy) (eventstore.EventPusher, error) {
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return err
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-0olDf", "Errors.IAM.PasswordLockoutPolicy.AlreadyExists")
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-0olDf", "Errors.IAM.PasswordLockoutPolicy.AlreadyExists")
}
iamAgg.PushEvents(iam_repo.NewPasswordLockoutPolicyAddedEvent(ctx, policy.MaxAttempts, policy.ShowLockOutFailures))
return nil
return iam_repo.NewPasswordLockoutPolicyAddedEvent(ctx, iamAgg, policy.MaxAttempts, policy.ShowLockOutFailures), nil
}
func (r *CommandSide) ChangeDefaultPasswordLockoutPolicy(ctx context.Context, policy *domain.PasswordLockoutPolicy) (*domain.PasswordLockoutPolicy, error) {
@ -47,19 +49,20 @@ func (r *CommandSide) ChangeDefaultPasswordLockoutPolicy(ctx context.Context, po
return nil, caos_errs.ThrowNotFound(nil, "IAM-0oPew", "Errors.IAM.PasswordLockoutPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.MaxAttempts, policy.ShowLockOutFailures)
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PasswordLockoutPolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.MaxAttempts, policy.ShowLockOutFailures)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.PasswordLockoutPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PasswordLockoutPolicyWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPasswordLockoutPolicy(&existingPolicy.PasswordLockoutPolicyWriteModel), nil
}

@ -42,10 +42,17 @@ func (wm *IAMPasswordLockoutPolicyWriteModel) Reduce() error {
func (wm *IAMPasswordLockoutPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.PasswordLockoutPolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.PasswordLockoutPolicyAddedEventType,
iam.PasswordLockoutPolicyChangedEventType)
}
func (wm *IAMPasswordLockoutPolicyWriteModel) NewChangedEvent(ctx context.Context, maxAttempts uint64, showLockoutFailure bool) (*iam.PasswordLockoutPolicyChangedEvent, bool) {
func (wm *IAMPasswordLockoutPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
maxAttempts uint64,
showLockoutFailure bool) (*iam.PasswordLockoutPolicyChangedEvent, bool) {
changes := make([]policy.PasswordLockoutPolicyChanges, 0)
if wm.MaxAttempts != maxAttempts {
changes = append(changes, policy.ChangeMaxAttempts(maxAttempts))
@ -56,7 +63,7 @@ func (wm *IAMPasswordLockoutPolicyWriteModel) NewChangedEvent(ctx context.Contex
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewPasswordLockoutPolicyChangedEvent(ctx, changes)
changedEvent, err := iam.NewPasswordLockoutPolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -15,6 +15,7 @@ type IDPConfigWriteModel struct {
Name string
StylingType domain.IDPConfigStylingType
//TODO: sub writemodels not used anymore?
OIDCConfig *OIDCConfigWriteModel
}

@ -29,15 +29,14 @@ func (r *CommandSide) GenerateSigningKeyPair(ctx context.Context, algorithm stri
keyPairWriteModel := NewKeyPairWriteModel(keyID, domain.IAMID)
keyAgg := KeyPairAggregateFromWriteModel(&keyPairWriteModel.WriteModel)
keyAgg.PushEvents(
keypair.NewAddedEvent(
ctx,
domain.KeyUsageSigning,
algorithm,
privateCrypto, publicCrypto,
privateKeyExp, publicKeyExp),
)
return r.eventstore.PushAggregate(ctx, keyPairWriteModel, keyAgg)
_, err = r.eventstore.PushEvents(ctx, keypair.NewAddedEvent(
ctx,
keyAgg,
domain.KeyUsageSigning,
algorithm,
privateCrypto, publicCrypto,
privateKeyExp, publicKeyExp))
return err
}
func setOIDCCtx(ctx context.Context) context.Context {

@ -51,11 +51,11 @@ func (wm *KeyPairWriteModel) Reduce() error {
func (wm *KeyPairWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(keypair.AddedEventType)
}
func KeyPairAggregateFromWriteModel(wm *eventstore.WriteModel) *keypair.Aggregate {
return &keypair.Aggregate{
Aggregate: *eventstore.AggregateFromWriteModel(wm, keypair.AggregateType, keypair.AggregateVersion),
}
func KeyPairAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate {
return eventstore.AggregateFromWriteModel(wm, keypair.AggregateType, keypair.AggregateVersion)
}

@ -7,7 +7,6 @@ import (
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
"github.com/caos/zitadel/internal/v2/repository/user"
)
func (r *CommandSide) getOrg(ctx context.Context, orgID string) (*domain.Org, error) {
@ -33,19 +32,16 @@ func (r *CommandSide) checkOrgExists(ctx context.Context, orgID string) error {
}
func (r *CommandSide) SetUpOrg(ctx context.Context, organisation *domain.Org, admin *domain.Human) error {
orgAgg, userAgg, orgMemberAgg, claimedUsers, err := r.setUpOrg(ctx, organisation, admin)
_, _, _, events, err := r.setUpOrg(ctx, organisation, admin)
if err != nil {
return err
}
aggregates := make([]eventstore.Aggregater, 0)
aggregates = append(aggregates, orgAgg, userAgg, orgMemberAgg)
aggregates = append(aggregates, claimedUsers...)
_, err = r.eventstore.PushAggregates(ctx, aggregates...)
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}
func (r *CommandSide) AddOrg(ctx context.Context, name, userID, resourceOwner string) (*domain.Org, error) {
orgAgg, addedOrg, claimedUsers, err := r.addOrg(ctx, &domain.Org{Name: name})
orgAgg, addedOrg, events, err := r.addOrg(ctx, &domain.Org{Name: name})
if err != nil {
return nil, err
}
@ -54,20 +50,17 @@ func (r *CommandSide) AddOrg(ctx context.Context, name, userID, resourceOwner st
if err != nil {
return nil, err
}
addedMember := NewOrgMemberWriteModel(orgAgg.ID(), userID)
err = r.addOrgMember(ctx, orgAgg, addedMember, domain.NewMember(orgAgg.ID(), userID, domain.RoleOrgOwner))
addedMember := NewOrgMemberWriteModel(addedOrg.AggregateID, userID)
orgMemberEvent, err := r.addOrgMember(ctx, orgAgg, addedMember, domain.NewMember(orgAgg.ID, userID, domain.RoleOrgOwner))
if err != nil {
return nil, err
}
aggregates := make([]eventstore.Aggregater, 0)
aggregates = append(aggregates, orgAgg)
aggregates = append(aggregates, claimedUsers...)
resEvents, err := r.eventstore.PushAggregates(ctx, aggregates...)
events = append(events, orgMemberEvent)
pushedEvents, err := r.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
addedOrg.AppendEvents(resEvents...)
err = addedOrg.Reduce()
err = AppendAndReduce(addedOrg, pushedEvents...)
if err != nil {
return nil, err
}
@ -86,9 +79,8 @@ func (r *CommandSide) DeactivateOrg(ctx context.Context, orgID string) error {
return caos_errs.ThrowInvalidArgument(nil, "EVENT-Dbs2g", "Errors.Org.AlreadyDeactivated")
}
orgAgg := OrgAggregateFromWriteModel(&orgWriteModel.WriteModel)
orgAgg.PushEvents(org.NewOrgDeactivatedEvent(ctx))
return r.eventstore.PushAggregate(ctx, orgWriteModel, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewOrgDeactivatedEvent(ctx, orgAgg))
return err
}
func (r *CommandSide) ReactivateOrg(ctx context.Context, orgID string) error {
@ -103,32 +95,33 @@ func (r *CommandSide) ReactivateOrg(ctx context.Context, orgID string) error {
return caos_errs.ThrowInvalidArgument(nil, "EVENT-bfnrh", "Errors.Org.AlreadyActive")
}
orgAgg := OrgAggregateFromWriteModel(&orgWriteModel.WriteModel)
orgAgg.PushEvents(org.NewOrgReactivatedEvent(ctx))
return r.eventstore.PushAggregate(ctx, orgWriteModel, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewOrgReactivatedEvent(ctx, orgAgg))
return err
}
func (r *CommandSide) setUpOrg(ctx context.Context, organisation *domain.Org, admin *domain.Human) (*org.Aggregate, *user.Aggregate, *org.Aggregate, []eventstore.Aggregater, error) {
orgAgg, _, claimedUserAggregates, err := r.addOrg(ctx, organisation)
func (r *CommandSide) setUpOrg(ctx context.Context, organisation *domain.Org, admin *domain.Human) (orgAgg *eventstore.Aggregate, human *HumanWriteModel, orgMember *OrgMemberWriteModel, events []eventstore.EventPusher, err error) {
orgAgg, _, addOrgEvents, err := r.addOrg(ctx, organisation)
if err != nil {
return nil, nil, nil, nil, err
}
userAgg, _, err := r.addHuman(ctx, orgAgg.ID(), admin)
userEvents, human, err := r.addHuman(ctx, orgAgg.ID, admin)
if err != nil {
return nil, nil, nil, nil, err
}
addOrgEvents = append(addOrgEvents, userEvents...)
addedMember := NewOrgMemberWriteModel(orgAgg.ID(), userAgg.ID())
addedMember := NewOrgMemberWriteModel(orgAgg.ID, human.AggregateID)
orgMemberAgg := OrgAggregateFromWriteModel(&addedMember.WriteModel)
err = r.addOrgMember(ctx, orgMemberAgg, addedMember, domain.NewMember(orgMemberAgg.ID(), userAgg.ID(), domain.RoleOrgOwner))
orgMemberEvent, err := r.addOrgMember(ctx, orgMemberAgg, addedMember, domain.NewMember(orgMemberAgg.ID, human.AggregateID, domain.RoleOrgOwner))
if err != nil {
return nil, nil, nil, nil, err
}
return orgAgg, userAgg, orgMemberAgg, claimedUserAggregates, nil
addOrgEvents = append(addOrgEvents, orgMemberEvent)
return orgAgg, human, addedMember, addOrgEvents, nil
}
func (r *CommandSide) addOrg(ctx context.Context, organisation *domain.Org, claimedUserIDs ...string) (_ *org.Aggregate, _ *OrgWriteModel, _ []eventstore.Aggregater, err error) {
func (r *CommandSide) addOrg(ctx context.Context, organisation *domain.Org, claimedUserIDs ...string) (_ *eventstore.Aggregate, _ *OrgWriteModel, _ []eventstore.EventPusher, err error) {
if organisation == nil || !organisation.IsValid() {
return nil, nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMM-deLSk", "Errors.Org.Invalid")
}
@ -141,17 +134,18 @@ func (r *CommandSide) addOrg(ctx context.Context, organisation *domain.Org, clai
addedOrg := NewOrgWriteModel(organisation.AggregateID)
orgAgg := OrgAggregateFromWriteModel(&addedOrg.WriteModel)
orgAgg.PushEvents(org.NewOrgAddedEvent(ctx, organisation.Name))
claimedUserAggregates := make([]eventstore.Aggregater, 0)
events := []eventstore.EventPusher{
org.NewOrgAddedEvent(ctx, orgAgg, organisation.Name),
}
for _, orgDomain := range organisation.Domains {
aggregates, err := r.addOrgDomain(ctx, orgAgg, NewOrgDomainWriteModel(orgAgg.ID(), orgDomain.Domain), orgDomain, claimedUserIDs...)
orgDomainEvents, err := r.addOrgDomain(ctx, orgAgg, NewOrgDomainWriteModel(orgAgg.ID, orgDomain.Domain), orgDomain, claimedUserIDs...)
if err != nil {
return nil, nil, nil, err
} else {
claimedUserAggregates = append(claimedUserAggregates, aggregates...)
events = append(events, orgDomainEvents...)
}
}
return orgAgg, addedOrg, claimedUserAggregates, nil
return orgAgg, addedOrg, events, nil
}
func (r *CommandSide) getOrgWriteModelByID(ctx context.Context, orgID string) (*OrgWriteModel, error) {

@ -16,27 +16,18 @@ import (
func (r *CommandSide) AddOrgDomain(ctx context.Context, orgDomain *domain.OrgDomain) (*domain.OrgDomain, error) {
domainWriteModel := NewOrgDomainWriteModel(orgDomain.AggregateID, orgDomain.Domain)
orgAgg := OrgAggregateFromWriteModel(&domainWriteModel.WriteModel)
userAggregates, err := r.addOrgDomain(ctx, orgAgg, domainWriteModel, orgDomain)
events, err := r.addOrgDomain(ctx, orgAgg, domainWriteModel, orgDomain)
if err != nil {
return nil, err
}
if len(userAggregates) == 0 {
err = r.eventstore.PushAggregate(ctx, domainWriteModel, orgAgg)
if err != nil {
return nil, err
}
return orgDomainWriteModelToOrgDomain(domainWriteModel), nil
}
aggregates := make([]eventstore.Aggregater, 0)
aggregates = append(aggregates, orgAgg)
aggregates = append(aggregates, userAggregates...)
resultEvents, err := r.eventstore.PushAggregates(ctx, aggregates...)
pushedEvents, err := r.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
err = AppendAndReduce(domainWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
domainWriteModel.AppendEvents(resultEvents...)
domainWriteModel.Reduce()
return orgDomainWriteModelToOrgDomain(domainWriteModel), nil
}
@ -68,9 +59,10 @@ func (r *CommandSide) GenerateOrgDomainValidation(ctx context.Context, orgDomain
}
orgAgg := OrgAggregateFromWriteModel(&domainWriteModel.WriteModel)
orgAgg.PushEvents(org.NewDomainVerificationAddedEvent(ctx, orgDomain.Domain, orgDomain.ValidationType, orgDomain.ValidationCode))
err = r.eventstore.PushAggregate(ctx, domainWriteModel, orgAgg)
_, err = r.eventstore.PushEvents(
ctx,
org.NewDomainVerificationAddedEvent(ctx, orgAgg, orgDomain.Domain, orgDomain.ValidationType, orgDomain.ValidationCode))
if err != nil {
return "", "", err
}
@ -102,25 +94,24 @@ func (r *CommandSide) ValidateOrgDomain(ctx context.Context, orgDomain *domain.O
checkType, _ := domainWriteModel.ValidationType.CheckType()
err = r.domainVerificationValidator(domainWriteModel.Domain, validationCode, validationCode, checkType)
orgAgg := OrgAggregateFromWriteModel(&domainWriteModel.WriteModel)
var events []eventstore.EventPusher
if err == nil {
aggregates := make([]eventstore.Aggregater, 0)
orgAgg.PushEvents(org.NewDomainVerifiedEvent(ctx, orgDomain.Domain))
aggregates = append(aggregates, orgAgg)
events = append(events, org.NewDomainVerifiedEvent(ctx, orgAgg, orgDomain.Domain))
for _, userID := range claimedUserIDs {
userAgg, _, err := r.userDomainClaimed(ctx, userID)
userEvents, _, err := r.userDomainClaimed(ctx, userID)
if err != nil {
logging.LogWithFields("COMMAND-5m8fs", "userid", userID).WithError(err).Warn("could not claim user")
continue
}
aggregates = append(aggregates, userAgg)
events = append(events, userEvents...)
}
_, err = r.eventstore.PushAggregates(ctx, aggregates...)
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}
orgAgg.PushEvents(org.NewDomainVerificationFailedEvent(ctx, orgDomain.Domain))
err = r.eventstore.PushAggregate(ctx, domainWriteModel, orgAgg)
logging.LogWithFields("ORG-dhTE", "orgID", orgAgg.ID(), "domain", orgDomain.Domain).OnError(err).Error("NewDomainVerificationFailedEvent push failed")
events = append(events, org.NewDomainVerificationFailedEvent(ctx, orgAgg, orgDomain.Domain))
_, err = r.eventstore.PushEvents(ctx, events...)
logging.LogWithFields("ORG-dhTE", "orgID", orgAgg.ID, "domain", orgDomain.Domain).OnError(err).Error("NewDomainVerificationFailedEvent push failed")
return caos_errs.ThrowInvalidArgument(err, "ORG-GH3s", "Errors.Org.DomainVerificationFailed")
}
@ -139,8 +130,8 @@ func (r *CommandSide) SetPrimaryOrgDomain(ctx context.Context, orgDomain *domain
return caos_errs.ThrowPreconditionFailed(nil, "ORG-Ggd32", "Errors.Org.DomainNotVerified")
}
orgAgg := OrgAggregateFromWriteModel(&domainWriteModel.WriteModel)
orgAgg.PushEvents(org.NewDomainPrimarySetEvent(ctx, orgDomain.Domain))
return r.eventstore.PushAggregate(ctx, domainWriteModel, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewDomainPrimarySetEvent(ctx, orgAgg, orgDomain.Domain))
return err
}
func (r *CommandSide) RemoveOrgDomain(ctx context.Context, orgDomain *domain.OrgDomain) error {
@ -158,11 +149,11 @@ func (r *CommandSide) RemoveOrgDomain(ctx context.Context, orgDomain *domain.Org
return caos_errs.ThrowPreconditionFailed(nil, "ORG-Sjdi3", "Errors.Org.PrimaryDomainNotDeletable")
}
orgAgg := OrgAggregateFromWriteModel(&domainWriteModel.WriteModel)
orgAgg.PushEvents(org.NewDomainRemovedEvent(ctx, orgDomain.Domain))
return r.eventstore.PushAggregate(ctx, domainWriteModel, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewDomainRemovedEvent(ctx, orgAgg, orgDomain.Domain))
return err
}
func (r *CommandSide) addOrgDomain(ctx context.Context, orgAgg *org.Aggregate, addedDomain *OrgDomainWriteModel, orgDomain *domain.OrgDomain, claimedUserIDs ...string) ([]eventstore.Aggregater, error) {
func (r *CommandSide) addOrgDomain(ctx context.Context, orgAgg *eventstore.Aggregate, addedDomain *OrgDomainWriteModel, orgDomain *domain.OrgDomain, claimedUserIDs ...string) ([]eventstore.EventPusher, error) {
err := r.eventstore.FilterToQueryReducer(ctx, addedDomain)
if err != nil {
return nil, err
@ -171,24 +162,25 @@ func (r *CommandSide) addOrgDomain(ctx context.Context, orgAgg *org.Aggregate, a
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMA-Bd2jj", "Errors.Org.Domain.AlreadyExists")
}
orgAgg.PushEvents(org.NewDomainAddedEvent(ctx, orgDomain.Domain))
events := []eventstore.EventPusher{
org.NewDomainAddedEvent(ctx, orgAgg, orgDomain.Domain),
}
userAggregates := make([]eventstore.Aggregater, 0)
if orgDomain.Verified {
orgAgg.PushEvents(org.NewDomainVerifiedEvent(ctx, orgDomain.Domain))
events = append(events, org.NewDomainVerifiedEvent(ctx, orgAgg, orgDomain.Domain))
for _, userID := range claimedUserIDs {
userAgg, _, err := r.userDomainClaimed(ctx, userID)
userEvents, _, err := r.userDomainClaimed(ctx, userID)
if err != nil {
logging.LogWithFields("COMMAND-nn8Jf", "userid", userID).WithError(err).Warn("could not claim user")
continue
}
userAggregates = append(userAggregates, userAgg)
events = append(events, userEvents...)
}
}
if orgDomain.Primary {
orgAgg.PushEvents(org.NewDomainPrimarySetEvent(ctx, orgDomain.Domain))
events = append(events, org.NewDomainPrimarySetEvent(ctx, orgAgg, orgDomain.Domain))
}
return userAggregates, nil
return events, nil
}
func (r *CommandSide) getOrgDomainWriteModel(ctx context.Context, orgID, domain string) (*OrgDomainWriteModel, error) {

@ -88,5 +88,12 @@ func (wm *OrgDomainWriteModel) Reduce() error {
func (wm *OrgDomainWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
org.OrgDomainAddedEventType,
org.OrgDomainVerifiedEventType,
org.OrgDomainVerificationAddedEventType,
org.OrgDomainVerifiedEventType,
org.OrgDomainPrimarySetEventType,
org.OrgDomainRemovedEventType)
}

@ -30,28 +30,31 @@ func (r *CommandSide) AddIDPConfig(ctx context.Context, config *domain.IDPConfig
}
orgAgg := OrgAggregateFromWriteModel(&addedConfig.WriteModel)
orgAgg.PushEvents(
events := []eventstore.EventPusher{
org_repo.NewIDPConfigAddedEvent(
ctx,
orgAgg.ResourceOwner(),
orgAgg,
idpConfigID,
config.Name,
config.Type,
config.StylingType,
),
)
orgAgg.PushEvents(
org_repo.NewIDPOIDCConfigAddedEvent(
ctx, config.OIDCConfig.ClientID,
ctx,
orgAgg,
config.OIDCConfig.ClientID,
idpConfigID,
config.OIDCConfig.Issuer,
clientSecret,
config.OIDCConfig.IDPDisplayNameMapping,
config.OIDCConfig.UsernameMapping,
config.OIDCConfig.Scopes...,
),
)
err = r.eventstore.PushAggregate(ctx, addedConfig, orgAgg)
config.OIDCConfig.Scopes...),
}
pushedEvents, err := r.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedConfig, pushedEvents...)
if err != nil {
return nil, err
}
@ -67,9 +70,10 @@ func (r *CommandSide) ChangeIDPConfig(ctx context.Context, config *domain.IDPCon
return nil, caos_errs.ThrowNotFound(nil, "Org-4M9so", "Errors.Org.IDPConfig.NotExisting")
}
orgAgg := OrgAggregateFromWriteModel(&existingIDP.WriteModel)
changedEvent, hasChanged := existingIDP.NewChangedEvent(
ctx,
existingIDP.ResourceOwner,
orgAgg,
config.IDPConfigID,
config.Name,
config.StylingType)
@ -77,10 +81,11 @@ func (r *CommandSide) ChangeIDPConfig(ctx context.Context, config *domain.IDPCon
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-4M9vs", "Errors.Org.LabelPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingIDP.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingIDP, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingIDP, pushedEvents...)
if err != nil {
return nil, err
}
@ -96,9 +101,8 @@ func (r *CommandSide) DeactivateIDPConfig(ctx context.Context, idpID, orgID stri
return caos_errs.ThrowPreconditionFailed(nil, "Org-4M9so", "Errors.Org.IDPConfig.NotActive")
}
orgAgg := OrgAggregateFromWriteModel(&existingIDP.WriteModel)
orgAgg.PushEvents(org_repo.NewIDPConfigDeactivatedEvent(ctx, idpID))
return r.eventstore.PushAggregate(ctx, existingIDP, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org_repo.NewIDPConfigDeactivatedEvent(ctx, orgAgg, idpID))
return err
}
func (r *CommandSide) ReactivateIDPConfig(ctx context.Context, idpID, orgID string) error {
@ -110,9 +114,8 @@ func (r *CommandSide) ReactivateIDPConfig(ctx context.Context, idpID, orgID stri
return caos_errs.ThrowPreconditionFailed(nil, "Org-5Mo0d", "Errors.Org.IDPConfig.NotInactive")
}
orgAgg := OrgAggregateFromWriteModel(&existingIDP.WriteModel)
orgAgg.PushEvents(org_repo.NewIDPConfigReactivatedEvent(ctx, idpID))
return r.eventstore.PushAggregate(ctx, existingIDP, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org_repo.NewIDPConfigReactivatedEvent(ctx, orgAgg, idpID))
return err
}
func (r *CommandSide) RemoveIDPConfig(ctx context.Context, idpID, orgID string, cascadeRemoveProvider bool, cascadeExternalIDPs ...*domain.ExternalIDP) error {
@ -128,18 +131,16 @@ func (r *CommandSide) RemoveIDPConfig(ctx context.Context, idpID, orgID string,
return caos_errs.ThrowPreconditionFailed(nil, "Org-5Mo0d", "Errors.Org.IDPConfig.NotInactive")
}
aggregates := make([]eventstore.Aggregater, 0)
orgAgg := OrgAggregateFromWriteModel(&existingIDP.WriteModel)
orgAgg.PushEvents(org_repo.NewIDPConfigRemovedEvent(ctx, existingIDP.ResourceOwner, idpID, existingIDP.Name))
userAggregates := make([]eventstore.Aggregater, 0)
if cascadeRemoveProvider {
userAggregates = r.removeIDPProviderFromLoginPolicy(ctx, orgAgg, idpID, true, cascadeExternalIDPs...)
events := []eventstore.EventPusher{
org_repo.NewIDPConfigRemovedEvent(ctx, orgAgg, idpID, existingIDP.Name),
}
aggregates = append(aggregates, orgAgg)
aggregates = append(aggregates, userAggregates...)
_, err = r.eventstore.PushAggregates(ctx, aggregates...)
if cascadeRemoveProvider {
removeIDPEvents := r.removeIDPProviderFromLoginPolicy(ctx, orgAgg, idpID, true, cascadeExternalIDPs...)
events = append(events, removeIDPEvents...)
}
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}

@ -28,7 +28,15 @@ func NewOrgIDPConfigWriteModel(configID, orgID string) *OrgIDPConfigWriteModel {
func (wm *OrgIDPConfigWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
org.IDPConfigAddedEventType,
org.IDPConfigChangedEventType,
org.IDPConfigDeactivatedEventType,
org.IDPConfigReactivatedEventType,
org.IDPConfigRemovedEventType,
org.IDPOIDCConfigAddedEventType,
org.IDPOIDCConfigChangedEventType)
}
func (wm *OrgIDPConfigWriteModel) AppendEvents(events ...eventstore.EventReader) {
@ -84,7 +92,7 @@ func (wm *OrgIDPConfigWriteModel) AppendAndReduce(events ...eventstore.EventRead
func (wm *OrgIDPConfigWriteModel) NewChangedEvent(
ctx context.Context,
resourceOwner,
aggregate *eventstore.Aggregate,
configID,
name string,
stylingType domain.IDPConfigStylingType,
@ -102,7 +110,7 @@ func (wm *OrgIDPConfigWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changeEvent, err := org.NewIDPConfigChangedEvent(ctx, resourceOwner, configID, oldName, changes)
changeEvent, err := org.NewIDPConfigChangedEvent(ctx, aggregate, configID, oldName, changes)
if err != nil {
return nil, false
}

@ -17,8 +17,10 @@ func (r *CommandSide) ChangeIDPOIDCConfig(ctx context.Context, config *domain.OI
return nil, caos_errs.ThrowAlreadyExists(nil, "Org-67J9d", "Errors.Org.IDPConfig.AlreadyExists")
}
orgAgg := OrgAggregateFromWriteModel(&existingConfig.WriteModel)
changedEvent, hasChanged, err := existingConfig.NewChangedEvent(
ctx,
orgAgg,
config.IDPConfigID,
config.ClientID,
config.Issuer,
@ -34,10 +36,11 @@ func (r *CommandSide) ChangeIDPOIDCConfig(ctx context.Context, config *domain.OI
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-4M9vs", "Errors.Org.LabelPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingConfig.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingConfig, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingConfig, pushedEvents...)
if err != nil {
return nil, err
}

@ -71,11 +71,18 @@ func (wm *IDPOIDCConfigWriteModel) Reduce() error {
func (wm *IDPOIDCConfigWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
org.IDPOIDCConfigAddedEventType,
org.IDPOIDCConfigChangedEventType,
org.IDPConfigReactivatedEventType,
org.IDPConfigDeactivatedEventType,
org.IDPConfigRemovedEventType)
}
func (wm *IDPOIDCConfigWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
idpConfigID,
clientID,
issuer,
@ -114,7 +121,7 @@ func (wm *IDPOIDCConfigWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false, nil
}
changeEvent, err := org.NewIDPOIDCConfigChangedEvent(ctx, idpConfigID, changes)
changeEvent, err := org.NewIDPOIDCConfigChangedEvent(ctx, aggregate, idpConfigID, changes)
if err != nil {
return nil, false, err
}

@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/errors"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
@ -14,37 +15,38 @@ import (
func (r *CommandSide) AddOrgMember(ctx context.Context, member *domain.Member) (*domain.Member, error) {
addedMember := NewOrgMemberWriteModel(member.AggregateID, member.UserID)
orgAgg := OrgAggregateFromWriteModel(&addedMember.WriteModel)
err := r.addOrgMember(ctx, orgAgg, addedMember, member)
event, err := r.addOrgMember(ctx, orgAgg, addedMember, member)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedMember, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedMember, pushedEvents...)
if err != nil {
return nil, err
}
return memberWriteModelToMember(&addedMember.MemberWriteModel), nil
}
func (r *CommandSide) addOrgMember(ctx context.Context, orgAgg *org.Aggregate, addedMember *OrgMemberWriteModel, member *domain.Member) error {
func (r *CommandSide) addOrgMember(ctx context.Context, orgAgg *eventstore.Aggregate, addedMember *OrgMemberWriteModel, member *domain.Member) (eventstore.EventPusher, error) {
//TODO: check if roles valid
if !member.IsValid() {
return caos_errs.ThrowPreconditionFailed(nil, "Org-W8m4l", "Errors.Org.MemberInvalid")
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-W8m4l", "Errors.Org.MemberInvalid")
}
err := r.eventstore.FilterToQueryReducer(ctx, addedMember)
if err != nil {
return err
return nil, err
}
if addedMember.State == domain.MemberStateActive {
return errors.ThrowAlreadyExists(nil, "Org-PtXi1", "Errors.Org.Member.AlreadyExists")
return nil, errors.ThrowAlreadyExists(nil, "Org-PtXi1", "Errors.Org.Member.AlreadyExists")
}
orgAgg.PushEvents(org.NewMemberAddedEvent(ctx, orgAgg.ID(), member.UserID, member.Roles...))
return nil
return org.NewMemberAddedEvent(ctx, orgAgg, member.UserID, member.Roles...), nil
}
//ChangeOrgMember updates an existing member
@ -64,18 +66,12 @@ func (r *CommandSide) ChangeOrgMember(ctx context.Context, member *domain.Member
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-LiaZi", "Errors.Org.Member.RolesNotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingMember.MemberWriteModel.WriteModel)
orgAgg.PushEvents(org.NewMemberChangedEvent(ctx, member.UserID, member.Roles...))
events, err := r.eventstore.PushAggregates(ctx, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, org.NewMemberChangedEvent(ctx, orgAgg, member.UserID, member.Roles...))
err = AppendAndReduce(existingMember, pushedEvents...)
if err != nil {
return nil, err
}
existingMember.AppendEvents(events...)
if err = existingMember.Reduce(); err != nil {
return nil, err
}
return memberWriteModelToMember(&existingMember.MemberWriteModel), nil
}
@ -89,9 +85,8 @@ func (r *CommandSide) RemoveOrgMember(ctx context.Context, orgID, userID string)
}
orgAgg := OrgAggregateFromWriteModel(&m.MemberWriteModel.WriteModel)
orgAgg.PushEvents(org.NewMemberRemovedEvent(ctx, orgAgg.ID(), userID))
return r.eventstore.PushAggregate(ctx, m, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewMemberRemovedEvent(ctx, orgAgg, userID))
return err
}
func (r *CommandSide) orgMemberWriteModelByID(ctx context.Context, orgID, userID string) (member *OrgMemberWriteModel, err error) {

@ -50,5 +50,9 @@ func (wm *OrgMemberWriteModel) Reduce() error {
func (wm *OrgMemberWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.MemberWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
org.MemberAddedEventType,
org.MemberChangedEventType,
org.MemberRemovedEventType)
}

@ -3,7 +3,6 @@ package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/org"
)
@ -24,19 +23,6 @@ func NewOrgWriteModel(orgID string) *OrgWriteModel {
}
}
func (wm *OrgWriteModel) AppendEvents(events ...eventstore.EventReader) {
wm.WriteModel.AppendEvents(events...)
for _, event := range events {
switch e := event.(type) {
case *org.OrgAddedEvent,
*iam.LabelPolicyChangedEvent:
wm.WriteModel.AppendEvents(e)
case *org.DomainPrimarySetEvent:
wm.WriteModel.AppendEvents(e)
}
}
}
func (wm *OrgWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
@ -55,11 +41,13 @@ func (wm *OrgWriteModel) Reduce() error {
func (wm *OrgWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
org.OrgAddedEventType,
org.OrgChangedEventType,
org.OrgDomainPrimarySetEventType)
}
func OrgAggregateFromWriteModel(wm *eventstore.WriteModel) *org.Aggregate {
return &org.Aggregate{
Aggregate: *eventstore.AggregateFromWriteModel(wm, org.AggregateType, org.AggregateVersion),
}
func OrgAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate {
return eventstore.AggregateFromWriteModel(wm, org.AggregateType, org.AggregateVersion)
}

@ -19,13 +19,14 @@ func (r *CommandSide) AddLabelPolicy(ctx context.Context, resourceOwner string,
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.LabelPolicyWriteModel.WriteModel)
orgAgg.PushEvents(org.NewLabelPolicyAddedEvent(ctx, policy.PrimaryColor, policy.SecondaryColor))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, org.NewLabelPolicyAddedEvent(ctx, orgAgg, policy.PrimaryColor, policy.SecondaryColor))
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToLabelPolicy(&addedPolicy.LabelPolicyWriteModel), nil
}
@ -39,19 +40,20 @@ func (r *CommandSide) ChangeLabelPolicy(ctx context.Context, resourceOwner strin
return nil, caos_errs.ThrowNotFound(nil, "Org-0K9dq", "Errors.Org.LabelPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.PrimaryColor, policy.SecondaryColor)
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.PrimaryColor, policy.SecondaryColor)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-4M9vs", "Errors.Org.LabelPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToLabelPolicy(&existingPolicy.LabelPolicyWriteModel), nil
}
@ -65,7 +67,6 @@ func (r *CommandSide) RemoveLabelPolicy(ctx context.Context, orgID string) error
return caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LabelPolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
orgAgg.PushEvents(org.NewLabelPolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewLabelPolicyRemovedEvent(ctx, orgAgg))
return err
}

@ -41,11 +41,15 @@ func (wm *OrgLabelPolicyWriteModel) Reduce() error {
func (wm *OrgLabelPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.LabelPolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
org.LabelPolicyAddedEventType,
org.LabelPolicyChangedEventType)
}
func (wm *OrgLabelPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
primaryColor,
secondaryColor string,
) (*org.LabelPolicyChangedEvent, bool) {
@ -59,7 +63,7 @@ func (wm *OrgLabelPolicyWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewLabelPolicyChangedEvent(ctx, changes)
changedEvent, err := org.NewLabelPolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -3,9 +3,8 @@ package command
import (
"context"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/eventstore/v2"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
)
@ -21,13 +20,23 @@ func (r *CommandSide) AddLoginPolicy(ctx context.Context, resourceOwner string,
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicyAddedEvent(ctx, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(
ctx,
org.NewLoginPolicyAddedEvent(
ctx,
orgAgg,
policy.AllowUsernamePassword,
policy.AllowRegister,
policy.AllowExternalIDP,
policy.ForceMFA,
policy.PasswordlessType))
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToLoginPolicy(&addedPolicy.LoginPolicyWriteModel), nil
}
@ -40,19 +49,20 @@ func (r *CommandSide) ChangeLoginPolicy(ctx context.Context, resourceOwner strin
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "Org-M0sif", "Errors.Org.LoginPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType)
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-5M9vdd", "Errors.Org.LoginPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToLoginPolicy(&existingPolicy.LoginPolicyWriteModel), nil
}
@ -66,9 +76,8 @@ func (r *CommandSide) RemoveLoginPolicy(ctx context.Context, orgID string) error
return caos_errs.ThrowNotFound(nil, "Org-GHB37", "Errors.Org.LoginPolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewLoginPolicyRemovedEvent(ctx, orgAgg))
return err
}
func (r *CommandSide) AddIDPProviderToLoginPolicy(ctx context.Context, resourceOwner string, idpProvider *domain.IDPProvider) (*domain.IDPProvider, error) {
@ -82,12 +91,14 @@ func (r *CommandSide) AddIDPProviderToLoginPolicy(ctx context.Context, resourceO
}
orgAgg := OrgAggregateFromWriteModel(&idpModel.WriteModel)
orgAgg.PushEvents(org.NewIdentityProviderAddedEvent(ctx, idpProvider.IDPConfigID, idpProvider.Type))
if err = r.eventstore.PushAggregate(ctx, idpModel, orgAgg); err != nil {
pushedEvents, err := r.eventstore.PushEvents(ctx, org.NewIdentityProviderAddedEvent(ctx, orgAgg, idpProvider.IDPConfigID, idpProvider.Type))
if err != nil {
return nil, err
}
err = AppendAndReduce(idpModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToIDPProvider(&idpModel.IdentityProviderWriteModel), nil
}
@ -101,35 +112,30 @@ func (r *CommandSide) RemoveIDPProviderFromLoginPolicy(ctx context.Context, reso
return caos_errs.ThrowNotFound(nil, "Org-39fjs", "Errors.Org.LoginPolicy.IDP.NotExisting")
}
aggregates := make([]eventstore.Aggregater, 0)
orgAgg := OrgAggregateFromWriteModel(&idpModel.IdentityProviderWriteModel.WriteModel)
userAggregates := r.removeIDPProviderFromLoginPolicy(ctx, orgAgg, idpProvider.IDPConfigID, false, cascadeExternalIDPs...)
events := r.removeIDPProviderFromLoginPolicy(ctx, orgAgg, idpProvider.IDPConfigID, false, cascadeExternalIDPs...)
aggregates = append(aggregates, orgAgg)
aggregates = append(aggregates, userAggregates...)
_, err = r.eventstore.PushAggregates(ctx, aggregates...)
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}
func (r *CommandSide) removeIDPProviderFromLoginPolicy(ctx context.Context, orgAgg *org.Aggregate, idpConfigID string, cascade bool, cascadeExternalIDPs ...*domain.ExternalIDP) []eventstore.Aggregater {
func (r *CommandSide) removeIDPProviderFromLoginPolicy(ctx context.Context, orgAgg *eventstore.Aggregate, idpConfigID string, cascade bool, cascadeExternalIDPs ...*domain.ExternalIDP) []eventstore.EventPusher {
var events []eventstore.EventPusher
if cascade {
orgAgg.PushEvents(org.NewIdentityProviderCascadeRemovedEvent(ctx, idpConfigID))
events = append(events, org.NewIdentityProviderCascadeRemovedEvent(ctx, orgAgg, idpConfigID))
} else {
orgAgg.PushEvents(org.NewIdentityProviderRemovedEvent(ctx, idpConfigID))
events = append(events, org.NewIdentityProviderRemovedEvent(ctx, orgAgg, idpConfigID))
}
userAggregates := make([]eventstore.Aggregater, 0)
for _, idp := range cascadeExternalIDPs {
userAgg, _, err := r.removeHumanExternalIDP(ctx, idp, true)
event, err := r.removeHumanExternalIDP(ctx, idp, true)
if err != nil {
logging.LogWithFields("COMMAND-n8RRf", "userid", idp.AggregateID, "idpconfigid", idp.IDPConfigID).WithError(err).Warn("could not cascade remove external idp")
continue
}
userAggregates = append(userAggregates, userAgg)
events = append(events, event)
}
return userAggregates
return events
}
func (r *CommandSide) AddSecondFactorToLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType, orgID string) (domain.SecondFactorType, error) {
@ -144,9 +150,8 @@ func (r *CommandSide) AddSecondFactorToLoginPolicy(ctx context.Context, secondFa
}
orgAgg := OrgAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicySecondFactorAddedEvent(ctx, secondFactor))
if err = r.eventstore.PushAggregate(ctx, secondFactorModel, orgAgg); err != nil {
if _, err = r.eventstore.PushEvents(ctx, org.NewLoginPolicySecondFactorAddedEvent(ctx, orgAgg, secondFactor)); err != nil {
return domain.SecondFactorTypeUnspecified, err
}
@ -163,9 +168,9 @@ func (r *CommandSide) RemoveSecondFactorFromLoginPolicy(ctx context.Context, sec
return caos_errs.ThrowNotFound(nil, "Org-3M9od", "Errors.Org.LoginPolicy.MFA.NotExisting")
}
orgAgg := OrgAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicySecondFactorRemovedEvent(ctx, domain.SecondFactorType(secondFactor)))
return r.eventstore.PushAggregate(ctx, secondFactorModel, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewLoginPolicySecondFactorRemovedEvent(ctx, orgAgg, secondFactor))
return err
}
func (r *CommandSide) AddMultiFactorToLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType, orgID string) (domain.MultiFactorType, error) {
@ -179,9 +184,8 @@ func (r *CommandSide) AddMultiFactorToLoginPolicy(ctx context.Context, multiFact
}
orgAgg := OrgAggregateFromWriteModel(&multiFactorModel.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicyMultiFactorAddedEvent(ctx, multiFactor))
if err = r.eventstore.PushAggregate(ctx, multiFactorModel, orgAgg); err != nil {
if _, err = r.eventstore.PushEvents(ctx, org.NewLoginPolicyMultiFactorAddedEvent(ctx, orgAgg, multiFactor)); err != nil {
return domain.MultiFactorTypeUnspecified, err
}
@ -198,7 +202,7 @@ func (r *CommandSide) RemoveMultiFactorFromLoginPolicy(ctx context.Context, mult
return caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LoginPolicy.MFA.NotExisting")
}
orgAgg := OrgAggregateFromWriteModel(&multiFactorModel.MultiFactoryWriteModel.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicyMultiFactorRemovedEvent(ctx, domain.MultiFactorType(multiFactor)))
return r.eventstore.PushAggregate(ctx, multiFactorModel, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewLoginPolicyMultiFactorRemovedEvent(ctx, orgAgg, multiFactor))
return err
}

@ -2,7 +2,7 @@ package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/org"
)
type OrgSecondFactorWriteModel struct {
@ -23,8 +23,10 @@ func NewOrgSecondFactorWriteModel(orgID string) *OrgSecondFactorWriteModel {
func (wm *OrgSecondFactorWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.LoginPolicySecondFactorAddedEvent:
case *org.LoginPolicySecondFactorAddedEvent:
wm.WriteModel.AppendEvents(&e.SecondFactorAddedEvent)
case *org.LoginPolicySecondFactorRemovedEvent:
wm.WriteModel.AppendEvents(&e.SecondFactorRemovedEvent)
}
}
}
@ -34,9 +36,12 @@ func (wm *OrgSecondFactorWriteModel) Reduce() error {
}
func (wm *OrgSecondFactorWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.WriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
org.LoginPolicySecondFactorAddedEventType,
org.LoginPolicySecondFactorRemovedEventType)
}
type OrgMultiFactorWriteModel struct {
@ -57,8 +62,10 @@ func NewOrgMultiFactorWriteModel(orgID string) *OrgMultiFactorWriteModel {
func (wm *OrgMultiFactorWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.LoginPolicyMultiFactorAddedEvent:
case *org.LoginPolicyMultiFactorAddedEvent:
wm.WriteModel.AppendEvents(&e.MultiFactorAddedEvent)
case *org.LoginPolicyMultiFactorRemovedEvent:
wm.WriteModel.AppendEvents(&e.MultiFactorRemovedEvent)
}
}
}
@ -68,7 +75,10 @@ func (wm *OrgMultiFactorWriteModel) Reduce() error {
}
func (wm *OrgMultiFactorWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.WriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
org.LoginPolicyMultiFactorAddedEventType,
org.LoginPolicyMultiFactorRemovedEventType)
}

@ -48,11 +48,16 @@ func (wm *OrgLoginPolicyWriteModel) Reduce() error {
func (wm *OrgLoginPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.LoginPolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
org.LoginPolicyAddedEventType,
org.LoginPolicyChangedEventType,
org.LoginPolicyRemovedEventType)
}
func (wm *OrgLoginPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
allowUsernamePassword,
allowRegister,
allowExternalIDP,
@ -79,7 +84,7 @@ func (wm *OrgLoginPolicyWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewLoginPolicyChangedEvent(ctx, changes)
changedEvent, err := org.NewLoginPolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -22,13 +22,14 @@ func (r *CommandSide) AddMailTemplate(ctx context.Context, resourceOwner string,
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.MailTemplateWriteModel.WriteModel)
orgAgg.PushEvents(org.NewMailTemplateAddedEvent(ctx, policy.Template))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, org.NewMailTemplateAddedEvent(ctx, orgAgg, policy.Template))
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToMailTemplate(&addedPolicy.MailTemplateWriteModel), nil
}
@ -45,19 +46,20 @@ func (r *CommandSide) ChangeMailTemplate(ctx context.Context, resourceOwner stri
return nil, caos_errs.ThrowNotFound(nil, "Org-5m9ie", "Errors.Org.MailTemplate.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.Template)
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.MailTemplateWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.Template)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-4M9vs", "Errors.Org.MailTemplate.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.MailTemplateWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToMailTemplate(&existingPolicy.MailTemplateWriteModel), nil
}
@ -71,7 +73,7 @@ func (r *CommandSide) RemoveMailTemplate(ctx context.Context, orgID string) erro
return caos_errs.ThrowNotFound(nil, "Org-3b8Jf", "Errors.Org.MailTemplate.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
orgAgg.PushEvents(org.NewMailTemplateRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewMailTemplateRemovedEvent(ctx, orgAgg))
return err
}

@ -31,6 +31,8 @@ func (wm *OrgMailTemplateWriteModel) AppendEvents(events ...eventstore.EventRead
wm.MailTemplateWriteModel.AppendEvents(&e.MailTemplateAddedEvent)
case *org.MailTemplateChangedEvent:
wm.MailTemplateWriteModel.AppendEvents(&e.MailTemplateChangedEvent)
case *org.MailTemplateRemovedEvent:
wm.MailTemplateWriteModel.AppendEvents(&e.MailTemplateRemovedEvent)
}
}
}
@ -41,7 +43,12 @@ func (wm *OrgMailTemplateWriteModel) Reduce() error {
func (wm *OrgMailTemplateWriteModel) Query() *eventstore.SearchQueryBuilder {
query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.MailTemplateWriteModel.AggregateID)
AggregateIDs(wm.MailTemplateWriteModel.AggregateID).
EventTypes(
org.MailTemplateAddedEventType,
org.MailTemplateChangedEventType,
org.MailTemplateRemovedEventType)
if wm.ResourceOwner != "" {
query.ResourceOwner(wm.ResourceOwner)
}
@ -50,6 +57,7 @@ func (wm *OrgMailTemplateWriteModel) Query() *eventstore.SearchQueryBuilder {
func (wm *OrgMailTemplateWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
template []byte,
) (*org.MailTemplateChangedEvent, bool) {
changes := make([]policy.MailTemplateChanges, 0)
@ -59,7 +67,7 @@ func (wm *OrgMailTemplateWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewMailTemplateChangedEvent(ctx, changes)
changedEvent, err := org.NewMailTemplateChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -22,10 +22,11 @@ func (r *CommandSide) AddMailText(ctx context.Context, resourceOwner string, mai
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.MailTextWriteModel.WriteModel)
orgAgg.PushEvents(
pushedEvents, err := r.eventstore.PushEvents(
ctx,
org.NewMailTextAddedEvent(
ctx,
resourceOwner,
orgAgg,
mailText.MailTextType,
mailText.Language,
mailText.Title,
@ -34,8 +35,10 @@ func (r *CommandSide) AddMailText(ctx context.Context, resourceOwner string, mai
mailText.Greeting,
mailText.Text,
mailText.ButtonText))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
@ -56,8 +59,10 @@ func (r *CommandSide) ChangeMailText(ctx context.Context, resourceOwner string,
return nil, caos_errs.ThrowNotFound(nil, "Org-3n8fM", "Errors.Org.MailText.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.MailTextWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(
ctx,
orgAgg,
mailText.MailTextType,
mailText.Language,
mailText.Title,
@ -70,10 +75,11 @@ func (r *CommandSide) ChangeMailText(ctx context.Context, resourceOwner string,
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-2n9fs", "Errors.Org.MailText.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.MailTextWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
@ -91,7 +97,6 @@ func (r *CommandSide) RemoveMailText(ctx context.Context, resourceOwner, mailTex
return caos_errs.ThrowNotFound(nil, "Org-3b8Jf", "Errors.Org.MailText.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
orgAgg.PushEvents(org.NewMailTextRemovedEvent(ctx, mailTextType, language, resourceOwner))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewMailTextRemovedEvent(ctx, orgAgg, mailTextType, language))
return err
}

@ -31,6 +31,8 @@ func (wm *OrgMailTextWriteModel) AppendEvents(events ...eventstore.EventReader)
wm.MailTextWriteModel.AppendEvents(&e.MailTextAddedEvent)
case *org.MailTextChangedEvent:
wm.MailTextWriteModel.AppendEvents(&e.MailTextChangedEvent)
case *org.MailTextRemovedEvent:
wm.MailTextWriteModel.AppendEvents(&e.MailTextRemovedEvent)
}
}
}
@ -41,7 +43,10 @@ func (wm *OrgMailTextWriteModel) Reduce() error {
func (wm *OrgMailTextWriteModel) Query() *eventstore.SearchQueryBuilder {
query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.MailTextWriteModel.AggregateID)
AggregateIDs(wm.MailTextWriteModel.AggregateID).
EventTypes(org.MailTextAddedEventType,
org.MailTextChangedEventType,
org.MailTextRemovedEventType)
if wm.ResourceOwner != "" {
query.ResourceOwner(wm.ResourceOwner)
}
@ -50,6 +55,7 @@ func (wm *OrgMailTextWriteModel) Query() *eventstore.SearchQueryBuilder {
func (wm *OrgMailTextWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
mailTextType,
language,
title,
@ -81,7 +87,7 @@ func (wm *OrgMailTextWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewMailTextChangedEvent(ctx, mailTextType, language, changes)
changedEvent, err := org.NewMailTextChangedEvent(ctx, aggregate, mailTextType, language, changes)
if err != nil {
return nil, false
}

@ -3,6 +3,7 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
@ -11,33 +12,30 @@ import (
func (r *CommandSide) AddOrgIAMPolicy(ctx context.Context, resourceOwner string, policy *domain.OrgIAMPolicy) (*domain.OrgIAMPolicy, error) {
addedPolicy := NewORGOrgIAMPolicyWriteModel(resourceOwner)
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.PolicyOrgIAMWriteModel.WriteModel)
err := r.addOrgIAMPolicy(ctx, orgAgg, addedPolicy, policy)
event, err := r.addOrgIAMPolicy(ctx, orgAgg, addedPolicy, policy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "ORG-5M0ds", "Errors.Org.OrgIAMPolicy.AlreadyExists")
}
orgAgg.PushEvents(org.NewOrgIAMPolicyAddedEvent(ctx, policy.UserLoginMustBeDomain))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return orgWriteModelToOrgIAMPolicy(addedPolicy), nil
}
func (r *CommandSide) addOrgIAMPolicy(ctx context.Context, orgAgg *org.Aggregate, addedPolicy *ORGOrgIAMPolicyWriteModel, policy *domain.OrgIAMPolicy) error {
func (r *CommandSide) addOrgIAMPolicy(ctx context.Context, orgAgg *eventstore.Aggregate, addedPolicy *ORGOrgIAMPolicyWriteModel, policy *domain.OrgIAMPolicy) (eventstore.EventPusher, error) {
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return err
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return caos_errs.ThrowAlreadyExists(nil, "ORG-1M8ds", "Errors.Org.OrgIAMPolicy.AlreadyExists")
return nil, caos_errs.ThrowAlreadyExists(nil, "ORG-1M8ds", "Errors.Org.OrgIAMPolicy.AlreadyExists")
}
orgAgg.PushEvents(org.NewOrgIAMPolicyAddedEvent(ctx, policy.UserLoginMustBeDomain))
return nil
return org.NewOrgIAMPolicyAddedEvent(ctx, orgAgg, policy.UserLoginMustBeDomain), nil
}
func (r *CommandSide) ChangeOrgIAMPolicy(ctx context.Context, resourceOwner string, policy *domain.OrgIAMPolicy) (*domain.OrgIAMPolicy, error) {
@ -49,19 +47,20 @@ func (r *CommandSide) ChangeOrgIAMPolicy(ctx context.Context, resourceOwner stri
return nil, caos_errs.ThrowNotFound(nil, "ORG-2N9sd", "Errors.Org.OrgIAMPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.UserLoginMustBeDomain)
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PolicyOrgIAMWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.UserLoginMustBeDomain)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "ORG-3M9ds", "Errors.Org.LabelPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PolicyOrgIAMWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return orgWriteModelToOrgIAMPolicy(existingPolicy), nil
}
@ -75,9 +74,8 @@ func (r *CommandSide) RemoveOrgIAMPolicy(ctx context.Context, orgID string) erro
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PolicyOrgIAMWriteModel.WriteModel)
orgAgg.PushEvents(org.NewOrgIAMPolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewOrgIAMPolicyRemovedEvent(ctx, orgAgg))
return err
}
func (r *CommandSide) getOrgIAMPolicy(ctx context.Context, orgID string) (*domain.OrgIAMPolicy, error) {

@ -30,6 +30,8 @@ func (wm *ORGOrgIAMPolicyWriteModel) AppendEvents(events ...eventstore.EventRead
wm.PolicyOrgIAMWriteModel.AppendEvents(&e.OrgIAMPolicyAddedEvent)
case *org.OrgIAMPolicyChangedEvent:
wm.PolicyOrgIAMWriteModel.AppendEvents(&e.OrgIAMPolicyChangedEvent)
case *org.OrgIAMPolicyRemovedEvent:
wm.PolicyOrgIAMWriteModel.AppendEvents(&e.OrgIAMPolicyRemovedEvent)
}
}
}
@ -41,10 +43,16 @@ func (wm *ORGOrgIAMPolicyWriteModel) Reduce() error {
func (wm *ORGOrgIAMPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.PolicyOrgIAMWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(org.OrgIAMPolicyAddedEventType,
org.OrgIAMPolicyChangedEventType,
org.OrgIAMPolicyRemovedEventType)
}
func (wm *ORGOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLoginMustBeDomain bool) (*org.OrgIAMPolicyChangedEvent, bool) {
func (wm *ORGOrgIAMPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
userLoginMustBeDomain bool) (*org.OrgIAMPolicyChangedEvent, bool) {
changes := make([]policy.OrgIAMPolicyChanges, 0)
if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
changes = append(changes, policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain))
@ -52,7 +60,7 @@ func (wm *ORGOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLo
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewOrgIAMPolicyChangedEvent(ctx, changes)
changedEvent, err := org.NewOrgIAMPolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -19,13 +19,14 @@ func (r *CommandSide) AddPasswordAgePolicy(ctx context.Context, resourceOwner st
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordAgePolicyAddedEvent(ctx, policy.ExpireWarnDays, policy.MaxAgeDays))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, org.NewPasswordAgePolicyAddedEvent(ctx, orgAgg, policy.ExpireWarnDays, policy.MaxAgeDays))
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPasswordAgePolicy(&addedPolicy.PasswordAgePolicyWriteModel), nil
}
@ -39,19 +40,20 @@ func (r *CommandSide) ChangePasswordAgePolicy(ctx context.Context, resourceOwner
return nil, caos_errs.ThrowNotFound(nil, "ORG-0oPew", "Errors.Org.PasswordAgePolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.ExpireWarnDays, policy.MaxAgeDays)
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PasswordAgePolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.ExpireWarnDays, policy.MaxAgeDays)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-dsgjR", "Errors.ORg.LabelPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PasswordAgePolicyWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPasswordAgePolicy(&existingPolicy.PasswordAgePolicyWriteModel), nil
}
@ -65,6 +67,6 @@ func (r *CommandSide) RemovePasswordAgePolicy(ctx context.Context, orgID string)
return caos_errs.ThrowNotFound(nil, "ORG-Dgs1g", "Errors.Org.PasswordAgePolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordAgePolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewPasswordAgePolicyRemovedEvent(ctx, orgAgg))
return err
}

@ -43,10 +43,18 @@ func (wm *OrgPasswordAgePolicyWriteModel) Reduce() error {
func (wm *OrgPasswordAgePolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.PasswordAgePolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(
org.PasswordAgePolicyAddedEventType,
org.PasswordAgePolicyChangedEventType,
org.PasswordAgePolicyRemovedEventType)
}
func (wm *OrgPasswordAgePolicyWriteModel) NewChangedEvent(ctx context.Context, expireWarnDays, maxAgeDays uint64) (*org.PasswordAgePolicyChangedEvent, bool) {
func (wm *OrgPasswordAgePolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
expireWarnDays,
maxAgeDays uint64) (*org.PasswordAgePolicyChangedEvent, bool) {
changes := make([]policy.PasswordAgePolicyChanges, 0)
if wm.ExpireWarnDays != expireWarnDays {
changes = append(changes, policy.ChangeExpireWarnDays(expireWarnDays))
@ -57,7 +65,7 @@ func (wm *OrgPasswordAgePolicyWriteModel) NewChangedEvent(ctx context.Context, e
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewPasswordAgePolicyChangedEvent(ctx, changes)
changedEvent, err := org.NewPasswordAgePolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -34,13 +34,23 @@ func (r *CommandSide) AddPasswordComplexityPolicy(ctx context.Context, resourceO
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordComplexityPolicyAddedEvent(ctx, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(
ctx,
org.NewPasswordComplexityPolicyAddedEvent(
ctx,
orgAgg,
policy.MinLength,
policy.HasLowercase,
policy.HasUppercase,
policy.HasNumber,
policy.HasSymbol))
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPasswordComplexityPolicy(&addedPolicy.PasswordComplexityPolicyWriteModel), nil
}
@ -58,18 +68,20 @@ func (r *CommandSide) ChangePasswordComplexityPolicy(ctx context.Context, resour
return nil, caos_errs.ThrowNotFound(nil, "ORG-Dgs3g", "Errors.Org.PasswordComplexityPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol)
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PasswordComplexityPolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-DAs21", "Errors.Org.PasswordComplexityPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PasswordComplexityPolicyWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPasswordComplexityPolicy(&existingPolicy.PasswordComplexityPolicyWriteModel), nil
}
@ -83,6 +95,6 @@ func (r *CommandSide) RemovePasswordComplexityPolicy(ctx context.Context, orgID
return caos_errs.ThrowNotFound(nil, "ORG-ADgs2", "Errors.Org.PasswordComplexityPolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordComplexityPolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewPasswordComplexityPolicyRemovedEvent(ctx, orgAgg))
return err
}

@ -43,11 +43,15 @@ func (wm *OrgPasswordComplexityPolicyWriteModel) Reduce() error {
func (wm *OrgPasswordComplexityPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.PasswordComplexityPolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(org.PasswordComplexityPolicyAddedEventType,
org.PasswordComplexityPolicyChangedEventType,
org.PasswordComplexityPolicyRemovedEventType)
}
func (wm *OrgPasswordComplexityPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
minLength uint64,
hasLowercase,
hasUppercase,
@ -74,7 +78,7 @@ func (wm *OrgPasswordComplexityPolicyWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewPasswordComplexityPolicyChangedEvent(ctx, changes)
changedEvent, err := org.NewPasswordComplexityPolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -2,7 +2,6 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
@ -19,13 +18,14 @@ func (r *CommandSide) AddPasswordLockoutPolicy(ctx context.Context, resourceOwne
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordLockoutPolicyAddedEvent(ctx, policy.MaxAttempts, policy.ShowLockOutFailures))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, org.NewPasswordLockoutPolicyAddedEvent(ctx, orgAgg, policy.MaxAttempts, policy.ShowLockOutFailures))
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPasswordLockoutPolicy(&addedPolicy.PasswordLockoutPolicyWriteModel), nil
}
@ -39,19 +39,20 @@ func (r *CommandSide) ChangePasswordLockoutPolicy(ctx context.Context, resourceO
return nil, caos_errs.ThrowNotFound(nil, "ORG-ADfs1", "Errors.Org.PasswordLockoutPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.MaxAttempts, policy.ShowLockOutFailures)
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PasswordLockoutPolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.MaxAttempts, policy.ShowLockOutFailures)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "ORG-4M9vs", "Errors.Org.PasswordLockoutPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PasswordLockoutPolicyWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPasswordLockoutPolicy(&existingPolicy.PasswordLockoutPolicyWriteModel), nil
}
@ -65,6 +66,7 @@ func (r *CommandSide) RemovePasswordLockoutPolicy(ctx context.Context, orgID str
return caos_errs.ThrowNotFound(nil, "ORG-D4zuz", "Errors.Org.PasswordLockoutPolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordLockoutPolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
_, err = r.eventstore.PushEvents(ctx, org.NewPasswordLockoutPolicyRemovedEvent(ctx, orgAgg))
return err
}

@ -30,8 +30,8 @@ func (wm *OrgPasswordLockoutPolicyWriteModel) AppendEvents(events ...eventstore.
wm.PasswordLockoutPolicyWriteModel.AppendEvents(&e.PasswordLockoutPolicyAddedEvent)
case *org.PasswordLockoutPolicyChangedEvent:
wm.PasswordLockoutPolicyWriteModel.AppendEvents(&e.PasswordLockoutPolicyChangedEvent)
case *org.PasswordComplexityPolicyRemovedEvent:
wm.PasswordLockoutPolicyWriteModel.AppendEvents(&e.PasswordComplexityPolicyRemovedEvent)
case *org.PasswordLockoutPolicyRemovedEvent:
wm.PasswordLockoutPolicyWriteModel.AppendEvents(&e.PasswordLockoutPolicyRemovedEvent)
}
}
}
@ -43,10 +43,17 @@ func (wm *OrgPasswordLockoutPolicyWriteModel) Reduce() error {
func (wm *OrgPasswordLockoutPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.PasswordLockoutPolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(org.PasswordLockoutPolicyAddedEventType,
org.PasswordLockoutPolicyChangedEventType,
org.PasswordLockoutPolicyRemovedEventType)
}
func (wm *OrgPasswordLockoutPolicyWriteModel) NewChangedEvent(ctx context.Context, maxAttempts uint64, showLockoutFailure bool) (*org.PasswordLockoutPolicyChangedEvent, bool) {
func (wm *OrgPasswordLockoutPolicyWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
maxAttempts uint64,
showLockoutFailure bool) (*org.PasswordLockoutPolicyChangedEvent, bool) {
changes := make([]policy.PasswordLockoutPolicyChanges, 0)
if wm.MaxAttempts != maxAttempts {
changes = append(changes, policy.ChangeMaxAttempts(maxAttempts))
@ -57,7 +64,7 @@ func (wm *OrgPasswordLockoutPolicyWriteModel) NewChangedEvent(ctx context.Contex
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewPasswordLockoutPolicyChangedEvent(ctx, changes)
changedEvent, err := org.NewPasswordLockoutPolicyChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false
}

@ -3,27 +3,29 @@ package command
import (
"context"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/eventstore/v2"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/project"
)
func (r *CommandSide) AddProject(ctx context.Context, project *domain.Project, resourceOwner, ownerUserID string) (_ *domain.Project, err error) {
projectAgg, addedProject, err := r.addProject(ctx, project, resourceOwner, ownerUserID)
events, addedProject, err := r.addProject(ctx, project, resourceOwner, ownerUserID)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedProject, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedProject, pushedEvents...)
if err != nil {
return nil, err
}
return projectWriteModelToProject(addedProject), nil
}
func (r *CommandSide) addProject(ctx context.Context, projectAdd *domain.Project, resourceOwner, ownerUserID string) (_ *project.Aggregate, _ *ProjectWriteModel, err error) {
func (r *CommandSide) addProject(ctx context.Context, projectAdd *domain.Project, resourceOwner, ownerUserID string) (_ []eventstore.EventPusher, _ *ProjectWriteModel, err error) {
if !projectAdd.IsValid() {
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
}
@ -42,11 +44,11 @@ func (r *CommandSide) addProject(ctx context.Context, projectAdd *domain.Project
if iam.GlobalOrgID == resourceOwner {
projectRole = domain.RoleProjectOwnerGlobal
}
projectAgg.PushEvents(
project.NewProjectAddedEvent(ctx, projectAdd.Name, resourceOwner),
project.NewProjectMemberAddedEvent(ctx, ownerUserID, projectRole),
)
return projectAgg, addedProject, nil
events := []eventstore.EventPusher{
project.NewProjectAddedEvent(ctx, projectAgg, projectAdd.Name),
project.NewProjectMemberAddedEvent(ctx, projectAgg, ownerUserID, projectRole),
}
return events, addedProject, nil
}
func (r *CommandSide) getProjectByID(ctx context.Context, projectID, resourceOwner string) (*domain.Project, error) {
@ -84,21 +86,22 @@ func (r *CommandSide) ChangeProject(ctx context.Context, projectChange *domain.P
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
}
changedEvent, hasChanged, err := existingProject.NewChangedEvent(ctx, existingProject.ResourceOwner, projectChange.Name, projectChange.ProjectRoleAssertion, projectChange.ProjectRoleCheck)
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
changedEvent, hasChanged, err := existingProject.NewChangedEvent(ctx, projectAgg, projectChange.Name, projectChange.ProjectRoleAssertion, projectChange.ProjectRoleCheck)
if err != nil {
return nil, err
}
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M0fs", "Errors.NoChangesFound")
}
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
projectAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingProject, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingProject, pushedEvents...)
if err != nil {
return nil, err
}
return projectWriteModelToProject(existingProject), nil
}
@ -119,9 +122,8 @@ func (r *CommandSide) DeactivateProject(ctx context.Context, projectID string, r
}
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
projectAgg.PushEvents(project.NewProjectDeactivatedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingProject, projectAgg)
_, err = r.eventstore.PushEvents(ctx, project.NewProjectDeactivatedEvent(ctx, projectAgg))
return err
}
func (r *CommandSide) ReactivateProject(ctx context.Context, projectID string, resourceOwner string) error {
@ -141,9 +143,8 @@ func (r *CommandSide) ReactivateProject(ctx context.Context, projectID string, r
}
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
projectAgg.PushEvents(project.NewProjectReactivatedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingProject, projectAgg)
_, err = r.eventstore.PushEvents(ctx, project.NewProjectReactivatedEvent(ctx, projectAgg))
return err
}
func (r *CommandSide) RemoveProject(ctx context.Context, projectID, resourceOwner string, cascadingUserGrantIDs ...string) error {
@ -158,22 +159,21 @@ func (r *CommandSide) RemoveProject(ctx context.Context, projectID, resourceOwne
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved {
return caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
}
aggregates := make([]eventstore.Aggregater, 0)
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
projectAgg.PushEvents(project.NewProjectRemovedEvent(ctx, existingProject.Name, existingProject.ResourceOwner))
aggregates = append(aggregates, projectAgg)
events := []eventstore.EventPusher{
project.NewProjectRemovedEvent(ctx, projectAgg, existingProject.Name),
}
for _, grantID := range cascadingUserGrantIDs {
grantAgg, _, err := r.removeUserGrant(ctx, grantID, "", true)
event, err := r.removeUserGrant(ctx, grantID, "", true)
if err != nil {
logging.LogWithFields("COMMAND-b8Djf", "usergrantid", grantID).WithError(err).Warn("could not cascade remove user grant")
continue
}
aggregates = append(aggregates, grantAgg)
events = append(events, event)
}
_, err = r.eventstore.PushAggregates(ctx, aggregates...)
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}

@ -2,7 +2,6 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/project"
@ -24,15 +23,16 @@ func (r *CommandSide) ChangeApplication(ctx context.Context, projectID string, a
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2m8vx", "Errors.NoChangesFound")
}
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
projectAgg.PushEvents(
project.NewApplicationChangedEvent(ctx, appChange.GetAppID(), existingApp.Name, appChange.GetApplicationName(), projectID),
)
err = r.eventstore.PushAggregate(ctx, existingApp, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(
ctx,
project.NewApplicationChangedEvent(ctx, projectAgg, appChange.GetAppID(), existingApp.Name, appChange.GetApplicationName(), projectID))
if err != nil {
return nil, err
}
err = AppendAndReduce(existingApp, pushedEvents...)
if err != nil {
return nil, err
}
return applicationWriteModelToApplication(existingApp), nil
}
@ -52,9 +52,8 @@ func (r *CommandSide) DeactivateApplication(ctx context.Context, projectID, appI
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-dsh35", "Errors.Project.App.NotActive")
}
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
projectAgg.PushEvents(project.NewApplicationDeactivatedEvent(ctx, appID))
return r.eventstore.PushAggregate(ctx, existingApp, projectAgg)
_, err = r.eventstore.PushEvents(ctx, project.NewApplicationDeactivatedEvent(ctx, projectAgg, appID))
return err
}
func (r *CommandSide) ReactivateApplication(ctx context.Context, projectID, appID, resourceOwner string) error {
@ -73,9 +72,9 @@ func (r *CommandSide) ReactivateApplication(ctx context.Context, projectID, appI
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-1n8cM", "Errors.Project.App.NotInactive")
}
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
projectAgg.PushEvents(project.NewApplicationReactivatedEvent(ctx, appID))
return r.eventstore.PushAggregate(ctx, existingApp, projectAgg)
_, err = r.eventstore.PushEvents(ctx, project.NewApplicationReactivatedEvent(ctx, projectAgg, appID))
return err
}
func (r *CommandSide) RemoveApplication(ctx context.Context, projectID, appID, resourceOwner string) error {
@ -91,9 +90,9 @@ func (r *CommandSide) RemoveApplication(ctx context.Context, projectID, appID, r
return caos_errs.ThrowNotFound(nil, "COMMAND-0po9s", "Errors.Project.App.NotExisting")
}
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
projectAgg.PushEvents(project.NewApplicationRemovedEvent(ctx, appID, existingApp.Name, projectID))
return r.eventstore.PushAggregate(ctx, existingApp, projectAgg)
_, err = r.eventstore.PushEvents(ctx, project.NewApplicationRemovedEvent(ctx, projectAgg, appID, existingApp.Name, projectID))
return err
}
func (r *CommandSide) getApplicationWriteModel(ctx context.Context, projectID, appID, resourceOwner string) (*ApplicationWriteModel, error) {

@ -96,13 +96,13 @@ func (wm *ApplicationWriteModel) Reduce() error {
func (wm *ApplicationWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
//EventTypes(
// project.ApplicationAddedType,
// project.ApplicationChangedType,
// project.ApplicationDeactivatedType,
// project.ApplicationReactivatedType,
// project.ApplicationRemovedType,
// project.ProjectRemovedType,
//)
ResourceOwner(wm.ResourceOwner).
EventTypes(
project.ApplicationAddedType,
project.ApplicationChangedType,
project.ApplicationDeactivatedType,
project.ApplicationReactivatedType,
project.ApplicationRemovedType,
project.ProjectRemovedType,
)
}

@ -3,6 +3,7 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/project"
)
@ -14,43 +15,49 @@ func (r *CommandSide) AddOIDCApplication(ctx context.Context, application *domai
}
addedApplication := NewOIDCApplicationWriteModel(application.AggregateID, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel)
stringPw, err := r.addOIDCApplication(ctx, projectAgg, project, application, resourceOwner)
events, stringPw, err := r.addOIDCApplication(ctx, projectAgg, project, application, resourceOwner)
if err != nil {
return nil, err
}
addedApplication.AppID = application.AppID
err = r.eventstore.PushAggregate(ctx, addedApplication, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedApplication, pushedEvents...)
if err != nil {
return nil, err
}
result := oidcWriteModelToOIDCConfig(addedApplication)
result.ClientSecretString = stringPw
result.FillCompliance()
return result, nil
}
func (r *CommandSide) addOIDCApplication(ctx context.Context, projectAgg *project.Aggregate, proj *domain.Project, oidcApp *domain.OIDCApp, resourceOwner string) (stringPW string, err error) {
func (r *CommandSide) addOIDCApplication(ctx context.Context, projectAgg *eventstore.Aggregate, proj *domain.Project, oidcApp *domain.OIDCApp, resourceOwner string) (events []eventstore.EventPusher, stringPW string, err error) {
if !oidcApp.IsValid() {
return "", caos_errs.ThrowPreconditionFailed(nil, "PROJECT-Bff2g", "Errors.Application.Invalid")
return nil, "", caos_errs.ThrowPreconditionFailed(nil, "PROJECT-Bff2g", "Errors.Application.Invalid")
}
oidcApp.AppID, err = r.idGenerator.Next()
if err != nil {
return "", err
return nil, "", err
}
projectAgg.PushEvents(project.NewApplicationAddedEvent(ctx, oidcApp.AppID, oidcApp.AppName, resourceOwner))
events = []eventstore.EventPusher{
project.NewApplicationAddedEvent(ctx, projectAgg, oidcApp.AppID, oidcApp.AppName, resourceOwner),
}
var stringPw string
err = oidcApp.GenerateNewClientID(r.idGenerator, proj)
if err != nil {
return "", err
return nil, "", err
}
stringPw, err = oidcApp.GenerateClientSecretIfNeeded(r.applicationSecretGenerator)
if err != nil {
return "", err
return nil, "", err
}
projectAgg.PushEvents(project.NewOIDCConfigAddedEvent(ctx,
events = append(events, project.NewOIDCConfigAddedEvent(ctx,
projectAgg,
oidcApp.OIDCVersion,
oidcApp.AppID,
oidcApp.ClientID,
@ -68,7 +75,7 @@ func (r *CommandSide) addOIDCApplication(ctx context.Context, projectAgg *projec
oidcApp.IDTokenUserinfoAssertion,
oidcApp.ClockSkew))
return stringPw, nil
return events, stringPw, nil
}
func (r *CommandSide) ChangeOIDCApplication(ctx context.Context, oidc *domain.OIDCApp, resourceOwner string) (*domain.OIDCApp, error) {
@ -83,8 +90,10 @@ func (r *CommandSide) ChangeOIDCApplication(ctx context.Context, oidc *domain.OI
if existingOIDC.State == domain.AppStateUnspecified || existingOIDC.State == domain.AppStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-2n8uU", "Errors.Project.App.NotExisting")
}
projectAgg := ProjectAggregateFromWriteModel(&existingOIDC.WriteModel)
changedEvent, hasChanged, err := existingOIDC.NewChangedEvent(
ctx,
projectAgg,
oidc.AppID,
oidc.ClientID,
oidc.RedirectUris,
@ -106,13 +115,16 @@ func (r *CommandSide) ChangeOIDCApplication(ctx context.Context, oidc *domain.OI
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-1m88i", "Errors.NoChangesFound")
}
projectAgg := ProjectAggregateFromWriteModel(&existingOIDC.WriteModel)
projectAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingOIDC, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingOIDC, pushedEvents...)
if err != nil {
return nil, err
}
result := oidcWriteModelToOIDCConfig(existingOIDC)
result.FillCompliance()
return result, nil
@ -136,9 +148,12 @@ func (r *CommandSide) ChangeOIDCApplicationSecret(ctx context.Context, projectID
}
projectAgg := ProjectAggregateFromWriteModel(&existingOIDC.WriteModel)
projectAgg.PushEvents(project.NewOIDCConfigSecretChangedEvent(ctx, appID, cryptoSecret))
err = r.eventstore.PushAggregate(ctx, existingOIDC, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, project.NewOIDCConfigSecretChangedEvent(ctx, projectAgg, appID, cryptoSecret))
if err != nil {
return nil, err
}
err = AppendAndReduce(existingOIDC, pushedEvents...)
if err != nil {
return nil, err
}

@ -201,22 +201,23 @@ func (wm *OIDCApplicationWriteModel) appendChangeOIDCEvent(e *project.OIDCConfig
func (wm *OIDCApplicationWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
//EventTypes(
// project.ApplicationAddedType,
// project.ApplicationChangedType,
// project.ApplicationDeactivatedType,
// project.ApplicationReactivatedType,
// project.ApplicationRemovedType,
// project.OIDCConfigAddedType,
// project.OIDCConfigChangedType,
// project.OIDCConfigSecretChangedType,
// project.ProjectRemovedType,
//)
ResourceOwner(wm.ResourceOwner).
EventTypes(
project.ApplicationAddedType,
project.ApplicationChangedType,
project.ApplicationDeactivatedType,
project.ApplicationReactivatedType,
project.ApplicationRemovedType,
project.OIDCConfigAddedType,
project.OIDCConfigChangedType,
project.OIDCConfigSecretChangedType,
project.ProjectRemovedType,
)
}
func (wm *OIDCApplicationWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
appID,
clientID string,
redirectURIS,
@ -281,7 +282,7 @@ func (wm *OIDCApplicationWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false, nil
}
changeEvent, err := project.NewOIDCConfigChangedEvent(ctx, appID, changes)
changeEvent, err := project.NewOIDCConfigChangedEvent(ctx, aggregate, appID, changes)
if err != nil {
return nil, false, err
}

@ -29,17 +29,16 @@ func (r *CommandSide) AddProjectGrant(ctx context.Context, grant *domain.Project
}
addedGrant := NewProjectGrantWriteModel(grant.GrantID, grant.AggregateID, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&addedGrant.WriteModel)
projectAgg.PushEvents(project.NewGrantAddedEvent(ctx, grant.GrantID, grant.GrantedOrgID, grant.AggregateID, grant.RoleKeys))
pushedEvents, err := r.eventstore.PushEvents(
ctx,
project.NewGrantAddedEvent(ctx, projectAgg, grant.GrantID, grant.GrantedOrgID, grant.AggregateID, grant.RoleKeys))
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedGrant, projectAgg)
err = AppendAndReduce(addedGrant, pushedEvents...)
if err != nil {
return nil, err
}
return projectGrantWriteModelToProjectGrant(addedGrant), nil
}
@ -61,45 +60,48 @@ func (r *CommandSide) ChangeProjectGrant(ctx context.Context, grant *domain.Proj
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-0o0pL", "Errors.NoChangesFoundc")
}
projectAgg.PushEvents(project.NewGrantChangedEvent(ctx, grant.GrantID, grant.RoleKeys))
events := []eventstore.EventPusher{
project.NewGrantChangedEvent(ctx, projectAgg, grant.GrantID, grant.RoleKeys),
}
removedRoles := domain.GetRemovedRoles(existingGrant.RoleKeys, grant.RoleKeys)
if len(removedRoles) == 0 {
err = r.eventstore.PushAggregate(ctx, existingGrant, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingGrant, pushedEvents...)
if err != nil {
return nil, err
}
return projectGrantWriteModelToProjectGrant(existingGrant), nil
}
aggregates := make([]eventstore.Aggregater, 0)
aggregates = append(aggregates, projectAgg)
for _, userGrantID := range cascadeUserGrantIDs {
grantAgg, _, err := r.removeRoleFromUserGrant(ctx, userGrantID, removedRoles, true)
event, err := r.removeRoleFromUserGrant(ctx, userGrantID, removedRoles, true)
if err != nil {
continue
}
aggregates = append(aggregates, grantAgg)
events = append(events, event)
}
resultEvents, err := r.eventstore.PushAggregates(ctx, aggregates...)
pushedEvents, err := r.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
existingGrant.AppendEvents(resultEvents...)
err = existingGrant.Reduce()
err = AppendAndReduce(existingGrant, pushedEvents...)
if err != nil {
return nil, err
}
return projectGrantWriteModelToProjectGrant(existingGrant), nil
}
func (r *CommandSide) removeRoleFromProjectGrant(ctx context.Context, projectAgg *project.Aggregate, projectID, projectGrantID, roleKey string, cascade bool) (_ *ProjectGrantWriteModel, err error) {
func (r *CommandSide) removeRoleFromProjectGrant(ctx context.Context, projectAgg *eventstore.Aggregate, projectID, projectGrantID, roleKey string, cascade bool) (_ eventstore.EventPusher, _ *ProjectGrantWriteModel, err error) {
existingProjectGrant, err := r.projectGrantWriteModelByID(ctx, projectID, projectGrantID, "")
if err != nil {
return nil, err
return nil, nil, err
}
if existingProjectGrant.State == domain.ProjectGrantStateUnspecified || existingProjectGrant.State == domain.ProjectGrantStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.Grant.NotFound")
return nil, nil, caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.Grant.NotFound")
}
keyExists := false
for i, key := range existingProjectGrant.RoleKeys {
@ -112,21 +114,15 @@ func (r *CommandSide) removeRoleFromProjectGrant(ctx context.Context, projectAgg
}
}
if !keyExists {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5m8g9", "Errors.Project.Grant.RoleKeyNotFound")
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5m8g9", "Errors.Project.Grant.RoleKeyNotFound")
}
changedProjectGrant := NewProjectGrantWriteModel(projectGrantID, projectID, existingProjectGrant.ResourceOwner)
if !cascade {
projectAgg.PushEvents(
project.NewGrantChangedEvent(ctx, projectGrantID, existingProjectGrant.RoleKeys),
)
} else {
projectAgg.PushEvents(
project.NewGrantCascadeChangedEvent(ctx, projectGrantID, existingProjectGrant.RoleKeys),
)
if cascade {
return project.NewGrantCascadeChangedEvent(ctx, projectAgg, projectGrantID, existingProjectGrant.RoleKeys), changedProjectGrant, nil
}
return changedProjectGrant, nil
return project.NewGrantChangedEvent(ctx, projectAgg, projectGrantID, existingProjectGrant.RoleKeys), changedProjectGrant, nil
}
func (r *CommandSide) DeactivateProjectGrant(ctx context.Context, projectID, grantID, resourceOwner string) (err error) {
@ -146,8 +142,8 @@ func (r *CommandSide) DeactivateProjectGrant(ctx context.Context, projectID, gra
}
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
projectAgg.PushEvents(project.NewGrantDeactivateEvent(ctx, grantID))
return r.eventstore.PushAggregate(ctx, existingGrant, projectAgg)
_, err = r.eventstore.PushEvents(ctx, project.NewGrantDeactivateEvent(ctx, projectAgg, grantID))
return err
}
func (r *CommandSide) ReactivateProjectGrant(ctx context.Context, projectID, grantID, resourceOwner string) (err error) {
@ -166,8 +162,8 @@ func (r *CommandSide) ReactivateProjectGrant(ctx context.Context, projectID, gra
return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-47fu8", "Errors.Project.Grant.NotInactive")
}
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
projectAgg.PushEvents(project.NewGrantReactivatedEvent(ctx, grantID))
return r.eventstore.PushAggregate(ctx, existingGrant, projectAgg)
_, err = r.eventstore.PushEvents(ctx, project.NewGrantReactivatedEvent(ctx, projectAgg, grantID))
return err
}
func (r *CommandSide) RemoveProjectGrant(ctx context.Context, projectID, grantID, resourceOwner string, cascadeUserGrantIDs ...string) (err error) {
@ -182,20 +178,19 @@ func (r *CommandSide) RemoveProjectGrant(ctx context.Context, projectID, grantID
if err != nil {
return err
}
aggregates := make([]eventstore.Aggregater, 0)
events := make([]eventstore.EventPusher, 0)
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
projectAgg.PushEvents(project.NewGrantRemovedEvent(ctx, grantID, existingGrant.GrantedOrgID, projectID))
aggregates = append(aggregates, projectAgg)
events = append(events, project.NewGrantRemovedEvent(ctx, projectAgg, grantID, existingGrant.GrantedOrgID, projectID))
for _, userGrantID := range cascadeUserGrantIDs {
grantAgg, _, err := r.removeUserGrant(ctx, userGrantID, "", true)
event, err := r.removeUserGrant(ctx, userGrantID, "", true)
if err != nil {
logging.LogWithFields("COMMAND-3m8sG", "usergrantid", grantID).WithError(err).Warn("could not cascade remove user grant")
continue
}
aggregates = append(aggregates, grantAgg)
events = append(events, event)
}
_, err = r.eventstore.PushAggregates(ctx, aggregates...)
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}

@ -28,9 +28,13 @@ func (r *CommandSide) AddProjectGrantMember(ctx context.Context, member *domain.
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-16dVN", "Errors.Project.Member.AlreadyExists")
}
projectAgg := ProjectAggregateFromWriteModel(&addedMember.WriteModel)
projectAgg.PushEvents(project.NewProjectGrantMemberAddedEvent(ctx, member.AggregateID, member.UserID, member.GrantID, member.Roles...))
err = r.eventstore.PushAggregate(ctx, addedMember, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(
ctx,
project.NewProjectGrantMemberAddedEvent(ctx, projectAgg, member.AggregateID, member.UserID, member.GrantID, member.Roles...))
if err != nil {
return nil, err
}
err = AppendAndReduce(addedMember, pushedEvents...)
if err != nil {
return nil, err
}
@ -55,15 +59,14 @@ func (r *CommandSide) ChangeProjectGrantMember(ctx context.Context, member *doma
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-2n8vx", "Errors.Project.Member.RolesNotChanged")
}
projectAgg := ProjectAggregateFromWriteModel(&existingMember.WriteModel)
projectAgg.PushEvents(project.NewProjectGrantMemberChangedEvent(ctx, member.UserID, member.GrantID, member.Roles...))
events, err := r.eventstore.PushAggregates(ctx, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(
ctx,
project.NewProjectGrantMemberChangedEvent(ctx, projectAgg, member.UserID, member.GrantID, member.Roles...))
if err != nil {
return nil, err
}
existingMember.AppendEvents(events...)
if err = existingMember.Reduce(); err != nil {
err = AppendAndReduce(existingMember, pushedEvents...)
if err != nil {
return nil, err
}
@ -77,9 +80,8 @@ func (r *CommandSide) RemoveProjectGrantMember(ctx context.Context, projectID, u
}
projectAgg := ProjectAggregateFromWriteModel(&m.WriteModel)
projectAgg.PushEvents(project.NewProjectGrantMemberRemovedEvent(ctx, projectID, userID, grantID))
return r.eventstore.PushAggregate(ctx, m, projectAgg)
_, err = r.eventstore.PushEvents(ctx, project.NewProjectGrantMemberRemovedEvent(ctx, projectAgg, projectID, userID, grantID))
return err
}
func (r *CommandSide) projectGrantMemberWriteModelByID(ctx context.Context, projectID, userID, grantID string) (member *ProjectGrantMemberWriteModel, err error) {

@ -49,6 +49,8 @@ func (wm *ProjectGrantMemberWriteModel) AppendEvents(events ...eventstore.EventR
continue
}
wm.WriteModel.AppendEvents(e)
case *project.ProjectRemovedEvent:
wm.WriteModel.AppendEvents(e)
}
}
}
@ -72,11 +74,11 @@ func (wm *ProjectGrantMemberWriteModel) Reduce() error {
func (wm *ProjectGrantMemberWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
AggregateIDs(wm.AggregateID)
//EventTypes(
// project.GrantMemberAddedType,
// project.GrantMemberChangedType,
// project.GrantMemberRemovedType,
// project.GrantRemovedType,
// project.ProjectRemovedType)
AggregateIDs(wm.AggregateID).
EventTypes(
project.GrantMemberAddedType,
project.GrantMemberChangedType,
project.GrantMemberRemovedType,
project.GrantRemovedType,
project.ProjectRemovedType)
}

@ -2,6 +2,7 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"reflect"
"github.com/caos/zitadel/internal/errors"
@ -14,12 +15,16 @@ import (
func (r *CommandSide) AddProjectMember(ctx context.Context, member *domain.Member, resourceOwner string) (*domain.Member, error) {
addedMember := NewProjectMemberWriteModel(member.AggregateID, member.UserID, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&addedMember.WriteModel)
err := r.addProjectMember(ctx, projectAgg, addedMember, member)
event, err := r.addProjectMember(ctx, projectAgg, addedMember, member)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedMember, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedMember, pushedEvents...)
if err != nil {
return nil, err
}
@ -27,28 +32,26 @@ func (r *CommandSide) AddProjectMember(ctx context.Context, member *domain.Membe
return memberWriteModelToMember(&addedMember.MemberWriteModel), nil
}
func (r *CommandSide) addProjectMember(ctx context.Context, projectAgg *project.Aggregate, addedMember *ProjectMemberWriteModel, member *domain.Member) error {
func (r *CommandSide) addProjectMember(ctx context.Context, projectAgg *eventstore.Aggregate, addedMember *ProjectMemberWriteModel, member *domain.Member) (eventstore.EventPusher, error) {
//TODO: check if roles valid
if !member.IsValid() {
return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-W8m4l", "Errors.Project.Member.Invalid")
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-W8m4l", "Errors.Project.Member.Invalid")
}
err := r.checkUserExists(ctx, addedMember.UserID, "")
if err != nil {
return err
return nil, err
}
err = r.eventstore.FilterToQueryReducer(ctx, addedMember)
if err != nil {
return err
return nil, err
}
if addedMember.State == domain.MemberStateActive {
return errors.ThrowAlreadyExists(nil, "PROJECT-PtXi1", "Errors.Project.Member.AlreadyExists")
return nil, errors.ThrowAlreadyExists(nil, "PROJECT-PtXi1", "Errors.Project.Member.AlreadyExists")
}
projectAgg.PushEvents(project.NewProjectMemberAddedEvent(ctx, projectAgg.ID(), member.UserID, member.Roles...))
return nil
return project.NewProjectMemberAddedEvent(ctx, projectAgg, member.UserID, member.Roles...), nil
}
//ChangeProjectMember updates an existing member
@ -68,15 +71,13 @@ func (r *CommandSide) ChangeProjectMember(ctx context.Context, member *domain.Me
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-LiaZi", "Errors.Project.Member.RolesNotChanged")
}
projectAgg := ProjectAggregateFromWriteModel(&existingMember.MemberWriteModel.WriteModel)
projectAgg.PushEvents(project.NewProjectMemberChangedEvent(ctx, member.UserID, member.Roles...))
events, err := r.eventstore.PushAggregates(ctx, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, project.NewProjectMemberChangedEvent(ctx, projectAgg, member.UserID, member.Roles...))
if err != nil {
return nil, err
}
existingMember.AppendEvents(events...)
if err = existingMember.Reduce(); err != nil {
err = AppendAndReduce(existingMember, pushedEvents...)
if err != nil {
return nil, err
}
@ -93,9 +94,8 @@ func (r *CommandSide) RemoveProjectMember(ctx context.Context, projectID, userID
}
projectAgg := ProjectAggregateFromWriteModel(&m.MemberWriteModel.WriteModel)
projectAgg.PushEvents(project.NewProjectMemberRemovedEvent(ctx, projectAgg.ID(), userID))
return r.eventstore.PushAggregate(ctx, m, projectAgg)
_, err = r.eventstore.PushEvents(ctx, project.NewProjectMemberRemovedEvent(ctx, projectAgg, userID))
return err
}
func (r *CommandSide) projectMemberWriteModelByID(ctx context.Context, projectID, userID, resourceOwner string) (member *ProjectMemberWriteModel, err error) {

@ -50,5 +50,8 @@ func (wm *ProjectMemberWriteModel) Reduce() error {
func (wm *ProjectMemberWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
AggregateIDs(wm.MemberWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(project.MemberAddedType,
project.MemberChangedType,
project.MemberRemovedType)
}

@ -25,10 +25,6 @@ func NewProjectWriteModel(projectID string, resourceOwner string) *ProjectWriteM
}
}
func (wm *ProjectWriteModel) AppendEvents(events ...eventstore.EventReader) {
wm.WriteModel.AppendEvents(events...)
}
func (wm *ProjectWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
@ -67,12 +63,17 @@ func (wm *ProjectWriteModel) Reduce() error {
func (wm *ProjectWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(project.ProjectAddedType,
project.ProjectChangedType,
project.ProjectDeactivatedType,
project.ProjectReactivatedType,
project.ProjectRemovedType)
}
func (wm *ProjectWriteModel) NewChangedEvent(
ctx context.Context,
resourceOwner,
aggregate *eventstore.Aggregate,
name string,
projectRoleAssertion,
projectRoleCheck bool,
@ -94,15 +95,13 @@ func (wm *ProjectWriteModel) NewChangedEvent(
if len(changes) == 0 {
return nil, false, nil
}
changeEvent, err := project.NewProjectChangeEvent(ctx, resourceOwner, oldName, changes)
changeEvent, err := project.NewProjectChangeEvent(ctx, aggregate, oldName, changes)
if err != nil {
return nil, false, err
}
return changeEvent, true, nil
}
func ProjectAggregateFromWriteModel(wm *eventstore.WriteModel) *project.Aggregate {
return &project.Aggregate{
Aggregate: *eventstore.AggregateFromWriteModel(wm, project.AggregateType, project.AggregateVersion),
}
func ProjectAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate {
return eventstore.AggregateFromWriteModel(wm, project.AggregateType, project.AggregateVersion)
}

@ -17,9 +17,15 @@ func (r *CommandSide) AddProjectRole(ctx context.Context, projectRole *domain.Pr
roleWriteModel := NewProjectRoleWriteModelWithKey(projectRole.Key, projectRole.AggregateID, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&roleWriteModel.WriteModel)
r.addProjectRoles(ctx, projectAgg, projectRole.AggregateID, resourceOwner, projectRole)
err = r.eventstore.PushAggregate(ctx, roleWriteModel, projectAgg)
events, err := r.addProjectRoles(ctx, projectAgg, projectRole.AggregateID, projectRole)
if err != nil {
return nil, err
}
pushedEvents, err := r.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
err = AppendAndReduce(roleWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
@ -34,28 +40,32 @@ func (r *CommandSide) BulkAddProjectRole(ctx context.Context, projectID, resourc
roleWriteModel := NewProjectRoleWriteModel(projectID, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&roleWriteModel.WriteModel)
r.addProjectRoles(ctx, projectAgg, projectID, resourceOwner, projectRoles...)
return r.eventstore.PushAggregate(ctx, roleWriteModel, projectAgg)
}
func (r *CommandSide) addProjectRoles(ctx context.Context, projectAgg *project.Aggregate, projectID, resourceOwner string, projectRoles ...*domain.ProjectRole) error {
for _, projectRole := range projectRoles {
if !projectRole.IsValid() {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
}
projectAgg.PushEvents(
project.NewRoleAddedEvent(
ctx,
projectRole.Key,
projectRole.DisplayName,
projectRole.Group,
projectID,
),
)
events, err := r.addProjectRoles(ctx, projectAgg, projectID, projectRoles...)
if err != nil {
return err
}
return nil
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}
func (r *CommandSide) addProjectRoles(ctx context.Context, projectAgg *eventstore.Aggregate, projectID string, projectRoles ...*domain.ProjectRole) ([]eventstore.EventPusher, error) {
var events []eventstore.EventPusher
for _, projectRole := range projectRoles {
if !projectRole.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
}
events = append(events, project.NewRoleAddedEvent(
ctx,
projectAgg,
projectRole.Key,
projectRole.DisplayName,
projectRole.Group,
projectID,
))
}
return events, nil
}
func (r *CommandSide) ChangeProjectRole(ctx context.Context, projectRole *domain.ProjectRole, resourceOwner string) (_ *domain.ProjectRole, err error) {
@ -77,16 +87,19 @@ func (r *CommandSide) ChangeProjectRole(ctx context.Context, projectRole *domain
projectAgg := ProjectAggregateFromWriteModel(&existingRole.WriteModel)
changeEvent, changed, err := existingRole.NewProjectRoleChangedEvent(ctx, projectRole.Key, projectRole.DisplayName, projectRole.Group)
changeEvent, changed, err := existingRole.NewProjectRoleChangedEvent(ctx, projectAgg, projectRole.Key, projectRole.DisplayName, projectRole.Group)
if err != nil {
return nil, err
}
if !changed {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5M0cs", "Errors.NoChangesFound")
}
projectAgg.PushEvents(changeEvent)
err = r.eventstore.PushAggregate(ctx, existingRole, projectAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changeEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingRole, pushedEvents...)
if err != nil {
return nil, err
}
@ -104,28 +117,30 @@ func (r *CommandSide) RemoveProjectRole(ctx context.Context, projectID, key, res
if existingRole.State == domain.ProjectRoleStateUnspecified || existingRole.State == domain.ProjectRoleStateRemoved {
return caos_errs.ThrowNotFound(nil, "COMMAND-m9vMf", "Errors.Project.Role.NotExisting")
}
aggregates := make([]eventstore.Aggregater, 0)
projectAgg := ProjectAggregateFromWriteModel(&existingRole.WriteModel)
projectAgg.PushEvents(project.NewRoleRemovedEvent(ctx, key, projectID))
events := []eventstore.EventPusher{
project.NewRoleRemovedEvent(ctx, projectAgg, key, projectID),
}
for _, projectGrantID := range cascadingProjectGrantIds {
_, err = r.removeRoleFromProjectGrant(ctx, projectAgg, projectID, projectGrantID, key, true)
event, _, err := r.removeRoleFromProjectGrant(ctx, projectAgg, projectID, projectGrantID, key, true)
if err != nil {
logging.LogWithFields("COMMAND-6n77g", "projectgrantid", projectGrantID).WithError(err).Warn("could not cascade remove role from project grant")
continue
}
events = append(events, event)
}
aggregates = append(aggregates, projectAgg)
for _, grantID := range cascadeUserGrantIDs {
grantAgg, _, err := r.removeRoleFromUserGrant(ctx, grantID, []string{key}, true)
event, err := r.removeRoleFromUserGrant(ctx, grantID, []string{key}, true)
if err != nil {
logging.LogWithFields("COMMAND-mK0of", "usergrantid", grantID).WithError(err).Warn("could not cascade remove role on user grant")
continue
}
aggregates = append(aggregates, grantAgg)
events = append(events, event)
}
_, err = r.eventstore.PushAggregates(ctx, aggregates...)
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}

@ -82,20 +82,19 @@ func (wm *ProjectRoleWriteModel) Reduce() error {
}
func (wm *ProjectRoleWriteModel) Query() *eventstore.SearchQueryBuilder {
//types := []eventstore.EventType{
// project.RoleAddedType,
// project.RoleChangedType,
// project.RoleRemovedType,
// project.ProjectRemovedType,
//}
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
//EventTypes(types...)
ResourceOwner(wm.ResourceOwner).
EventTypes(
project.RoleAddedType,
project.RoleChangedType,
project.RoleRemovedType,
project.ProjectRemovedType)
}
func (wm *ProjectRoleWriteModel) NewProjectRoleChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
key,
displayName,
group string,
@ -113,7 +112,7 @@ func (wm *ProjectRoleWriteModel) NewProjectRoleChangedEvent(
if len(changes) == 0 {
return nil, false, nil
}
changeEvent, err := project.NewRoleChangedEvent(ctx, changes)
changeEvent, err := project.NewRoleChangedEvent(ctx, aggregate, changes)
if err != nil {
return nil, false, err
}

@ -2,6 +2,7 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/logging"
@ -63,16 +64,20 @@ func (r *CommandSide) StartSetup(ctx context.Context, step domain.Step) (*domain
if iamWriteModel.SetUpStarted >= step || iamWriteModel.SetUpStarted != iamWriteModel.SetUpDone {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9so34", "setup error")
}
aggregate := IAMAggregateFromWriteModel(&iamWriteModel.WriteModel).PushEvents(iam_repo.NewSetupStepStartedEvent(ctx, step))
err = r.eventstore.PushAggregate(ctx, iamWriteModel, aggregate)
aggregate := IAMAggregateFromWriteModel(&iamWriteModel.WriteModel)
pushedEvents, err := r.eventstore.PushEvents(ctx, iam_repo.NewSetupStepStartedEvent(ctx, aggregate, step))
if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Grgh1", "Setup start failed")
}
err = AppendAndReduce(iamWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
logging.LogWithFields("SETUP-fhh21", "step", step).Info("setup step started")
return writeModelToIAM(iamWriteModel), nil
}
func (r *CommandSide) setup(ctx context.Context, step Step, iamAggregateProvider func(*IAMWriteModel) (*iam_repo.Aggregate, error)) error {
func (r *CommandSide) setup(ctx context.Context, step Step, iamAggregateProvider func(*IAMWriteModel) ([]eventstore.EventPusher, error)) error {
iam, err := r.getIAMWriteModel(ctx)
if err != nil && !caos_errs.IsNotFound(err) {
return err
@ -80,13 +85,14 @@ func (r *CommandSide) setup(ctx context.Context, step Step, iamAggregateProvider
if iam.SetUpStarted != step.Step() && iam.SetUpDone+1 != step.Step() {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-Dge32", "wrong step")
}
iamAgg, err := iamAggregateProvider(iam)
events, err := iamAggregateProvider(iam)
if err != nil {
return err
}
iamAgg.PushEvents(iam_repo.NewSetupStepDoneEvent(ctx, step.Step()))
iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel)
events = append(events, iam_repo.NewSetupStepDoneEvent(ctx, iamAgg, step.Step()))
_, err = r.eventstore.PushAggregates(ctx, iamAgg)
_, err = r.eventstore.PushEvents(ctx, events...)
if err != nil {
return caos_errs.ThrowPreconditionFailedf(nil, "EVENT-dbG31", "Setup %v failed", step.Step())
}

@ -2,6 +2,7 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/logging"
@ -10,7 +11,6 @@ import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/project"
)
const (
@ -84,10 +84,11 @@ type OIDCApp struct {
}
func (r *CommandSide) SetupStep1(ctx context.Context, step1 *Step1) error {
var events []eventstore.EventPusher
iamWriteModel := NewIAMWriteModel()
iamAgg := IAMAggregateFromWriteModel(&iamWriteModel.WriteModel)
//create default login policy
err := r.addDefaultLoginPolicy(ctx, iamAgg, NewIAMLoginPolicyWriteModel(),
loginPolicyEvent, err := r.addDefaultLoginPolicy(ctx, iamAgg, NewIAMLoginPolicyWriteModel(),
&domain.LoginPolicy{
AllowUsernamePassword: step1.DefaultLoginPolicy.AllowUsernamePassword,
AllowRegister: step1.DefaultLoginPolicy.AllowRegister,
@ -96,11 +97,11 @@ func (r *CommandSide) SetupStep1(ctx context.Context, step1 *Step1) error {
if err != nil {
return err
}
events = append(events, loginPolicyEvent)
logging.Log("SETUP-sd2hj").Info("default login policy set up")
//create orgs
aggregates := make([]eventstore.Aggregater, 0)
for _, organisation := range step1.Orgs {
orgAgg, userAgg, orgMemberAgg, claimedUsers, err := r.setUpOrg(ctx,
orgAgg, humanWriteModel, _, setUpOrgEvents, err := r.setUpOrg(ctx,
&domain.Org{
Name: organisation.Name,
Domains: []*domain.OrgDomain{{Domain: organisation.Domain}},
@ -122,66 +123,70 @@ func (r *CommandSide) SetupStep1(ctx context.Context, step1 *Step1) error {
if err != nil {
return err
}
logging.LogWithFields("SETUP-Gdsfg", "id", orgAgg.ID(), "name", organisation.Name).Info("org set up")
events = append(events, setUpOrgEvents...)
logging.LogWithFields("SETUP-Gdsfg", "id", orgAgg.ID, "name", organisation.Name).Info("org set up")
if organisation.OrgIamPolicy {
err = r.addOrgIAMPolicy(ctx, orgAgg, NewORGOrgIAMPolicyWriteModel(orgAgg.ID()), &domain.OrgIAMPolicy{UserLoginMustBeDomain: false})
orgIAMPolicyEvent, err := r.addOrgIAMPolicy(ctx, orgAgg, NewORGOrgIAMPolicyWriteModel(orgAgg.ID), &domain.OrgIAMPolicy{UserLoginMustBeDomain: false})
if err != nil {
return err
}
events = append(events, orgIAMPolicyEvent)
}
aggregates = append(aggregates, orgAgg, userAgg, orgMemberAgg)
aggregates = append(aggregates, claimedUsers...)
if organisation.Name == step1.GlobalOrg {
err = r.setGlobalOrg(ctx, iamAgg, iamWriteModel, orgAgg.ID())
globalOrgEvent, err := r.setGlobalOrg(ctx, iamAgg, iamWriteModel, orgAgg.ID)
if err != nil {
return err
}
events = append(events, globalOrgEvent)
logging.Log("SETUP-BDn52").Info("global org set")
}
//projects
for _, proj := range organisation.Projects {
project := &domain.Project{Name: proj.Name}
projectAgg, _, err := r.addProject(ctx, project, orgAgg.ID(), userAgg.ID())
projectEvents, projectWriteModel, err := r.addProject(ctx, project, orgAgg.ID, humanWriteModel.AggregateID)
if err != nil {
return err
}
events = append(events, projectEvents...)
if project.Name == step1.IAMProject {
err = r.setIAMProject(ctx, iamAgg, iamWriteModel, projectAgg.ID())
iamProjectEvent, err := r.setIAMProject(ctx, iamAgg, iamWriteModel, projectWriteModel.AggregateID)
if err != nil {
return err
}
events = append(events, iamProjectEvent)
logging.Log("SETUP-Bdfs1").Info("IAM project set")
err = r.addIAMMember(ctx, iamAgg, NewIAMMemberWriteModel(userAgg.ID()), domain.NewMember(iamAgg.ID(), userAgg.ID(), domain.RoleIAMOwner))
iamEvent, err := r.addIAMMember(ctx, iamAgg, NewIAMMemberWriteModel(humanWriteModel.AggregateID), domain.NewMember(iamAgg.ID, humanWriteModel.AggregateID, domain.RoleIAMOwner))
if err != nil {
return err
}
events = append(events, iamEvent)
logging.Log("SETUP-BSf2h").Info("IAM owner set")
}
//create applications
for _, app := range proj.OIDCApps {
err = setUpApplication(ctx, r, projectAgg, project, app, orgAgg.ID())
applicationEvents, err := setUpApplication(ctx, r, projectWriteModel, project, app, orgAgg.ID)
if err != nil {
return err
}
events = append(events, applicationEvents...)
}
aggregates = append(aggregates, projectAgg)
}
}
iamAgg.PushEvents(iam_repo.NewSetupStepDoneEvent(ctx, domain.Step1))
events = append(events, iam_repo.NewSetupStepDoneEvent(ctx, iamAgg, domain.Step1))
_, err = r.eventstore.PushAggregates(ctx, append(aggregates, iamAgg)...)
_, err = r.eventstore.PushEvents(ctx, events...)
if err != nil {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-Gr2hh", "Setup Step1 failed")
}
return nil
}
func setUpApplication(ctx context.Context, r *CommandSide, projectAgg *project.Aggregate, project *domain.Project, oidcApp OIDCApp, resourceOwner string) error {
func setUpApplication(ctx context.Context, r *CommandSide, projectWriteModel *ProjectWriteModel, project *domain.Project, oidcApp OIDCApp, resourceOwner string) ([]eventstore.EventPusher, error) {
app := &domain.OIDCApp{
ObjectRoot: models.ObjectRoot{
AggregateID: projectAgg.ID(),
AggregateID: projectWriteModel.AggregateID,
},
AppName: oidcApp.Name,
RedirectUris: oidcApp.RedirectUris,
@ -192,12 +197,13 @@ func setUpApplication(ctx context.Context, r *CommandSide, projectAgg *project.A
DevMode: oidcApp.DevMode,
}
_, err := r.addOIDCApplication(ctx, projectAgg, project, app, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&projectWriteModel.WriteModel)
events, _, err := r.addOIDCApplication(ctx, projectAgg, project, app, resourceOwner)
if err != nil {
return err
return nil, err
}
logging.LogWithFields("SETUP-Edgw4", "name", app.AppName, "clientID", app.ClientID).Info("application set up")
return nil
return events, nil
}
func getOIDCResponseTypes(responseTypes []string) []domain.OIDCResponseType {

@ -3,8 +3,8 @@ package command
import (
"context"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
type Step10 struct {
@ -21,20 +21,24 @@ func (s *Step10) execute(ctx context.Context, commandSide *CommandSide) error {
}
func (r *CommandSide) SetupStep10(ctx context.Context, step *Step10) error {
fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) {
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel)
err := r.addDefaultMailTemplate(ctx, iamAgg, NewIAMMailTemplateWriteModel(), &step.DefaultMailTemplate)
mailTemplateEvent, err := r.addDefaultMailTemplate(ctx, iamAgg, NewIAMMailTemplateWriteModel(), &step.DefaultMailTemplate)
if err != nil {
return nil, err
}
events := []eventstore.EventPusher{
mailTemplateEvent,
}
for _, text := range step.DefaultMailTexts {
r.addDefaultMailText(ctx, iamAgg, NewIAMMailTextWriteModel(text.MailTextType, text.Language), &text)
defaultTextEvent, err := r.addDefaultMailText(ctx, iamAgg, NewIAMMailTextWriteModel(text.MailTextType, text.Language), &text)
if err != nil {
return nil, err
}
events = append(events, defaultTextEvent)
}
logging.Log("SETUP-3N9fs").Info("default mail template/text set up")
return iamAgg, nil
return events, nil
}
return r.setup(ctx, step, fn)
}

@ -3,6 +3,7 @@ package command
import (
"context"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
@ -20,7 +21,7 @@ func (s *Step11) execute(ctx context.Context, commandSide *CommandSide) error {
}
func (r *CommandSide) SetupStep11(ctx context.Context, step *Step11) error {
fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) {
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel)
var uniqueContraintMigrations []*domain.UniqueConstraintMigration
if step.MigrateV1EventstoreToV2 {
@ -31,9 +32,8 @@ func (r *CommandSide) SetupStep11(ctx context.Context, step *Step11) error {
}
uniqueContraintMigrations = uniqueConstraints.UniqueConstraints
}
iamAgg.PushEvents(iam_repo.NewMigrateUniqueConstraintEvent(ctx, uniqueContraintMigrations))
logging.Log("SETUP-M9fsd").Info("migrate v1 eventstore to v2")
return iamAgg, nil
return []eventstore.EventPusher{iam_repo.NewMigrateUniqueConstraintEvent(ctx, iamAgg, uniqueContraintMigrations)}, nil
}
return r.setup(ctx, step, fn)
}

@ -2,12 +2,12 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/logging"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
type Step2 struct {
@ -23,9 +23,9 @@ func (s *Step2) execute(ctx context.Context, commandSide *CommandSide) error {
}
func (r *CommandSide) SetupStep2(ctx context.Context, step *Step2) error {
fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) {
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel)
err := r.addDefaultPasswordComplexityPolicy(ctx, iamAgg, NewIAMPasswordComplexityPolicyWriteModel(), &domain.PasswordComplexityPolicy{
event, err := r.addDefaultPasswordComplexityPolicy(ctx, iamAgg, NewIAMPasswordComplexityPolicyWriteModel(), &domain.PasswordComplexityPolicy{
MinLength: step.DefaultPasswordComplexityPolicy.MinLength,
HasLowercase: step.DefaultPasswordComplexityPolicy.HasLowercase,
HasUppercase: step.DefaultPasswordComplexityPolicy.HasUppercase,
@ -36,7 +36,7 @@ func (r *CommandSide) SetupStep2(ctx context.Context, step *Step2) error {
return nil, err
}
logging.Log("SETUP-ADgd2").Info("default password complexity policy set up")
return iamAgg, nil
return []eventstore.EventPusher{event}, nil
}
return r.setup(ctx, step, fn)
}

@ -2,12 +2,12 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/logging"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
type Step3 struct {
@ -23,9 +23,9 @@ func (s *Step3) execute(ctx context.Context, commandSide *CommandSide) error {
}
func (r *CommandSide) SetupStep3(ctx context.Context, step *Step3) error {
fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) {
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel)
err := r.addDefaultPasswordAgePolicy(ctx, iamAgg, NewIAMPasswordAgePolicyWriteModel(), &domain.PasswordAgePolicy{
event, err := r.addDefaultPasswordAgePolicy(ctx, iamAgg, NewIAMPasswordAgePolicyWriteModel(), &domain.PasswordAgePolicy{
MaxAgeDays: step.DefaultPasswordAgePolicy.MaxAgeDays,
ExpireWarnDays: step.DefaultPasswordAgePolicy.ExpireWarnDays,
})
@ -33,7 +33,7 @@ func (r *CommandSide) SetupStep3(ctx context.Context, step *Step3) error {
return nil, err
}
logging.Log("SETUP-DBqgq").Info("default password age policy set up")
return iamAgg, nil
return []eventstore.EventPusher{event}, nil
}
return r.setup(ctx, step, fn)
}

@ -2,12 +2,12 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/logging"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
type Step4 struct {
@ -23,9 +23,9 @@ func (s *Step4) execute(ctx context.Context, commandSide *CommandSide) error {
}
func (r *CommandSide) SetupStep4(ctx context.Context, step *Step4) error {
fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) {
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel)
err := r.addDefaultPasswordLockoutPolicy(ctx, iamAgg, NewIAMPasswordLockoutPolicyWriteModel(), &domain.PasswordLockoutPolicy{
event, err := r.addDefaultPasswordLockoutPolicy(ctx, iamAgg, NewIAMPasswordLockoutPolicyWriteModel(), &domain.PasswordLockoutPolicy{
MaxAttempts: step.DefaultPasswordLockoutPolicy.MaxAttempts,
ShowLockOutFailures: step.DefaultPasswordLockoutPolicy.ShowLockOutFailures,
})
@ -33,7 +33,7 @@ func (r *CommandSide) SetupStep4(ctx context.Context, step *Step4) error {
return nil, err
}
logging.Log("SETUP-Bfnge").Info("default password lockout policy set up")
return iamAgg, nil
return []eventstore.EventPusher{event}, nil
}
return r.setup(ctx, step, fn)
}

@ -2,12 +2,12 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/logging"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
type Step5 struct {
@ -23,16 +23,16 @@ func (s *Step5) execute(ctx context.Context, commandSide *CommandSide) error {
}
func (r *CommandSide) SetupStep5(ctx context.Context, step *Step5) error {
fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) {
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel)
err := r.addDefaultOrgIAMPolicy(ctx, iamAgg, NewIAMOrgIAMPolicyWriteModel(), &domain.OrgIAMPolicy{
event, err := r.addDefaultOrgIAMPolicy(ctx, iamAgg, NewIAMOrgIAMPolicyWriteModel(), &domain.OrgIAMPolicy{
UserLoginMustBeDomain: step.DefaultOrgIAMPolicy.UserLoginMustBeDomain,
})
if err != nil {
return nil, err
}
logging.Log("SETUP-ADgd2").Info("default org iam policy set up")
return iamAgg, nil
return []eventstore.EventPusher{event}, nil
}
return r.setup(ctx, step, fn)
}

@ -2,12 +2,12 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/logging"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
type Step6 struct {
@ -23,9 +23,9 @@ func (s *Step6) execute(ctx context.Context, commandSide *CommandSide) error {
}
func (r *CommandSide) SetupStep6(ctx context.Context, step *Step6) error {
fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) {
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel)
err := r.addDefaultLabelPolicy(ctx, iamAgg, NewIAMLabelPolicyWriteModel(), &domain.LabelPolicy{
event, err := r.addDefaultLabelPolicy(ctx, iamAgg, NewIAMLabelPolicyWriteModel(), &domain.LabelPolicy{
PrimaryColor: step.DefaultLabelPolicy.PrimaryColor,
SecondaryColor: step.DefaultLabelPolicy.SecondaryColor,
})
@ -33,7 +33,7 @@ func (r *CommandSide) SetupStep6(ctx context.Context, step *Step6) error {
return nil, err
}
logging.Log("SETUP-ADgd2").Info("default label policy set up")
return iamAgg, nil
return []eventstore.EventPusher{event}, nil
}
return r.setup(ctx, step, fn)
}

@ -2,11 +2,11 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
type Step7 struct {
@ -22,18 +22,18 @@ func (s *Step7) execute(ctx context.Context, commandSide *CommandSide) error {
}
func (r *CommandSide) SetupStep7(ctx context.Context, step *Step7) error {
fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) {
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
secondFactorModel := NewIAMSecondFactorWriteModel()
iamAgg := IAMAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
if !step.OTP {
return iamAgg, nil
return []eventstore.EventPusher{}, nil
}
err := r.addSecondFactorToDefaultLoginPolicy(ctx, iamAgg, secondFactorModel, domain.SecondFactorTypeOTP)
event, err := r.addSecondFactorToDefaultLoginPolicy(ctx, iamAgg, secondFactorModel, domain.SecondFactorTypeOTP)
if err != nil {
return nil, err
}
logging.Log("SETUP-Dggsg").Info("added OTP to 2FA login policy")
return iamAgg, nil
return []eventstore.EventPusher{event}, nil
}
return r.setup(ctx, step, fn)
}

@ -2,11 +2,11 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
type Step8 struct {
@ -22,18 +22,18 @@ func (s *Step8) execute(ctx context.Context, commandSide *CommandSide) error {
}
func (r *CommandSide) SetupStep8(ctx context.Context, step *Step8) error {
fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) {
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
secondFactorModel := NewIAMSecondFactorWriteModel()
iamAgg := IAMAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
if !step.U2F {
return iamAgg, nil
return []eventstore.EventPusher{}, nil
}
err := r.addSecondFactorToDefaultLoginPolicy(ctx, iamAgg, secondFactorModel, domain.SecondFactorTypeU2F)
event, err := r.addSecondFactorToDefaultLoginPolicy(ctx, iamAgg, secondFactorModel, domain.SecondFactorTypeU2F)
if err != nil {
return nil, err
}
logging.Log("SETUP-BDhne").Info("added U2F to 2FA login policy")
return iamAgg, nil
return []eventstore.EventPusher{event}, nil
}
return r.setup(ctx, step, fn)
}

@ -2,11 +2,11 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
type Step9 struct {
@ -22,31 +22,31 @@ func (s *Step9) execute(ctx context.Context, commandSide *CommandSide) error {
}
func (r *CommandSide) SetupStep9(ctx context.Context, step *Step9) error {
fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) {
fn := func(iam *IAMWriteModel) ([]eventstore.EventPusher, error) {
multiFactorModel := NewIAMMultiFactorWriteModel()
iamAgg := IAMAggregateFromWriteModel(&multiFactorModel.MultiFactoryWriteModel.WriteModel)
if !step.Passwordless {
return iamAgg, nil
return []eventstore.EventPusher{}, nil
}
err := setPasswordlessAllowedInPolicy(ctx, r, iamAgg)
passwordlessEvent, err := setPasswordlessAllowedInPolicy(ctx, r, iamAgg)
if err != nil {
return nil, err
}
logging.Log("SETUP-AEG2t").Info("allowed passwordless in login policy")
err = r.addMultiFactorToDefaultLoginPolicy(ctx, iamAgg, multiFactorModel, domain.MultiFactorTypeU2FWithPIN)
multifactorEvent, err := r.addMultiFactorToDefaultLoginPolicy(ctx, iamAgg, multiFactorModel, domain.MultiFactorTypeU2FWithPIN)
if err != nil {
return nil, err
}
logging.Log("SETUP-ADfng").Info("added passwordless to MFA login policy")
return iamAgg, err
return []eventstore.EventPusher{passwordlessEvent, multifactorEvent}, nil
}
return r.setup(ctx, step, fn)
}
func setPasswordlessAllowedInPolicy(ctx context.Context, c *CommandSide, iamAgg *iam_repo.Aggregate) error {
func setPasswordlessAllowedInPolicy(ctx context.Context, c *CommandSide, iamAgg *eventstore.Aggregate) (eventstore.EventPusher, error) {
policy, err := c.getDefaultLoginPolicy(ctx)
if err != nil {
return err
return nil, err
}
policy.PasswordlessType = domain.PasswordlessTypeAllowed
return c.changeDefaultLoginPolicy(ctx, iamAgg, NewIAMLoginPolicyWriteModel(), policy)

@ -42,123 +42,129 @@ func (rm *UniqueConstraintReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *org.OrgAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), org.NewAddOrgNameUniqueConstraint(e.Name))
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.NewAddOrgNameUniqueConstraint(e.Name))
case *org.OrgChangedEvent:
rm.changeUniqueConstraint(e.AggregateID(), e.AggregateID(), org.NewAddOrgNameUniqueConstraint(e.Name))
rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.NewAddOrgNameUniqueConstraint(e.Name))
case *org.DomainVerifiedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), org.NewAddOrgNameUniqueConstraint(e.Domain))
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.NewAddOrgNameUniqueConstraint(e.Domain))
case *org.DomainRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.AggregateID(), org.UniqueOrgDomain)
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.UniqueOrgDomain)
case *iam.IDPConfigAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.ResourceOwner()))
rm.addUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner))
case *iam.IDPConfigChangedEvent:
rm.changeUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.ResourceOwner()))
rm.changeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner))
case *iam.IDPConfigRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.UniqueIDPConfigNameType)
rm.removeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.UniqueIDPConfigNameType)
case *org.IDPConfigAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.ResourceOwner()))
rm.addUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner))
case *org.IDPConfigChangedEvent:
rm.changeUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.ResourceOwner()))
rm.changeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner))
case *org.IDPConfigRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.UniqueIDPConfigNameType)
rm.removeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.UniqueIDPConfigNameType)
case *iam.MailTextAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.MailTextType+e.Language, policy.NewAddMailTextUniqueConstraint(e.AggregateID(), e.MailTextType, e.Language))
rm.addUniqueConstraint(e.Aggregate().ID, e.MailTextType+e.Language, policy.NewAddMailTextUniqueConstraint(e.Aggregate().ID, e.MailTextType, e.Language))
case *org.MailTextAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.MailTextType+e.Language, policy.NewAddMailTextUniqueConstraint(e.AggregateID(), e.MailTextType, e.Language))
rm.addUniqueConstraint(e.Aggregate().ID, e.MailTextType+e.Language, policy.NewAddMailTextUniqueConstraint(e.Aggregate().ID, e.MailTextType, e.Language))
case *org.MailTextRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.MailTextType+e.Language, policy.UniqueMailText)
rm.removeUniqueConstraint(e.Aggregate().ID, e.MailTextType+e.Language, policy.UniqueMailText)
case *project.ProjectAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), project.NewAddProjectNameUniqueConstraint(e.Name, e.ResourceOwner()))
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, project.NewAddProjectNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner))
case *project.ProjectChangeEvent:
rm.changeUniqueConstraint(e.AggregateID(), e.AggregateID(), project.NewAddProjectNameUniqueConstraint(*e.Name, e.ResourceOwner()))
rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, project.NewAddProjectNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner))
case *project.ProjectRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.AggregateID(), project.UniqueProjectnameType)
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, project.UniqueProjectnameType)
case *project.ApplicationAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.AppID, project.NewAddApplicationUniqueConstraint(e.Name, e.AggregateID()))
rm.addUniqueConstraint(e.Aggregate().ID, e.AppID, project.NewAddApplicationUniqueConstraint(e.Name, e.Aggregate().ID))
case *project.ApplicationChangedEvent:
rm.changeUniqueConstraint(e.AggregateID(), e.AppID, project.NewAddApplicationUniqueConstraint(e.Name, e.AggregateID()))
rm.changeUniqueConstraint(e.Aggregate().ID, e.AppID, project.NewAddApplicationUniqueConstraint(e.Name, e.Aggregate().ID))
case *project.ApplicationRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.AppID, project.UniqueAppNameType)
rm.removeUniqueConstraint(e.Aggregate().ID, e.AppID, project.UniqueAppNameType)
case *project.GrantAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.GrantID, project.NewAddProjectGrantUniqueConstraint(e.GrantedOrgID, e.AggregateID()))
rm.addUniqueConstraint(e.Aggregate().ID, e.GrantID, project.NewAddProjectGrantUniqueConstraint(e.GrantedOrgID, e.Aggregate().ID))
case *project.GrantRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.GrantID, project.UniqueGrantType)
rm.removeUniqueConstraint(e.Aggregate().ID, e.GrantID, project.UniqueGrantType)
case *project.GrantMemberAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.GrantID+e.UserID, project.NewAddProjectGrantMemberUniqueConstraint(e.AggregateID(), e.UserID, e.GrantID))
rm.addUniqueConstraint(e.Aggregate().ID, e.GrantID+e.UserID, project.NewAddProjectGrantMemberUniqueConstraint(e.Aggregate().ID, e.UserID, e.GrantID))
case *project.GrantMemberRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.GrantID+e.UserID, project.UniqueProjectGrantMemberType)
rm.removeUniqueConstraint(e.Aggregate().ID, e.GrantID+e.UserID, project.UniqueProjectGrantMemberType)
case *project.RoleAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.Key, project.NewAddProjectRoleUniqueConstraint(e.Key, e.AggregateID()))
rm.addUniqueConstraint(e.Aggregate().ID, e.Key, project.NewAddProjectRoleUniqueConstraint(e.Key, e.Aggregate().ID))
case *project.RoleRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.Key, project.UniqueRoleType)
rm.removeUniqueConstraint(e.Aggregate().ID, e.Key, project.UniqueRoleType)
case *user.HumanAddedEvent:
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.ResourceOwner())
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.Aggregate().ResourceOwner)
if err != nil {
logging.Log("COMMAND-0k9Gs").WithError(err).Error("could not read policy for human added event unique constraint")
continue
}
rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), user.NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), policy.UserLoginMustBeDomain))
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
case *user.HumanRegisteredEvent:
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.ResourceOwner())
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.Aggregate().ResourceOwner)
if err != nil {
logging.Log("COMMAND-m9fod").WithError(err).Error("could not read policy for human registered event unique constraint")
continue
}
rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), user.NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), policy.UserLoginMustBeDomain))
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
case *user.MachineAddedEvent:
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.ResourceOwner())
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.Aggregate().ResourceOwner)
if err != nil {
logging.Log("COMMAND-2n8vs").WithError(err).Error("could not read policy for machine added event unique constraint")
continue
}
rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), user.NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), policy.UserLoginMustBeDomain))
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
case *user.UserRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.AggregateID(), user.UniqueUsername)
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.UniqueUsername)
case *user.UsernameChangedEvent:
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.ResourceOwner())
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.Aggregate().ResourceOwner)
if err != nil {
logging.Log("COMMAND-5n8gk").WithError(err).Error("could not read policy for username changed event unique constraint")
continue
}
rm.changeUniqueConstraint(e.AggregateID(), e.AggregateID(), user.NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), policy.UserLoginMustBeDomain))
rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
case *user.DomainClaimedEvent:
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.ResourceOwner())
policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.Aggregate().ResourceOwner)
if err != nil {
logging.Log("COMMAND-xb8uf").WithError(err).Error("could not read policy for domain claimed event unique constraint")
continue
}
rm.changeUniqueConstraint(e.AggregateID(), e.AggregateID(), user.NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), policy.UserLoginMustBeDomain))
rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
case *user.HumanExternalIDPAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.IDPConfigID+e.ExternalUserID, user.NewAddExternalIDPUniqueConstraint(e.IDPConfigID, e.ExternalUserID))
rm.addUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.NewAddExternalIDPUniqueConstraint(e.IDPConfigID, e.ExternalUserID))
case *user.HumanExternalIDPRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.IDPConfigID+e.ExternalUserID, user.UniqueExternalIDPType)
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueExternalIDPType)
case *user.HumanExternalIDPCascadeRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.IDPConfigID+e.ExternalUserID, user.UniqueExternalIDPType)
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueExternalIDPType)
case *usergrant.UserGrantAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), usergrant.NewAddUserGrantUniqueConstraint(e.ResourceOwner(), e.UserID, e.ProjectID, e.ProjectGrantID))
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.NewAddUserGrantUniqueConstraint(e.Aggregate().ResourceOwner, e.UserID, e.ProjectID, e.ProjectGrantID))
case *usergrant.UserGrantRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.AggregateID(), usergrant.UniqueUserGrant)
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.UniqueUserGrant)
case *usergrant.UserGrantCascadeRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.AggregateID(), usergrant.UniqueUserGrant)
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.UniqueUserGrant)
case *iam.MemberAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.UserID, member.NewAddMemberUniqueConstraint(e.AggregateID(), e.UserID))
rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID))
case *iam.MemberRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.UserID, member.UniqueMember)
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
case *org.MemberAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.UserID, member.NewAddMemberUniqueConstraint(e.AggregateID(), e.UserID))
rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID))
case *org.MemberRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.UserID, member.UniqueMember)
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
case *project.MemberAddedEvent:
rm.addUniqueConstraint(e.AggregateID(), e.UserID, member.NewAddMemberUniqueConstraint(e.AggregateID(), e.UserID))
rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID))
case *project.MemberRemovedEvent:
rm.removeUniqueConstraint(e.AggregateID(), e.UserID, member.UniqueMember)
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
}
}
return nil
}
func (rm *UniqueConstraintReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType, org.AggregateType, project.AggregateType, user.AggregateType, usergrant.AggregateType).
return eventstore.NewSearchQueryBuilder(
eventstore.ColumnsEvent,
iam.AggregateType,
org.AggregateType,
project.AggregateType,
user.AggregateType,
usergrant.AggregateType).
EventTypes(
org.OrgAddedEventType,
org.OrgChangedEventType,

@ -3,196 +3,203 @@ package command
import (
"context"
"fmt"
"github.com/caos/logging"
auth_req_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/eventstore/v2"
"strings"
"time"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/user"
)
func (r *CommandSide) ChangeUsername(ctx context.Context, orgID, userID, userName string) error {
func (cs *CommandSide) ChangeUsername(ctx context.Context, orgID, userID, userName string) error {
if orgID == "" || userID == "" || userName == "" {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2N9fs", "Errors.IDMissing")
}
existingUser, err := r.userWriteModelByID(ctx, userID, orgID)
existingUser, err := cs.userWriteModelByID(ctx, userID, orgID)
if err != nil {
return err
}
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
if !isUserStateExists(existingUser.UserState) {
return caos_errs.ThrowNotFound(nil, "COMMAND-5N9ds", "Errors.User.NotFound")
}
if existingUser.UserName == userName {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6m9gs", "Errors.User.UsernameNotChanged")
}
orgIAMPolicy, err := r.getOrgIAMPolicy(ctx, orgID)
orgIAMPolicy, err := cs.getOrgIAMPolicy(ctx, orgID)
if err != nil {
return err
}
if err := CheckOrgIAMPolicyForUserName(userName, orgIAMPolicy); err != nil {
return err
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUsernameChangedEvent(ctx, existingUser.UserName, userName, orgIAMPolicy.UserLoginMustBeDomain))
return r.eventstore.PushAggregate(ctx, existingUser, userAgg)
_, err = cs.eventstore.PushEvents(ctx,
user.NewUsernameChangedEvent(ctx, userAgg, existingUser.UserName, userName, orgIAMPolicy.UserLoginMustBeDomain))
return err
}
func (r *CommandSide) DeactivateUser(ctx context.Context, userID, resourceOwner string) error {
if userID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-m0gDf", "Errors.User.UserIDMissing")
}
existingUser, err := r.userWriteModelByID(ctx, userID, resourceOwner)
if err != nil {
return err
}
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
if !isUserStateExists(existingUser.UserState) {
return caos_errs.ThrowNotFound(nil, "COMMAND-3M9ds", "Errors.User.NotFound")
}
if existingUser.UserState == domain.UserStateInactive {
if isUserStateInactive(existingUser.UserState) {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5M0sf", "Errors.User.AlreadyInactive")
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserDeactivatedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingUser, userAgg)
_, err = r.eventstore.PushEvents(ctx,
user.NewUserDeactivatedEvent(ctx, UserAggregateFromWriteModel(&existingUser.WriteModel)))
return err
}
func (r *CommandSide) ReactivateUser(ctx context.Context, userID, resourceOwner string) error {
if userID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M9ds", "Errors.User.UserIDMissing")
}
existingUser, err := r.userWriteModelByID(ctx, userID, resourceOwner)
if err != nil {
return err
}
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
if !isUserStateExists(existingUser.UserState) {
return caos_errs.ThrowNotFound(nil, "COMMAND-4M0sd", "Errors.User.NotFound")
}
if existingUser.UserState != domain.UserStateInactive {
if !isUserStateInactive(existingUser.UserState) {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6M0sf", "Errors.User.NotInactive")
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserReactivatedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingUser, userAgg)
_, err = r.eventstore.PushEvents(ctx,
user.NewUserReactivatedEvent(ctx, UserAggregateFromWriteModel(&existingUser.WriteModel)))
return err
}
func (r *CommandSide) LockUser(ctx context.Context, userID, resourceOwner string) error {
if userID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M0sd", "Errors.User.UserIDMissing")
}
existingUser, err := r.userWriteModelByID(ctx, userID, resourceOwner)
if err != nil {
return err
}
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
if !isUserStateExists(existingUser.UserState) {
return caos_errs.ThrowNotFound(nil, "COMMAND-5M9fs", "Errors.User.NotFound")
}
if existingUser.UserState != domain.UserStateActive && existingUser.UserState != domain.UserStateInitial {
if !hasUserState(existingUser.UserState, domain.UserStateActive, domain.UserStateInitial) {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-3NN8v", "Errors.User.ShouldBeActiveOrInitial")
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserLockedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingUser, userAgg)
_, err = r.eventstore.PushEvents(ctx,
user.NewUserLockedEvent(ctx, UserAggregateFromWriteModel(&existingUser.WriteModel)))
return err
}
func (r *CommandSide) UnlockUser(ctx context.Context, userID, resourceOwner string) error {
if userID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-M0dse", "Errors.User.UserIDMissing")
}
existingUser, err := r.userWriteModelByID(ctx, userID, resourceOwner)
if err != nil {
return err
}
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
if !isUserStateExists(existingUser.UserState) {
return caos_errs.ThrowNotFound(nil, "COMMAND-M0dos", "Errors.User.NotFound")
}
if existingUser.UserState != domain.UserStateLocked {
if !hasUserState(existingUser.UserState, domain.UserStateLocked) {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M0ds", "Errors.User.NotLocked")
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserUnlockedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingUser, userAgg)
_, err = r.eventstore.PushEvents(ctx,
user.NewUserUnlockedEvent(ctx, UserAggregateFromWriteModel(&existingUser.WriteModel)))
return err
}
func (r *CommandSide) RemoveUser(ctx context.Context, userID, resourceOwner string, cascadingGrantIDs ...string) error {
if userID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M0ds", "Errors.User.UserIDMissing")
}
existingUser, err := r.userWriteModelByID(ctx, userID, resourceOwner)
if err != nil {
return err
}
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
if !isUserStateExists(existingUser.UserState) {
return caos_errs.ThrowNotFound(nil, "COMMAND-5M0od", "Errors.User.NotFound")
}
orgIAMPolicy, err := r.getOrgIAMPolicy(ctx, existingUser.ResourceOwner)
if err != nil {
return err
}
aggregates := make([]eventstore.Aggregater, 0)
var events []eventstore.EventPusher
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserRemovedEvent(ctx, existingUser.ResourceOwner, existingUser.UserName, orgIAMPolicy.UserLoginMustBeDomain))
aggregates = append(aggregates, userAgg)
events = append(events, user.NewUserRemovedEvent(ctx, userAgg, existingUser.UserName, orgIAMPolicy.UserLoginMustBeDomain))
for _, grantID := range cascadingGrantIDs {
grantAgg, _, err := r.removeUserGrant(ctx, grantID, "", true)
removeEvent, err := r.removeUserGrant(ctx, grantID, "", true)
if err != nil {
logging.LogWithFields("COMMAND-5m9oL", "usergrantid", grantID).WithError(err).Warn("could not cascade remove role on user grant")
continue
}
aggregates = append(aggregates, grantAgg)
events = append(events, removeEvent)
}
_, err = r.eventstore.PushAggregates(ctx, aggregates...)
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}
func (r *CommandSide) CreateUserToken(ctx context.Context, orgID, agentID, clientID, userID string, audience, scopes []string, lifetime time.Duration) (*domain.Token, error) {
func (r *CommandSide) AddUserToken(ctx context.Context, orgID, agentID, clientID, userID string, audience, scopes []string, lifetime time.Duration) (*domain.Token, error) {
if orgID == "" || userID == "" {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-55n8M", "Errors.IDMissing")
}
existingUser, err := r.userWriteModelByID(ctx, userID, orgID)
if err != nil {
return nil, err
}
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
if !isUserStateExists(existingUser.UserState) {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-1d6Gg", "Errors.User.NotFound")
}
for _, scope := range scopes {
if strings.HasPrefix(scope, auth_req_model.ProjectIDScope) && strings.HasSuffix(scope, auth_req_model.AudSuffix) {
audience = append(audience, strings.TrimSuffix(strings.TrimPrefix(scope, auth_req_model.ProjectIDScope), auth_req_model.AudSuffix))
}
}
audience = domain.AddAudScopeToAudience(audience, scopes)
preferredLanguage := ""
existingHuman, err := r.getHumanWriteModelByID(ctx, userID, orgID)
if existingHuman != nil {
preferredLanguage = existingHuman.PreferredLanguage.String()
}
now := time.Now().UTC()
expiration := time.Now().UTC().Add(lifetime)
tokenID, err := r.idGenerator.Next()
if err != nil {
return nil, err
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserTokenAddedEvent(ctx, tokenID, clientID, agentID, preferredLanguage, audience, scopes, now.Add(lifetime)))
err = r.eventstore.PushAggregate(ctx, existingUser, userAgg)
_, err = r.eventstore.PushEvents(ctx,
user.NewUserTokenAddedEvent(ctx, userAgg, tokenID, clientID, agentID, preferredLanguage, audience, scopes, expiration))
if err != nil {
return nil, err
}
return &domain.Token{
ObjectRoot: models.ObjectRoot{
AggregateID: userID,
@ -202,12 +209,12 @@ func (r *CommandSide) CreateUserToken(ctx context.Context, orgID, agentID, clien
ApplicationID: clientID,
Audience: audience,
Scopes: scopes,
Expiration: now.Add(lifetime),
Expiration: expiration,
PreferredLanguage: preferredLanguage,
}, nil
}
func (r *CommandSide) userDomainClaimed(ctx context.Context, userID string) (_ *user.Aggregate, _ *UserWriteModel, err error) {
func (r *CommandSide) userDomainClaimed(ctx context.Context, userID string) (events []eventstore.EventPusher, _ *UserWriteModel, err error) {
existingUser, err := r.userWriteModelByID(ctx, userID, "")
if err != nil {
return nil, nil, err
@ -227,8 +234,14 @@ func (r *CommandSide) userDomainClaimed(ctx context.Context, userID string) (_ *
if err != nil {
return nil, nil, err
}
userAgg.PushEvents(user.NewDomainClaimedEvent(ctx, fmt.Sprintf("%s@temporary.%s", id, r.iamDomain), existingUser.UserName, orgIAMPolicy.UserLoginMustBeDomain))
return userAgg, changedUserGrant, nil
return []eventstore.EventPusher{
user.NewDomainClaimedEvent(
ctx,
userAgg,
fmt.Sprintf("%s@temporary.%s", id, r.iamDomain),
existingUser.UserName,
orgIAMPolicy.UserLoginMustBeDomain),
}, changedUserGrant, nil
}
func (r *CommandSide) UserDomainClaimedSent(ctx context.Context, orgID, userID string) (err error) {
@ -236,20 +249,21 @@ func (r *CommandSide) UserDomainClaimedSent(ctx context.Context, orgID, userID s
if err != nil {
return err
}
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
if !isUserStateExists(existingUser.UserState) {
return caos_errs.ThrowNotFound(nil, "COMMAND-5m9gK", "Errors.User.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewDomainClaimedSentEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingUser, userAgg)
_, err = r.eventstore.PushEvents(ctx,
user.NewDomainClaimedSentEvent(ctx, UserAggregateFromWriteModel(&existingUser.WriteModel)))
return err
}
func (r *CommandSide) checkUserExists(ctx context.Context, userID, resourceOwner string) error {
userWriteModel, err := r.userWriteModelByID(ctx, userID, resourceOwner)
existingUser, err := r.userWriteModelByID(ctx, userID, resourceOwner)
if err != nil {
return err
}
if userWriteModel.UserState == domain.UserStateUnspecified || userWriteModel.UserState == domain.UserStateDeleted {
if !isUserStateExists(existingUser.UserState) {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M0fs", "Errors.User.NotFound")
}
return nil
@ -266,15 +280,3 @@ func (r *CommandSide) userWriteModelByID(ctx context.Context, userID, resourceOw
}
return writeModel, nil
}
func (r *CommandSide) userReadModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *UserWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel = NewUserWriteModel(userID, resourceOwner)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

@ -2,28 +2,33 @@ package command
import (
"context"
"reflect"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/usergrant"
"reflect"
)
func (r *CommandSide) AddUserGrant(ctx context.Context, usergrant *domain.UserGrant, resourceOwner string) (_ *domain.UserGrant, err error) {
userGrantAgg, addedUserGrant, err := r.addUserGrant(ctx, usergrant, resourceOwner)
event, addedUserGrant, err := r.addUserGrant(ctx, usergrant, resourceOwner)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedUserGrant, userGrantAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedUserGrant, pushedEvents...)
if err != nil {
return nil, err
}
return userGrantWriteModelToUserGrant(addedUserGrant), nil
}
func (r *CommandSide) addUserGrant(ctx context.Context, userGrant *domain.UserGrant, resourceOwner string) (_ *usergrant.Aggregate, _ *UserGrantWriteModel, err error) {
func (r *CommandSide) addUserGrant(ctx context.Context, userGrant *domain.UserGrant, resourceOwner string) (pusher eventstore.EventPusher, _ *UserGrantWriteModel, err error) {
err = checkExplicitProjectPermission(ctx, userGrant.ProjectGrantID, userGrant.ProjectID)
if err != nil {
return nil, nil, err
@ -43,36 +48,37 @@ func (r *CommandSide) addUserGrant(ctx context.Context, userGrant *domain.UserGr
if err != nil {
return nil, nil, err
}
addedUserGrant := NewUserGrantWriteModel(userGrant.AggregateID, resourceOwner)
userGrantAgg := UserGrantAggregateFromWriteModel(&addedUserGrant.WriteModel)
userGrantAgg.PushEvents(
usergrant.NewUserGrantAddedEvent(
ctx,
resourceOwner,
userGrant.UserID,
userGrant.ProjectID,
userGrant.ProjectGrantID,
userGrant.RoleKeys,
),
pusher = usergrant.NewUserGrantAddedEvent(
ctx,
userGrantAgg,
userGrant.UserID,
userGrant.ProjectID,
userGrant.ProjectGrantID,
userGrant.RoleKeys,
)
return userGrantAgg, addedUserGrant, nil
return pusher, addedUserGrant, nil
}
func (r *CommandSide) ChangeUserGrant(ctx context.Context, userGrant *domain.UserGrant, resourceOwner string) (_ *domain.UserGrant, err error) {
userGrantAgg, addedUserGrant, err := r.changeUserGrant(ctx, userGrant, resourceOwner, false)
event, changedUserGrant, err := r.changeUserGrant(ctx, userGrant, resourceOwner, false)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedUserGrant, userGrantAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
return userGrantWriteModelToUserGrant(addedUserGrant), nil
err = AppendAndReduce(changedUserGrant, pushedEvents...)
if err != nil {
return nil, err
}
return userGrantWriteModelToUserGrant(changedUserGrant), nil
}
func (r *CommandSide) changeUserGrant(ctx context.Context, userGrant *domain.UserGrant, resourceOwner string, cascade bool) (_ *usergrant.Aggregate, _ *UserGrantWriteModel, err error) {
func (r *CommandSide) changeUserGrant(ctx context.Context, userGrant *domain.UserGrant, resourceOwner string, cascade bool) (_ eventstore.EventPusher, _ *UserGrantWriteModel, err error) {
err = checkExplicitProjectPermission(ctx, userGrant.ProjectGrantID, userGrant.ProjectID)
if err != nil {
return nil, nil, err
@ -95,26 +101,19 @@ func (r *CommandSide) changeUserGrant(ctx context.Context, userGrant *domain.Use
changedUserGrant := NewUserGrantWriteModel(userGrant.AggregateID, resourceOwner)
userGrantAgg := UserGrantAggregateFromWriteModel(&changedUserGrant.WriteModel)
if !cascade {
userGrantAgg.PushEvents(
usergrant.NewUserGrantChangedEvent(ctx, userGrant.RoleKeys),
)
} else {
userGrantAgg.PushEvents(
usergrant.NewUserGrantCascadeChangedEvent(ctx, userGrant.RoleKeys),
)
if cascade {
return usergrant.NewUserGrantCascadeChangedEvent(ctx, userGrantAgg, userGrant.RoleKeys), existingUserGrant, nil
}
return userGrantAgg, changedUserGrant, nil
return usergrant.NewUserGrantChangedEvent(ctx, userGrantAgg, userGrant.RoleKeys), existingUserGrant, nil
}
func (r *CommandSide) removeRoleFromUserGrant(ctx context.Context, userGrantID string, roleKeys []string, cascade bool) (_ *usergrant.Aggregate, _ *UserGrantWriteModel, err error) {
func (r *CommandSide) removeRoleFromUserGrant(ctx context.Context, userGrantID string, roleKeys []string, cascade bool) (_ eventstore.EventPusher, err error) {
existingUserGrant, err := r.userGrantWriteModelByID(ctx, userGrantID, "")
if err != nil {
return nil, nil, err
return nil, err
}
if existingUserGrant.State == domain.UserGrantStateUnspecified || existingUserGrant.State == domain.UserGrantStateRemoved {
return nil, nil, caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.UserGrant.NotFound")
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.UserGrant.NotFound")
}
keyExists := false
for i, key := range existingUserGrant.RoleKeys {
@ -129,22 +128,16 @@ func (r *CommandSide) removeRoleFromUserGrant(ctx context.Context, userGrantID s
}
}
if !keyExists {
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5m8g9", "Errors.UserGrant.RoleKeyNotFound")
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5m8g9", "Errors.UserGrant.RoleKeyNotFound")
}
changedUserGrant := NewUserGrantWriteModel(userGrantID, "")
userGrantAgg := UserGrantAggregateFromWriteModel(&changedUserGrant.WriteModel)
if !cascade {
userGrantAgg.PushEvents(
usergrant.NewUserGrantChangedEvent(ctx, existingUserGrant.RoleKeys),
)
} else {
userGrantAgg.PushEvents(
usergrant.NewUserGrantCascadeChangedEvent(ctx, existingUserGrant.RoleKeys),
)
if cascade {
return usergrant.NewUserGrantCascadeChangedEvent(ctx, userGrantAgg, existingUserGrant.RoleKeys), nil
}
return userGrantAgg, changedUserGrant, nil
return usergrant.NewUserGrantChangedEvent(ctx, userGrantAgg, existingUserGrant.RoleKeys), nil
}
func (r *CommandSide) DeactivateUserGrant(ctx context.Context, grantID, resourceOwner string) (err error) {
@ -169,11 +162,8 @@ func (r *CommandSide) DeactivateUserGrant(ctx context.Context, grantID, resource
deactivateUserGrant := NewUserGrantWriteModel(grantID, resourceOwner)
userGrantAgg := UserGrantAggregateFromWriteModel(&deactivateUserGrant.WriteModel)
userGrantAgg.PushEvents(
usergrant.NewUserGrantDeactivatedEvent(ctx),
)
return r.eventstore.PushAggregate(ctx, deactivateUserGrant, userGrantAgg)
_, err = r.eventstore.PushEvents(ctx, usergrant.NewUserGrantDeactivatedEvent(ctx, userGrantAgg))
return err
}
func (r *CommandSide) ReactivateUserGrant(ctx context.Context, grantID, resourceOwner string) (err error) {
@ -198,78 +188,69 @@ func (r *CommandSide) ReactivateUserGrant(ctx context.Context, grantID, resource
deactivateUserGrant := NewUserGrantWriteModel(grantID, resourceOwner)
userGrantAgg := UserGrantAggregateFromWriteModel(&deactivateUserGrant.WriteModel)
userGrantAgg.PushEvents(
usergrant.NewUserGrantReactivatedEvent(ctx),
)
return r.eventstore.PushAggregate(ctx, deactivateUserGrant, userGrantAgg)
_, err = r.eventstore.PushEvents(ctx, usergrant.NewUserGrantReactivatedEvent(ctx, userGrantAgg))
return err
}
func (r *CommandSide) RemoveUserGrant(ctx context.Context, grantID, resourceOwner string) (err error) {
userGrantAgg, removeUserGrant, err := r.removeUserGrant(ctx, grantID, resourceOwner, false)
event, err := r.removeUserGrant(ctx, grantID, resourceOwner, false)
if err != nil {
return nil
}
return r.eventstore.PushAggregate(ctx, removeUserGrant, userGrantAgg)
}
func (r *CommandSide) BulkRemoveUserGrant(ctx context.Context, grantIDs []string, resourceOwner string) (err error) {
aggregates := make([]eventstore.Aggregater, len(grantIDs))
for i, grantID := range grantIDs {
userGrantAgg, _, err := r.removeUserGrant(ctx, grantID, resourceOwner, false)
if err != nil {
return nil
}
aggregates[i] = userGrantAgg
}
_, err = r.eventstore.PushAggregates(ctx, aggregates...)
_, err = r.eventstore.PushEvents(ctx, event)
return err
}
func (r *CommandSide) removeUserGrant(ctx context.Context, grantID, resourceOwner string, cascade bool) (_ *usergrant.Aggregate, _ *UserGrantWriteModel, err error) {
func (r *CommandSide) BulkRemoveUserGrant(ctx context.Context, grantIDs []string, resourceOwner string) (err error) {
events := make([]eventstore.EventPusher, len(grantIDs))
for i, grantID := range grantIDs {
event, err := r.removeUserGrant(ctx, grantID, resourceOwner, false)
if err != nil {
return nil
}
events[i] = event
}
_, err = r.eventstore.PushEvents(ctx, events...)
return err
}
func (r *CommandSide) removeUserGrant(ctx context.Context, grantID, resourceOwner string, cascade bool) (_ eventstore.EventPusher, err error) {
if grantID == "" {
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-J9sc5", "Errors.UserGrant.IDMissing")
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-J9sc5", "Errors.UserGrant.IDMissing")
}
existingUserGrant, err := r.userGrantWriteModelByID(ctx, grantID, resourceOwner)
if err != nil {
return nil, nil, err
return nil, err
}
if !cascade {
err = checkExplicitProjectPermission(ctx, existingUserGrant.ProjectGrantID, existingUserGrant.ProjectID)
if err != nil {
return nil, nil, err
return nil, err
}
}
if existingUserGrant.State == domain.UserGrantStateUnspecified || existingUserGrant.State == domain.UserGrantStateRemoved {
return nil, nil, caos_errs.ThrowNotFound(nil, "COMMAND-1My0t", "Errors.UserGrant.NotFound")
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-1My0t", "Errors.UserGrant.NotFound")
}
removeUserGrant := NewUserGrantWriteModel(grantID, resourceOwner)
userGrantAgg := UserGrantAggregateFromWriteModel(&removeUserGrant.WriteModel)
if !cascade {
userGrantAgg.PushEvents(
usergrant.NewUserGrantRemovedEvent(
ctx,
existingUserGrant.ResourceOwner,
existingUserGrant.UserID,
existingUserGrant.ProjectID,
existingUserGrant.ProjectGrantID),
)
} else {
userGrantAgg.PushEvents(
usergrant.NewUserGrantCascadeRemovedEvent(
ctx,
existingUserGrant.ResourceOwner,
existingUserGrant.UserID,
existingUserGrant.ProjectID,
existingUserGrant.ProjectGrantID),
)
if cascade {
return usergrant.NewUserGrantCascadeRemovedEvent(
ctx,
userGrantAgg,
existingUserGrant.UserID,
existingUserGrant.ProjectID,
existingUserGrant.ProjectGrantID), nil
}
return userGrantAgg, removeUserGrant, nil
return usergrant.NewUserGrantRemovedEvent(
ctx,
userGrantAgg,
existingUserGrant.UserID,
existingUserGrant.ProjectID,
existingUserGrant.ProjectGrantID), nil
}
func (r *CommandSide) userGrantWriteModelByID(ctx context.Context, userGrantID, resourceOwner string) (writeModel *UserGrantWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)

@ -25,10 +25,6 @@ func NewUserGrantWriteModel(userGrantID string, resourceOwner string) *UserGrant
}
}
func (wm *UserGrantWriteModel) AppendEvents(events ...eventstore.EventReader) {
wm.WriteModel.AppendEvents(events...)
}
func (wm *UserGrantWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
@ -63,15 +59,20 @@ func (wm *UserGrantWriteModel) Reduce() error {
func (wm *UserGrantWriteModel) Query() *eventstore.SearchQueryBuilder {
query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, usergrant.AggregateType).
AggregateIDs(wm.AggregateID)
AggregateIDs(wm.AggregateID).
EventTypes(usergrant.UserGrantAddedType,
usergrant.UserGrantChangedType,
usergrant.UserGrantCascadeChangedType,
usergrant.UserGrantDeactivatedType,
usergrant.UserGrantReactivatedType,
usergrant.UserGrantRemovedType,
usergrant.UserGrantCascadeRemovedType)
if wm.ResourceOwner != "" {
query.ResourceOwner(wm.ResourceOwner)
}
return query
}
func UserGrantAggregateFromWriteModel(wm *eventstore.WriteModel) *usergrant.Aggregate {
return &usergrant.Aggregate{
Aggregate: *eventstore.AggregateFromWriteModel(wm, usergrant.AggregateType, usergrant.AggregateVersion),
}
func UserGrantAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate {
return eventstore.AggregateFromWriteModel(wm, usergrant.AggregateType, usergrant.AggregateVersion)
}

@ -2,6 +2,7 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/eventstore/v2"
@ -11,22 +12,27 @@ import (
)
func (r *CommandSide) getHuman(ctx context.Context, userID, resourceowner string) (*domain.Human, error) {
writeModel, err := r.getHumanWriteModelByID(ctx, userID, resourceowner)
human, err := r.getHumanWriteModelByID(ctx, userID, resourceowner)
if err != nil {
return nil, err
}
if writeModel.UserState == domain.UserStateUnspecified || writeModel.UserState == domain.UserStateDeleted {
if !isUserStateExists(human.UserState) {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-M9dsd", "Errors.User.NotFound")
}
return writeModelToHuman(writeModel), nil
return writeModelToHuman(human), nil
}
func (r *CommandSide) AddHuman(ctx context.Context, orgID string, human *domain.Human) (*domain.Human, error) {
userAgg, addedHuman, err := r.addHuman(ctx, orgID, human)
events, addedHuman, err := r.addHuman(ctx, orgID, human)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedHuman, userAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedHuman, pushedEvents...)
if err != nil {
return nil, err
}
@ -34,7 +40,7 @@ func (r *CommandSide) AddHuman(ctx context.Context, orgID string, human *domain.
return writeModelToHuman(addedHuman), nil
}
func (r *CommandSide) addHuman(ctx context.Context, orgID string, human *domain.Human) (*user.Aggregate, *HumanWriteModel, error) {
func (r *CommandSide) addHuman(ctx context.Context, orgID string, human *domain.Human) ([]eventstore.EventPusher, *HumanWriteModel, error) {
if !human.IsValid() {
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4M90d", "Errors.User.Invalid")
}
@ -42,46 +48,48 @@ func (r *CommandSide) addHuman(ctx context.Context, orgID string, human *domain.
}
func (r *CommandSide) RegisterHuman(ctx context.Context, orgID string, human *domain.Human, externalIDP *domain.ExternalIDP, orgMemberRoles []string) (*domain.Human, error) {
aggregates := make([]eventstore.Aggregater, 2)
userAgg, addedHuman, err := r.registerHuman(ctx, orgID, human, externalIDP)
userEvents, registeredHuman, err := r.registerHuman(ctx, orgID, human, externalIDP)
if err != nil {
return nil, err
}
aggregates[0] = userAgg
orgMemberWriteModel := NewOrgMemberWriteModel(orgID, addedHuman.AggregateID)
orgMemberWriteModel := NewOrgMemberWriteModel(orgID, registeredHuman.AggregateID)
orgAgg := OrgAggregateFromWriteModel(&orgMemberWriteModel.WriteModel)
if orgMemberRoles != nil {
if len(orgMemberRoles) > 0 {
orgMember := &domain.Member{
ObjectRoot: models.ObjectRoot{
AggregateID: orgID,
},
UserID: userAgg.ID(),
UserID: human.AggregateID,
Roles: orgMemberRoles,
}
r.addOrgMember(ctx, orgAgg, orgMemberWriteModel, orgMember)
memberEvent, err := r.addOrgMember(ctx, orgAgg, orgMemberWriteModel, orgMember)
if err != nil {
return nil, err
}
userEvents = append(userEvents, memberEvent)
}
aggregates[1] = orgAgg
eventReader, err := r.eventstore.PushAggregates(ctx, aggregates...)
pushedEvents, err := r.eventstore.PushEvents(ctx, userEvents...)
if err != nil {
return nil, err
}
addedHuman.AppendEvents(eventReader...)
addedHuman.Reduce()
return writeModelToHuman(addedHuman), nil
err = AppendAndReduce(registeredHuman, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToHuman(registeredHuman), nil
}
func (r *CommandSide) registerHuman(ctx context.Context, orgID string, human *domain.Human, externalIDP *domain.ExternalIDP) (*user.Aggregate, *HumanWriteModel, error) {
func (r *CommandSide) registerHuman(ctx context.Context, orgID string, human *domain.Human, externalIDP *domain.ExternalIDP) ([]eventstore.EventPusher, *HumanWriteModel, error) {
if !human.IsValid() || externalIDP == nil && (human.Password == nil || human.SecretString == "") {
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-9dk45", "Errors.User.Invalid")
}
return r.createHuman(ctx, orgID, human, externalIDP, true)
}
func (r *CommandSide) createHuman(ctx context.Context, orgID string, human *domain.Human, externalIDP *domain.ExternalIDP, selfregister bool) (*user.Aggregate, *HumanWriteModel, error) {
func (r *CommandSide) createHuman(ctx context.Context, orgID string, human *domain.Human, externalIDP *domain.ExternalIDP, selfregister bool) ([]eventstore.EventPusher, *HumanWriteModel, error) {
userID, err := r.idGenerator.Next()
if err != nil {
return nil, nil, err
@ -95,8 +103,6 @@ func (r *CommandSide) createHuman(ctx context.Context, orgID string, human *doma
if err != nil {
return nil, nil, err
}
addedHuman := NewHumanWriteModel(human.AggregateID, orgID)
if err := human.CheckOrgIAMPolicy(orgIAMPolicy); err != nil {
return nil, nil, err
}
@ -104,43 +110,48 @@ func (r *CommandSide) createHuman(ctx context.Context, orgID string, human *doma
if err := human.HashPasswordIfExisting(pwPolicy, r.userPasswordAlg, true); err != nil {
return nil, nil, err
}
addedHuman := NewHumanWriteModel(human.AggregateID, orgID)
//TODO: adlerhurst maybe we could simplify the code below
userAgg := UserAggregateFromWriteModel(&addedHuman.WriteModel)
var createEvent eventstore.EventPusher
var events []eventstore.EventPusher
if selfregister {
createEvent = createRegisterHumanEvent(ctx, orgID, human, orgIAMPolicy.UserLoginMustBeDomain)
events = append(events, createRegisterHumanEvent(ctx, userAgg, human, orgIAMPolicy.UserLoginMustBeDomain))
} else {
createEvent = createAddHumanEvent(ctx, orgID, human, orgIAMPolicy.UserLoginMustBeDomain)
events = append(events, createAddHumanEvent(ctx, userAgg, human, orgIAMPolicy.UserLoginMustBeDomain))
}
userAgg.PushEvents(createEvent)
if externalIDP != nil {
err = r.addHumanExternalIDP(ctx, userAgg, externalIDP)
event, err := r.addHumanExternalIDP(ctx, userAgg, externalIDP)
if err != nil {
return nil, nil, err
}
events = append(events, event)
}
if human.IsInitialState() {
initCode, err := domain.NewInitUserCode(r.initializeUserCode)
if err != nil {
return nil, nil, err
}
userAgg.PushEvents(user.NewHumanInitialCodeAddedEvent(ctx, initCode.Code, initCode.Expiry))
events = append(events, user.NewHumanInitialCodeAddedEvent(ctx, userAgg, initCode.Code, initCode.Expiry))
}
if human.Email != nil && human.EmailAddress != "" && human.IsEmailVerified {
userAgg.PushEvents(user.NewHumanEmailVerifiedEvent(ctx))
events = append(events, user.NewHumanEmailVerifiedEvent(ctx, userAgg))
}
if human.Phone != nil && human.PhoneNumber != "" && !human.IsPhoneVerified {
phoneCode, err := domain.NewPhoneCode(r.phoneVerificationCode)
if err != nil {
return nil, nil, err
}
userAgg.PushEvents(user.NewHumanPhoneCodeAddedEvent(ctx, phoneCode.Code, phoneCode.Expiry))
events = append(events, user.NewHumanPhoneCodeAddedEvent(ctx, userAgg, phoneCode.Code, phoneCode.Expiry))
} else if human.Phone != nil && human.PhoneNumber != "" && human.IsPhoneVerified {
userAgg.PushEvents(user.NewHumanPhoneVerifiedEvent(ctx))
events = append(events, user.NewHumanPhoneVerifiedEvent(ctx, userAgg))
}
return userAgg, addedHuman, nil
return events, addedHuman, nil
}
func (r *CommandSide) HumanSkipMFAInit(ctx context.Context, userID, resourceowner string) (err error) {
@ -152,18 +163,20 @@ func (r *CommandSide) HumanSkipMFAInit(ctx context.Context, userID, resourceowne
if err != nil {
return err
}
if existingHuman.UserState == domain.UserStateUnspecified || existingHuman.UserState == domain.UserStateDeleted {
if !isUserStateExists(existingHuman.UserState) {
return caos_errs.ThrowNotFound(nil, "COMMAND-m9cV8", "Errors.User.NotFound")
}
userAgg := UserAggregateFromWriteModel(&existingHuman.WriteModel)
userAgg.PushEvents(user.NewHumanMFAInitSkippedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingHuman, userAgg)
_, err = r.eventstore.PushEvents(ctx,
user.NewHumanMFAInitSkippedEvent(ctx, UserAggregateFromWriteModel(&existingHuman.WriteModel)))
return err
}
func createAddHumanEvent(ctx context.Context, orgID string, human *domain.Human, userLoginMustBeDomain bool) *user.HumanAddedEvent {
///TODO: adlerhurst maybe we can simplify createAddHumanEvent and createRegisterHumanEvent
func createAddHumanEvent(ctx context.Context, aggregate *eventstore.Aggregate, human *domain.Human, userLoginMustBeDomain bool) *user.HumanAddedEvent {
addEvent := user.NewHumanAddedEvent(
ctx,
orgID,
aggregate,
human.Username,
human.FirstName,
human.LastName,
@ -191,10 +204,10 @@ func createAddHumanEvent(ctx context.Context, orgID string, human *domain.Human,
return addEvent
}
func createRegisterHumanEvent(ctx context.Context, orgID string, human *domain.Human, userLoginMustBeDomain bool) *user.HumanRegisteredEvent {
func createRegisterHumanEvent(ctx context.Context, aggregate *eventstore.Aggregate, human *domain.Human, userLoginMustBeDomain bool) *user.HumanRegisteredEvent {
addEvent := user.NewHumanRegisteredEvent(
ctx,
orgID,
aggregate,
human.Username,
human.FirstName,
human.LastName,
@ -226,21 +239,22 @@ func (r *CommandSide) HumansSignOut(ctx context.Context, agentID string, userIDs
if agentID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M0ds", "Errors.User.UserIDMissing")
}
aggregates := make([]eventstore.Aggregater, len(userIDs))
events := make([]eventstore.EventPusher, len(userIDs))
for i, userID := range userIDs {
existingUser, err := r.getHumanWriteModelByID(ctx, userID, "")
if err != nil {
return err
}
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
if !isUserStateExists(existingUser.UserState) {
continue
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewHumanSignedOutEvent(ctx, agentID))
aggregates[i] = userAgg
events[i] = user.NewHumanSignedOutEvent(
ctx,
UserAggregateFromWriteModel(&existingUser.WriteModel),
agentID)
}
_, err := r.eventstore.PushAggregates(ctx, aggregates...)
_, err := r.eventstore.PushEvents(ctx, events...)
return err
}

@ -15,18 +15,19 @@ func (r *CommandSide) ChangeHumanAddress(ctx context.Context, address *domain.Ad
if existingAddress.State == domain.AddressStateUnspecified || existingAddress.State == domain.AddressStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-0pLdo", "Errors.User.Address.NotFound")
}
changedEvent, hasChanged := existingAddress.NewChangedEvent(ctx, address.Country, address.Locality, address.PostalCode, address.Region, address.StreetAddress)
userAgg := UserAggregateFromWriteModel(&existingAddress.WriteModel)
changedEvent, hasChanged := existingAddress.NewChangedEvent(ctx, userAgg, address.Country, address.Locality, address.PostalCode, address.Region, address.StreetAddress)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-3M0cs", "Errors.User.Address.NotChanged")
}
userAgg := UserAggregateFromWriteModel(&existingAddress.WriteModel)
userAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingAddress, userAgg)
pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingAddress, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToAddress(existingAddress), nil
}

@ -29,10 +29,6 @@ func NewHumanAddressWriteModel(userID, resourceOwner string) *HumanAddressWriteM
}
}
func (wm *HumanAddressWriteModel) AppendEvents(events ...eventstore.EventReader) {
wm.WriteModel.AppendEvents(events...)
}
func (wm *HumanAddressWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
@ -76,11 +72,16 @@ func (wm *HumanAddressWriteModel) Reduce() error {
func (wm *HumanAddressWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
ResourceOwner(wm.ResourceOwner).
EventTypes(user.HumanAddedType,
user.HumanRegisteredType,
user.HumanAddressChangedType,
user.UserRemovedType)
}
func (wm *HumanAddressWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
country,
locality,
postalCode,
@ -88,7 +89,7 @@ func (wm *HumanAddressWriteModel) NewChangedEvent(
streetAddress string,
) (*user.HumanAddressChangedEvent, bool) {
hasChanged := false
changedEvent := user.NewHumanAddressChangedEvent(ctx)
changedEvent := user.NewHumanAddressChangedEvent(ctx, aggregate)
if wm.Country != country {
hasChanged = true
changedEvent.Country = &country

Some files were not shown because too many files have changed in this diff Show More