feat: uniqueness (#1190)

* feat: uniqueness on events

* fix: some tests

* fix: add unique username

* fix: nice error message

* fix: add unique test

* fix: add unique test

* fix: add unique constraint to events

* fix: correct unique constraint on user events

* fix: remove user constraint

* fix: add unique constraints

* fix: add unique constraints

* fix: add unique constraints

* fix: unnique constraints without interface

* fix: unique idp config

* fix: unique constraint comments

* fix: unique constraints in one table

* fix: unique constraints error

* fix: fix unique constraint on create user

* fix: fix unique constraint on create project

* fix: fix unique constraint on idp configs
This commit is contained in:
Fabi 2021-01-21 10:49:38 +01:00 committed by GitHub
parent c2e6e782a8
commit 28bfe72930
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 1046 additions and 313 deletions

View File

@ -8,6 +8,7 @@ import (
context "context" context "context"
eventstore "github.com/caos/zitadel/internal/eventstore" eventstore "github.com/caos/zitadel/internal/eventstore"
models "github.com/caos/zitadel/internal/eventstore/models" models "github.com/caos/zitadel/internal/eventstore/models"
eventstore0 "github.com/caos/zitadel/internal/eventstore/v2"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
reflect "reflect" reflect "reflect"
) )
@ -129,3 +130,17 @@ func (mr *MockEventstoreMockRecorder) Subscribe(arg0 ...interface{}) *gomock.Cal
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockEventstore)(nil).Subscribe), arg0...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockEventstore)(nil).Subscribe), arg0...)
} }
// V2 mocks base method
func (m *MockEventstore) V2() *eventstore0.Eventstore {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "V2")
ret0, _ := ret[0].(*eventstore0.Eventstore)
return ret0
}
// V2 indicates an expected call of V2
func (mr *MockEventstoreMockRecorder) V2() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "V2", reflect.TypeOf((*MockEventstore)(nil).V2))
}

View File

@ -5,92 +5,11 @@
package mock package mock
import ( import (
models "github.com/caos/zitadel/internal/eventstore/models"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
reflect "reflect" reflect "reflect"
time "time" time "time"
) )
// MockHandler is a mock of Handler interface
type MockHandler struct {
ctrl *gomock.Controller
recorder *MockHandlerMockRecorder
}
// MockHandlerMockRecorder is the mock recorder for MockHandler
type MockHandlerMockRecorder struct {
mock *MockHandler
}
// NewMockHandler creates a new mock instance
func NewMockHandler(ctrl *gomock.Controller) *MockHandler {
mock := &MockHandler{ctrl: ctrl}
mock.recorder = &MockHandlerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockHandler) EXPECT() *MockHandlerMockRecorder {
return m.recorder
}
// ViewModel mocks base method
func (m *MockHandler) ViewModel() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ViewModel")
ret0, _ := ret[0].(string)
return ret0
}
// ViewModel indicates an expected call of ViewModel
func (mr *MockHandlerMockRecorder) ViewModel() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ViewModel", reflect.TypeOf((*MockHandler)(nil).ViewModel))
}
// EventQuery mocks base method
func (m *MockHandler) EventQuery() (*models.SearchQuery, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EventQuery")
ret0, _ := ret[0].(*models.SearchQuery)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EventQuery indicates an expected call of EventQuery
func (mr *MockHandlerMockRecorder) EventQuery() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EventQuery", reflect.TypeOf((*MockHandler)(nil).EventQuery))
}
// Reduce mocks base method
func (m *MockHandler) Process(arg0 *models.Event) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Reduce", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// Reduce indicates an expected call of Reduce
func (mr *MockHandlerMockRecorder) Process(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Reduce", reflect.TypeOf((*MockHandler)(nil).Process), arg0)
}
// MinimumCycleDuration mocks base method
func (m *MockHandler) MinimumCycleDuration() time.Duration {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "MinimumCycleDuration")
ret0, _ := ret[0].(time.Duration)
return ret0
}
// MinimumCycleDuration indicates an expected call of MinimumCycleDuration
func (mr *MockHandlerMockRecorder) MinimumCycleDuration() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MinimumCycleDuration", reflect.TypeOf((*MockHandler)(nil).MinimumCycleDuration))
}
// MockLocker is a mock of Locker interface // MockLocker is a mock of Locker interface
type MockLocker struct { type MockLocker struct {
ctrl *gomock.Controller ctrl *gomock.Controller

View File

@ -18,6 +18,8 @@ type EventPusher interface {
// * struct which can be marshalled to json // * struct which can be marshalled to json
// * pointer to struct which can be marshalled to json // * pointer to struct which can be marshalled to json
Data() interface{} Data() interface{}
//UniqueConstraints should be added for unique attributes of an event, if nil constraints will not be checked
UniqueConstraints() []*EventUniqueConstraint
} }
type EventReader interface { type EventReader interface {

View File

@ -81,3 +81,13 @@ func NewBaseEventForPush(ctx context.Context, typ EventType) *BaseEvent {
EventType: typ, 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,
}
}

View File

@ -50,12 +50,12 @@ func (es *Eventstore) PushAggregate(ctx context.Context, writeModel queryReducer
//PushAggregates maps the events of all aggregates to an eventstore event //PushAggregates maps the events of all aggregates to an eventstore event
// based on the pushMapper // based on the pushMapper
func (es *Eventstore) PushAggregates(ctx context.Context, aggregates ...Aggregater) ([]EventReader, error) { func (es *Eventstore) PushAggregates(ctx context.Context, aggregates ...Aggregater) ([]EventReader, error) {
events, err := es.aggregatesToEvents(aggregates) events, uniqueConstraints, err := es.aggregatesToEvents(aggregates)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = es.repo.Push(ctx, events...) err = es.repo.Push(ctx, events, uniqueConstraints...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -63,13 +63,14 @@ func (es *Eventstore) PushAggregates(ctx context.Context, aggregates ...Aggregat
return es.mapEvents(events) return es.mapEvents(events)
} }
func (es *Eventstore) aggregatesToEvents(aggregates []Aggregater) ([]*repository.Event, error) { func (es *Eventstore) aggregatesToEvents(aggregates []Aggregater) ([]*repository.Event, []*repository.UniqueConstraint, error) {
events := make([]*repository.Event, 0, len(aggregates)) events := make([]*repository.Event, 0, len(aggregates))
uniqueConstraints := make([]*repository.UniqueConstraint, 0)
for _, aggregate := range aggregates { for _, aggregate := range aggregates {
for _, event := range aggregate.Events() { for _, event := range aggregate.Events() {
data, err := eventData(event) data, err := eventData(event)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
events = append(events, &repository.Event{ events = append(events, &repository.Event{
AggregateID: aggregate.ID(), AggregateID: aggregate.ID(),
@ -81,9 +82,21 @@ func (es *Eventstore) aggregatesToEvents(aggregates []Aggregater) ([]*repository
Version: repository.Version(aggregate.Version()), Version: repository.Version(aggregate.Version()),
Data: data, 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,
},
)
}
}
} }
} }
return events, nil return events, uniqueConstraints, nil
} }
//FilterEvents filters the stored events based on the searchQuery //FilterEvents filters the stored events based on the searchQuery
@ -209,3 +222,14 @@ func eventData(event EventPusher) ([]byte, error) {
} }
return nil, errors.ThrowInvalidArgument(nil, "V2-91NRm", "wrong type of event data") return nil, errors.ThrowInvalidArgument(nil, "V2-91NRm", "wrong type of event data")
} }
func uniqueConstraintActionToRepository(action UniqueConstraintAction) repository.UniqueConstraintAction {
switch action {
case UniqueConstraintAdd:
return repository.UniqueConstraintAdd
case UniqueConstraintRemove:
return repository.UniqueConstraintRemoved
default:
return repository.UniqueConstraintAdd
}
}

View File

@ -63,6 +63,10 @@ func (e *testEvent) Data() interface{} {
return e.data() return e.data()
} }
func (e *testEvent) UniqueConstraint() []EventUniqueConstraint {
return nil
}
func testFilterMapper(event *repository.Event) (EventReader, error) { func testFilterMapper(event *repository.Event) (EventReader, error) {
if event == nil { if event == nil {
return newTestEvent("hodor", nil, false), nil return newTestEvent("hodor", nil, false), nil
@ -543,7 +547,7 @@ func TestEventstore_aggregatesToEvents(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
es := &Eventstore{} es := &Eventstore{}
events, err := es.aggregatesToEvents(tt.args.aggregates) events, _, err := es.aggregatesToEvents(tt.args.aggregates)
if (err != nil) != tt.res.wantErr { if (err != nil) != tt.res.wantErr {
t.Errorf("Eventstore.aggregatesToEvents() error = %v, wantErr %v", err, tt.res.wantErr) t.Errorf("Eventstore.aggregatesToEvents() error = %v, wantErr %v", err, tt.res.wantErr)
return return
@ -576,7 +580,7 @@ func (repo *testRepo) Health(ctx context.Context) error {
return nil return nil
} }
func (repo *testRepo) Push(ctx context.Context, events ...*repository.Event) error { func (repo *testRepo) Push(ctx context.Context, events []*repository.Event, uniqueConstraints ...*repository.UniqueConstraint) error {
if repo.err != nil { if repo.err != nil {
return repo.err return repo.err
} }

View File

@ -29,7 +29,6 @@ func NewUserAggregate(id string) *UserAggregate {
"test.user", "test.user",
"caos", "caos",
"v1", "v1",
0,
), ),
} }
} }
@ -84,6 +83,10 @@ func (e *UserAddedEvent) Data() interface{} {
return e return e
} }
func (e *UserAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
// ------------------------------------------------------------ // ------------------------------------------------------------
// User first name changed event start // User first name changed event start
// ------------------------------------------------------------ // ------------------------------------------------------------
@ -122,6 +125,10 @@ func (e *UserFirstNameChangedEvent) Data() interface{} {
return e return e
} }
func (e *UserFirstNameChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
// ------------------------------------------------------------ // ------------------------------------------------------------
// User password checked event start // User password checked event start
// ------------------------------------------------------------ // ------------------------------------------------------------
@ -152,6 +159,10 @@ func (e *UserPasswordCheckedEvent) Data() interface{} {
return nil return nil
} }
func (e *UserPasswordCheckedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
// ------------------------------------------------------------ // ------------------------------------------------------------
// User deleted event // User deleted event
// ------------------------------------------------------------ // ------------------------------------------------------------
@ -182,6 +193,10 @@ func (e *UserDeletedEvent) Data() interface{} {
return nil return nil
} }
func (e *UserDeletedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
// ------------------------------------------------------------ // ------------------------------------------------------------
// Users read model start // Users read model start
// ------------------------------------------------------------ // ------------------------------------------------------------

View File

@ -9,8 +9,9 @@ type Repository interface {
//Health checks if the connection to the storage is available //Health checks if the connection to the storage is available
Health(ctx context.Context) error Health(ctx context.Context) error
// PushEvents adds all events of the given aggregates to the eventstreams of the aggregates. // PushEvents adds all events of the given aggregates to the eventstreams of the aggregates.
// if unique constraints are pushed, they will be added to the unique table for checking unique constraint violations
// This call is transaction save. The transaction will be rolled back if one event fails // This call is transaction save. The transaction will be rolled back if one event fails
Push(ctx context.Context, events ...*Event) error Push(ctx context.Context, events []*Event, uniqueConstraints ...*UniqueConstraint) error
// Filter returns all events matching the given search query // Filter returns all events matching the given search query
Filter(ctx context.Context, searchQuery *SearchQuery) (events []*Event, err error) Filter(ctx context.Context, searchQuery *SearchQuery) (events []*Event, err error)
//LatestSequence returns the latests sequence found by the the search query //LatestSequence returns the latests sequence found by the the search query

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"database/sql" "database/sql"
"errors" "errors"
"github.com/lib/pq"
"regexp" "regexp"
"strconv" "strconv"
@ -88,6 +89,18 @@ const (
" FROM data " + " FROM data " +
" ) " + " ) " +
"RETURNING id, event_sequence, previous_sequence, creation_date, resource_owner" "RETURNING id, event_sequence, previous_sequence, creation_date, resource_owner"
uniqueInsert = `INSERT INTO eventstore.unique_constraints
(
unique_type,
unique_field
)
VALUES (
$1,
$2
)`
uniqueDelete = `DELETE FROM eventstore.unique_constraints
WHERE unique_type = $1 and unique_field = $2`
) )
type CRDB struct { type CRDB struct {
@ -102,7 +115,7 @@ func (db *CRDB) Health(ctx context.Context) error { return db.client.Ping() }
// Push adds all events to the eventstreams of the aggregates. // Push adds all events to the eventstreams of the aggregates.
// This call is transaction save. The transaction will be rolled back if one event fails // This call is transaction save. The transaction will be rolled back if one event fails
func (db *CRDB) Push(ctx context.Context, events ...*repository.Event) error { func (db *CRDB) Push(ctx context.Context, events []*repository.Event, uniqueConstraints ...*repository.UniqueConstraint) error {
err := crdb.ExecuteTx(ctx, db.client, nil, func(tx *sql.Tx) error { err := crdb.ExecuteTx(ctx, db.client, nil, func(tx *sql.Tx) error {
stmt, err := tx.PrepareContext(ctx, crdbInsert) stmt, err := tx.PrepareContext(ctx, crdbInsert)
if err != nil { if err != nil {
@ -136,6 +149,10 @@ func (db *CRDB) Push(ctx context.Context, events ...*repository.Event) error {
} }
} }
err = db.handleUniqueConstraints(ctx, tx, uniqueConstraints...)
if err != nil {
return err
}
return nil return nil
}) })
if err != nil && !errors.Is(err, &caos_errs.CaosError{}) { if err != nil && !errors.Is(err, &caos_errs.CaosError{}) {
@ -145,6 +162,39 @@ func (db *CRDB) Push(ctx context.Context, events ...*repository.Event) error {
return err return err
} }
// handleUniqueConstraints adds or removes unique constraints
func (db *CRDB) handleUniqueConstraints(ctx context.Context, tx *sql.Tx, uniqueConstraints ...*repository.UniqueConstraint) (err error) {
if uniqueConstraints == nil || len(uniqueConstraints) == 0 || (len(uniqueConstraints) == 1 && uniqueConstraints[0] == nil) {
return nil
}
for _, uniqueConstraint := range uniqueConstraints {
if uniqueConstraint.Action == repository.UniqueConstraintAdd {
_, err := tx.ExecContext(ctx, uniqueInsert, uniqueConstraint.UniqueType, uniqueConstraint.UniqueField)
if err != nil {
logging.LogWithFields("SQL-IP3js",
"unique_type", uniqueConstraint.UniqueType,
"unique_field", uniqueConstraint.UniqueField).WithError(err).Info("insert unique constraint failed")
if db.isUniqueViolationError(err) {
return caos_errs.ThrowAlreadyExists(err, "SQL-M0dsf", uniqueConstraint.ErrorMessage)
}
return caos_errs.ThrowInternal(err, "SQL-dM9ds", "unable to create unique constraint ")
}
} else if uniqueConstraint.Action == repository.UniqueConstraintRemoved {
_, err := tx.ExecContext(ctx, uniqueDelete, uniqueConstraint.UniqueType, uniqueConstraint.UniqueField)
if err != nil {
logging.LogWithFields("SQL-M0vsf",
"unique_type", uniqueConstraint.UniqueType,
"unique_field", uniqueConstraint.UniqueField).WithError(err).Info("delete unique constraint failed")
return caos_errs.ThrowInternal(err, "SQL-2M9fs", "unable to remove unique constraint ")
}
}
}
return nil
}
// Filter returns all events matching the given search query // Filter returns all events matching the given search query
func (db *CRDB) Filter(ctx context.Context, searchQuery *repository.SearchQuery) (events []*repository.Event, err error) { func (db *CRDB) Filter(ctx context.Context, searchQuery *repository.SearchQuery) (events []*repository.Event, err error) {
events = []*repository.Event{} events = []*repository.Event{}
@ -262,3 +312,12 @@ func (db *CRDB) placeholder(query string) string {
} }
return replaced return replaced
} }
func (db *CRDB) isUniqueViolationError(err error) bool {
if pqErr, ok := err.(*pq.Error); ok {
if pqErr.Code == "23505" {
return true
}
}
return false
}

View File

@ -266,11 +266,15 @@ func TestCRDB_columnName(t *testing.T) {
func TestCRDB_Push_OneAggregate(t *testing.T) { func TestCRDB_Push_OneAggregate(t *testing.T) {
type args struct { type args struct {
ctx context.Context ctx context.Context
events []*repository.Event events []*repository.Event
uniqueConstraints *repository.UniqueConstraint
uniqueDataType string
uniqueDataField string
} }
type eventsRes struct { type eventsRes struct {
pushedEventsCount int pushedEventsCount int
uniqueCount int
aggType repository.AggregateType aggType repository.AggregateType
aggID []string aggID []string
} }
@ -334,26 +338,84 @@ func TestCRDB_Push_OneAggregate(t *testing.T) {
}, },
}, },
}, },
{
name: "push 1 event and add unique constraint",
args: args{
ctx: context.Background(),
events: []*repository.Event{
generateEvent(t, "10"),
},
uniqueConstraints: generateAddUniqueConstraint(t, "usernames", "field"),
},
res: res{
wantErr: false,
eventsRes: eventsRes{
pushedEventsCount: 1,
uniqueCount: 1,
aggID: []string{"10"},
aggType: repository.AggregateType(t.Name()),
}},
},
{
name: "push 1 event and remove unique constraint",
args: args{
ctx: context.Background(),
events: []*repository.Event{
generateEvent(t, "11"),
},
uniqueConstraints: generateRemoveUniqueConstraint(t, "usernames", "testremove"),
uniqueDataType: "usernames",
uniqueDataField: "testremove",
},
res: res{
wantErr: false,
eventsRes: eventsRes{
pushedEventsCount: 1,
uniqueCount: 0,
aggID: []string{"11"},
aggType: repository.AggregateType(t.Name()),
}},
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
db := &CRDB{ db := &CRDB{
client: testCRDBClient, client: testCRDBClient,
} }
if err := db.Push(tt.args.ctx, tt.args.events...); (err != nil) != tt.res.wantErr { if tt.args.uniqueDataType != "" && tt.args.uniqueDataField != "" {
err := fillUniqueData(tt.args.uniqueDataType, tt.args.uniqueDataField)
if err != nil {
t.Error("unable to prefill insert unique data: ", err)
return
}
}
if err := db.Push(tt.args.ctx, tt.args.events, tt.args.uniqueConstraints); (err != nil) != tt.res.wantErr {
t.Errorf("CRDB.Push() error = %v, wantErr %v", err, tt.res.wantErr) t.Errorf("CRDB.Push() error = %v, wantErr %v", err, tt.res.wantErr)
} }
countRow := testCRDBClient.QueryRow("SELECT COUNT(*) FROM eventstore.events where aggregate_type = $1 AND aggregate_id = ANY($2)", tt.res.eventsRes.aggType, pq.Array(tt.res.eventsRes.aggID)) countEventRow := testCRDBClient.QueryRow("SELECT COUNT(*) FROM eventstore.events where aggregate_type = $1 AND aggregate_id = ANY($2)", tt.res.eventsRes.aggType, pq.Array(tt.res.eventsRes.aggID))
var count int var eventCount int
err := countRow.Scan(&count) err := countEventRow.Scan(&eventCount)
if err != nil { if err != nil {
t.Error("unable to query inserted rows: ", err) t.Error("unable to query inserted rows: ", err)
return return
} }
if count != tt.res.eventsRes.pushedEventsCount { if eventCount != tt.res.eventsRes.pushedEventsCount {
t.Errorf("expected push count %d got %d", tt.res.eventsRes.pushedEventsCount, count) t.Errorf("expected push count %d got %d", tt.res.eventsRes.pushedEventsCount, eventCount)
} }
if tt.args.uniqueConstraints != nil {
countUniqueRow := testCRDBClient.QueryRow("SELECT COUNT(*) FROM eventstore.unique_constraints where unique_type = $1 AND unique_field = $2", tt.args.uniqueConstraints.UniqueType, tt.args.uniqueConstraints.UniqueField)
var uniqueCount int
err := countUniqueRow.Scan(&uniqueCount)
if err != nil {
t.Error("unable to query inserted rows: ", err)
return
}
if uniqueCount != tt.res.eventsRes.uniqueCount {
t.Errorf("expected unique count %d got %d", tt.res.eventsRes.uniqueCount, uniqueCount)
}
}
}) })
} }
} }
@ -445,7 +507,7 @@ func TestCRDB_Push_MultipleAggregate(t *testing.T) {
db := &CRDB{ db := &CRDB{
client: testCRDBClient, client: testCRDBClient,
} }
if err := db.Push(context.Background(), tt.args.events...); (err != nil) != tt.res.wantErr { if err := db.Push(context.Background(), tt.args.events); (err != nil) != tt.res.wantErr {
t.Errorf("CRDB.Push() error = %v, wantErr %v", err, tt.res.wantErr) t.Errorf("CRDB.Push() error = %v, wantErr %v", err, tt.res.wantErr)
} }
@ -616,7 +678,7 @@ func TestCRDB_Push_Parallel(t *testing.T) {
for _, events := range tt.args.events { for _, events := range tt.args.events {
wg.Add(1) wg.Add(1)
go func(events []*repository.Event) { go func(events []*repository.Event) {
err := db.Push(context.Background(), events...) err := db.Push(context.Background(), events)
if err != nil { if err != nil {
errsMu.Lock() errsMu.Lock()
errs = append(errs, err) errs = append(errs, err)
@ -728,7 +790,7 @@ func TestCRDB_Filter(t *testing.T) {
} }
// setup initial data for query // setup initial data for query
if err := db.Push(context.Background(), tt.fields.existingEvents...); err != nil { if err := db.Push(context.Background(), tt.fields.existingEvents); err != nil {
t.Errorf("error in setup = %v", err) t.Errorf("error in setup = %v", err)
return return
} }
@ -814,7 +876,7 @@ func TestCRDB_LatestSequence(t *testing.T) {
} }
// setup initial data for query // setup initial data for query
if err := db.Push(context.Background(), tt.fields.existingEvents...); err != nil { if err := db.Push(context.Background(), tt.fields.existingEvents); err != nil {
t.Errorf("error in setup = %v", err) t.Errorf("error in setup = %v", err)
return return
} }
@ -956,7 +1018,7 @@ func TestCRDB_Push_ResourceOwner(t *testing.T) {
db := &CRDB{ db := &CRDB{
client: testCRDBClient, client: testCRDBClient,
} }
if err := db.Push(context.Background(), tt.args.events...); err != nil { if err := db.Push(context.Background(), tt.args.events); err != nil {
t.Errorf("CRDB.Push() error = %v", err) t.Errorf("CRDB.Push() error = %v", err)
} }
@ -1036,3 +1098,25 @@ func generateEventWithData(t *testing.T, aggregateID string, data []byte) *repos
Data: data, Data: data,
} }
} }
func generateAddUniqueConstraint(t *testing.T, table, uniqueField string) *repository.UniqueConstraint {
t.Helper()
e := &repository.UniqueConstraint{
UniqueType: table,
UniqueField: uniqueField,
Action: repository.UniqueConstraintAdd,
}
return e
}
func generateRemoveUniqueConstraint(t *testing.T, table, uniqueField string) *repository.UniqueConstraint {
t.Helper()
e := &repository.UniqueConstraint{
UniqueType: table,
UniqueField: uniqueField,
Action: repository.UniqueConstraintRemoved,
}
return e
}

View File

@ -80,6 +80,11 @@ func executeMigrations() error {
return nil return nil
} }
func fillUniqueData(unique_type, field string) error {
_, err := testCRDBClient.Exec("INSERT INTO eventstore.unique_constraints (unique_type, unique_field) VALUES ($1, $2)", unique_type, field)
return err
}
type migrationPaths []string type migrationPaths []string
type version struct { type version struct {

View File

@ -521,7 +521,7 @@ func Test_query_events_with_crdb(t *testing.T) {
} }
// setup initial data for query // setup initial data for query
if err := db.Push(context.Background(), tt.fields.existingEvents...); err != nil { if err := db.Push(context.Background(), tt.fields.existingEvents); err != nil {
t.Errorf("error in setup = %v", err) t.Errorf("error in setup = %v", err)
return return
} }

View File

@ -0,0 +1,29 @@
package repository
//UniqueCheck represents all information about a unique attribute
type UniqueConstraint struct {
//UniqueField is the field which should be unique
UniqueField string
//UniqueType is the type of the unique field
UniqueType string
//Action defines if unique constraint should be added or removed
Action UniqueConstraintAction
//ErrorMessage is the message key which should be returned if constraint is violated
ErrorMessage string
}
type UniqueConstraintAction int32
const (
UniqueConstraintAdd UniqueConstraintAction = iota
UniqueConstraintRemoved
uniqueConstraintActionCount
)
func (f UniqueConstraintAction) Valid() bool {
return f >= 0 && f < uniqueConstraintActionCount
}

View File

@ -0,0 +1,43 @@
package eventstore
type EventUniqueConstraint struct {
// UniqueType is the table name for the unique constraint
UniqueType string
//UniqueField is the unique key
UniqueField string
//Action defines if unique constraint should be added or removed
Action UniqueConstraintAction
//ErrorMessage defines the translation file key for the error message
ErrorMessage string
}
type UniqueConstraintAction int32
const (
UniqueConstraintAdd UniqueConstraintAction = iota
UniqueConstraintRemove
uniqueConstraintActionCount
)
func NewAddEventUniqueConstraint(
uniqueType,
uniqueField,
errMessage string) *EventUniqueConstraint {
return &EventUniqueConstraint{
UniqueType: uniqueType,
UniqueField: uniqueField,
ErrorMessage: errMessage,
Action: UniqueConstraintAdd,
}
}
func NewRemoveEventUniqueConstraint(
uniqueType,
uniqueField string) *EventUniqueConstraint {
return &EventUniqueConstraint{
UniqueType: uniqueType,
UniqueField: uniqueField,
Action: UniqueConstraintRemove,
}
}

View File

@ -76,78 +76,79 @@ func TestIamByID(t *testing.T) {
} }
} }
func TestSetUpStarted(t *testing.T) { //
ctrl := gomock.NewController(t) //func TestSetUpStarted(t *testing.T) {
type args struct { // ctrl := gomock.NewController(t)
es *IAMEventstore // type args struct {
ctx context.Context // es *IAMEventstore
iamID string // ctx context.Context
step iam_model.Step // iamID string
} // step iam_model.Step
type res struct { // }
iam *iam_model.IAM // type res struct {
errFunc func(err error) bool // iam *iam_model.IAM
} // errFunc func(err error) bool
tests := []struct { // }
name string // tests := []struct {
args args // name string
res res // args args
}{ // res res
{ // }{
name: "setup started iam, ok", // {
args: args{ // name: "setup started iam, ok",
es: GetMockManipulateIAMNotExisting(ctrl), // args: args{
ctx: authz.NewMockContext("orgID", "userID"), // es: GetMockManipulateIAMNotExisting(ctrl),
iamID: "iamID", // ctx: authz.NewMockContext("orgID", "userID"),
step: iam_model.Step1, // iamID: "iamID",
}, // step: iam_model.Step1,
res: res{ // },
iam: &iam_model.IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: iam_model.Step1}, // res: res{
}, // iam: &iam_model.IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: iam_model.Step1},
}, // },
{ // },
name: "setup already started", // {
args: args{ // name: "setup already started",
es: GetMockManipulateIAM(ctrl), // args: args{
ctx: authz.NewMockContext("orgID", "userID"), // es: GetMockManipulateIAM(ctrl),
iamID: "iamID", // ctx: authz.NewMockContext("orgID", "userID"),
step: iam_model.Step1, // iamID: "iamID",
}, // step: iam_model.Step1,
res: res{ // },
errFunc: caos_errs.IsPreconditionFailed, // res: res{
}, // errFunc: caos_errs.IsPreconditionFailed,
}, // },
{ // },
name: "setup iam no id", // {
args: args{ // name: "setup iam no id",
es: GetMockManipulateIAM(ctrl), // args: args{
ctx: authz.NewMockContext("orgID", "userID"), // es: GetMockManipulateIAM(ctrl),
step: iam_model.Step1, // ctx: authz.NewMockContext("orgID", "userID"),
}, // step: iam_model.Step1,
res: res{ // },
errFunc: caos_errs.IsPreconditionFailed, // res: res{
}, // errFunc: caos_errs.IsPreconditionFailed,
}, // },
} // },
for _, tt := range tests { // }
t.Run(tt.name, func(t *testing.T) { // for _, tt := range tests {
result, err := tt.args.es.StartSetup(tt.args.ctx, tt.args.iamID, tt.args.step) // t.Run(tt.name, func(t *testing.T) {
if (tt.res.errFunc != nil && !tt.res.errFunc(err)) || (err != nil && tt.res.errFunc == nil) { // result, err := tt.args.es.StartSetup(tt.args.ctx, tt.args.iamID, tt.args.step)
t.Errorf("got wrong err: %v ", err) // if (tt.res.errFunc != nil && !tt.res.errFunc(err)) || (err != nil && tt.res.errFunc == nil) {
return // t.Errorf("got wrong err: %v ", err)
} // return
if tt.res.errFunc != nil && tt.res.errFunc(err) { // }
return // if tt.res.errFunc != nil && tt.res.errFunc(err) {
} // return
if result.AggregateID == "" { // }
t.Errorf("result has no id") // if result.AggregateID == "" {
} // t.Errorf("result has no id")
if result.SetUpStarted != tt.res.iam.SetUpStarted { // }
t.Errorf("got wrong result setupStarted: expected: %v, actual: %v ", tt.res.iam.SetUpStarted, result.SetUpStarted) // if result.SetUpStarted != tt.res.iam.SetUpStarted {
} // t.Errorf("got wrong result setupStarted: expected: %v, actual: %v ", tt.res.iam.SetUpStarted, result.SetUpStarted)
}) // }
} // })
} // }
//}
func TestSetUpDone(t *testing.T) { func TestSetUpDone(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
@ -2731,7 +2732,7 @@ func TestAddOrgIAMPolicy(t *testing.T) {
return return
} }
if result.UserLoginMustBeDomain != tt.res.result.UserLoginMustBeDomain { if result.UserLoginMustBeDomain != tt.res.result.UserLoginMustBeDomain {
t.Errorf("got wrong result UserLoginMustBeDomain: expected: %v, actual: %v ", tt.res.result.UserLoginMustBeDomain, result.UserLoginMustBeDomain) t.Errorf("got wrong result userLoginMustBeDomain: expected: %v, actual: %v ", tt.res.result.UserLoginMustBeDomain, result.UserLoginMustBeDomain)
} }
}) })
} }
@ -2810,7 +2811,7 @@ func TestChangeOrgIAMPolicy(t *testing.T) {
return return
} }
if result.UserLoginMustBeDomain != tt.res.result.UserLoginMustBeDomain { if result.UserLoginMustBeDomain != tt.res.result.UserLoginMustBeDomain {
t.Errorf("got wrong result UserLoginMustBeDomain: expected: %v, actual: %v ", tt.res.result.UserLoginMustBeDomain, result.UserLoginMustBeDomain) t.Errorf("got wrong result userLoginMustBeDomain: expected: %v, actual: %v ", tt.res.result.UserLoginMustBeDomain, result.UserLoginMustBeDomain)
} }
}) })
} }

View File

@ -5,6 +5,7 @@ Errors:
IDMissing: ID fehlt IDMissing: ID fehlt
User: User:
NotFound: Benutzer konnte nicht gefunden werden NotFound: Benutzer konnte nicht gefunden werden
AlreadyExists: Benutzer existierts bereits
NotFoundOnOrg: Benutzer konnte in der gewünschten Organisation nicht gefunden werden NotFoundOnOrg: Benutzer konnte in der gewünschten Organisation nicht gefunden werden
NotAllowedOrg: Benutzer gehört nicht der benötigten Organisation an NotAllowedOrg: Benutzer gehört nicht der benötigten Organisation an
UserIDMissing: User ID fehlt UserIDMissing: User ID fehlt
@ -41,6 +42,7 @@ Errors:
NotMachine: Der Benutzer muss technisch sein NotMachine: Der Benutzer muss technisch sein
NotAllowedToLink: Der Benutzer darf nicht mit einem externen Login Provider verlinkt werden NotAllowedToLink: Der Benutzer darf nicht mit einem externen Login Provider verlinkt werden
Username: Username:
AlreadyExists: Benutzername ist bereits vergeben
Reservied: Benutzername ist bereits vergeben Reservied: Benutzername ist bereits vergeben
Code: Code:
Empty: Code ist leer Empty: Code ist leer
@ -64,6 +66,7 @@ Errors:
IDPConfigNotExisting: IDP Provider ungültig für diese Organisation IDPConfigNotExisting: IDP Provider ungültig für diese Organisation
NotAllowed: Externer IDP ist auf dieser Organisation nicht erlaubt. NotAllowed: Externer IDP ist auf dieser Organisation nicht erlaubt.
MinimumExternalIDPNeeded: Mindestens ein IDP muss hinzugefügt werden. MinimumExternalIDPNeeded: Mindestens ein IDP muss hinzugefügt werden.
AlreadyExists: External IDP ist bereits vergeben
MFA: MFA:
OTP: OTP:
AlreadyReady: Multifaktor OTP (OneTimePassword) ist bereits eingerichtet AlreadyReady: Multifaktor OTP (OneTimePassword) ist bereits eingerichtet
@ -84,6 +87,7 @@ Errors:
ValidateLoginFailed: Zugangsdaten konnten nicht validiert werden ValidateLoginFailed: Zugangsdaten konnten nicht validiert werden
CloneWarning: Authentifizierungsdaten wurden möglicherweise geklont CloneWarning: Authentifizierungsdaten wurden möglicherweise geklont
Org: Org:
AlreadyExist: Organisationsname existiert bereits
Invalid: Organisation ist ungültig Invalid: Organisation ist ungültig
AlreadyDeactivated: Organisation ist bereits deaktiviert AlreadyDeactivated: Organisation ist bereits deaktiviert
AlreadyActive: Organisation ist bereits aktiv AlreadyActive: Organisation ist bereits aktiv
@ -250,6 +254,8 @@ Errors:
NotActive: Benutzer Berechtigung ist nicht aktiv NotActive: Benutzer Berechtigung ist nicht aktiv
NotInactive: Benutzer Berechtigung ist nicht deaktiviert NotInactive: Benutzer Berechtigung ist nicht deaktiviert
NoPermissionForProject: Benutzer hat keine Rechte auf diesem Projekt NoPermissionForProject: Benutzer hat keine Rechte auf diesem Projekt
IDPConfig:
AlreadyExists: IDP Konfiguration mit diesem Name existiert bereits
Changes: Changes:
NotFound: Es konnte kein Änderungsverlauf gefunden werden NotFound: Es konnte kein Änderungsverlauf gefunden werden
Token: Token:

View File

@ -5,6 +5,7 @@ Errors:
IDMissing: ID missing IDMissing: ID missing
User: User:
NotFound: User could not be found NotFound: User could not be found
AlreadyExists: User already exists
NotFoundOnOrg: User could not be found on chosen organisation NotFoundOnOrg: User could not be found on chosen organisation
NotAllowedOrg: User is no member of the required organisation NotAllowedOrg: User is no member of the required organisation
UserIDMissing: User ID missing UserIDMissing: User ID missing
@ -41,6 +42,7 @@ Errors:
NotMachine: The User must be technical NotMachine: The User must be technical
NotAllowedToLink: User is not allowed to link with external login provider NotAllowedToLink: User is not allowed to link with external login provider
Username: Username:
AlreadyExists: Username already taken
Reservied: Username is already taken Reservied: Username is already taken
Code: Code:
Empty: Code is empty Empty: Code is empty
@ -64,6 +66,7 @@ Errors:
IDPConfigNotExisting: IDP provider invalid for this organisation IDPConfigNotExisting: IDP provider invalid for this organisation
NotAllowed: External IDP not allowed on this organisation NotAllowed: External IDP not allowed on this organisation
MinimumExternalIDPNeeded: At least one IDP must be added MinimumExternalIDPNeeded: At least one IDP must be added
AlreadyExists: External IDP already taken
MFA: MFA:
OTP: OTP:
AlreadyReady: Multifactor OTP (OneTimePassword) is already set up AlreadyReady: Multifactor OTP (OneTimePassword) is already set up
@ -84,6 +87,7 @@ Errors:
ValidateLoginFailed: Error on validate login credentials ValidateLoginFailed: Error on validate login credentials
CloneWarning: Credentials may be cloned CloneWarning: Credentials may be cloned
Org: Org:
AlreadyExist: Organisationname already taken
Invalid: Organisation is invalid Invalid: Organisation is invalid
AlreadyDeactivated: Organisation is already deactivated AlreadyDeactivated: Organisation is already deactivated
AlreadyActive: Organisation is already ative AlreadyActive: Organisation is already ative
@ -247,6 +251,8 @@ Errors:
NotActive: User grant is not active NotActive: User grant is not active
NotInactive: User grant is not deactivated NotInactive: User grant is not deactivated
NoPermissionForProject: User has no permissions on this project NoPermissionForProject: User has no permissions on this project
IDPConfig:
AlreadyExists: IDP Configuration with this name already exists
Changes: Changes:
NotFound: No history found NotFound: No history found
Token: Token:

View File

@ -9,7 +9,6 @@ import (
"github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/repository/iam"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
) )
@ -110,27 +109,17 @@ func (r *CommandSide) ReactivateDefaultIDPConfig(ctx context.Context, idpID stri
} }
func (r *CommandSide) RemoveDefaultIDPConfig(ctx context.Context, idpID string) error { func (r *CommandSide) RemoveDefaultIDPConfig(ctx context.Context, idpID string) error {
_, err := r.pushDefaultIDPWriteModel(ctx, idpID, func(a *iam.Aggregate, _ *IAMIDPConfigWriteModel) *iam.Aggregate { existingIDP, err := r.iamIDPConfigWriteModelByID(ctx, idpID)
a.Aggregate = *a.PushEvents(iam_repo.NewIDPConfigRemovedEvent(ctx, idpID))
return a
})
return err
}
func (r *CommandSide) pushDefaultIDPWriteModel(ctx context.Context, idpID string, eventSetter func(*iam.Aggregate, *IAMIDPConfigWriteModel) *iam.Aggregate) (*IAMIDPConfigWriteModel, error) {
writeModel := NewIAMIDPConfigWriteModel(idpID)
err := r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil { if err != nil {
return nil, err return err
} }
if existingIDP.State == domain.IDPConfigStateRemoved || existingIDP.State == domain.IDPConfigStateUnspecified {
aggregate := eventSetter(IAMAggregateFromWriteModel(&writeModel.WriteModel), writeModel) return caos_errs.ThrowNotFound(nil, "IAM-4M0xy", "Errors.IAM.IDPConfig.NotExisting")
err = r.eventstore.PushAggregate(ctx, writeModel, aggregate)
if err != nil {
return nil, err
} }
iamAgg := IAMAggregateFromWriteModel(&existingIDP.WriteModel)
iamAgg.PushEvents(iam_repo.NewIDPConfigRemovedEvent(ctx, existingIDP.ResourceOwner, idpID, existingIDP.Name))
return writeModel, nil return r.eventstore.PushAggregate(ctx, existingIDP, iamAgg)
} }
func (r *CommandSide) iamIDPConfigWriteModelByID(ctx context.Context, idpID string) (policy *IAMIDPConfigWriteModel, err error) { func (r *CommandSide) iamIDPConfigWriteModelByID(ctx context.Context, idpID string) (policy *IAMIDPConfigWriteModel, err error) {

View File

@ -122,7 +122,6 @@ func (r *CommandSide) addOrg(ctx context.Context, organisation *domain.Org) (_ *
addedOrg := NewOrgWriteModel(organisation.AggregateID) addedOrg := NewOrgWriteModel(organisation.AggregateID)
orgAgg := OrgAggregateFromWriteModel(&addedOrg.WriteModel) orgAgg := OrgAggregateFromWriteModel(&addedOrg.WriteModel)
//TODO: uniqueness org name
orgAgg.PushEvents(org.NewOrgAddedEvent(ctx, organisation.Name)) orgAgg.PushEvents(org.NewOrgAddedEvent(ctx, organisation.Name))
for _, orgDomain := range organisation.Domains { for _, orgDomain := range organisation.Domains {
if err := r.addOrgDomain(ctx, orgAgg, NewOrgDomainWriteModel(orgAgg.ID(), orgDomain.Domain), orgDomain); err != nil { if err := r.addOrgDomain(ctx, orgAgg, NewOrgDomainWriteModel(orgAgg.ID(), orgDomain.Domain), orgDomain); err != nil {

View File

@ -9,7 +9,6 @@ import (
"github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/repository/org"
org_repo "github.com/caos/zitadel/internal/v2/repository/org" org_repo "github.com/caos/zitadel/internal/v2/repository/org"
) )
@ -34,6 +33,7 @@ func (r *CommandSide) AddIDPConfig(ctx context.Context, config *domain.IDPConfig
orgAgg.PushEvents( orgAgg.PushEvents(
org_repo.NewIDPConfigAddedEvent( org_repo.NewIDPConfigAddedEvent(
ctx, ctx,
orgAgg.ResourceOwner(),
idpConfigID, idpConfigID,
config.Name, config.Name,
config.Type, config.Type,
@ -110,27 +110,21 @@ func (r *CommandSide) ReactivateIDPConfig(ctx context.Context, idpID, orgID stri
} }
func (r *CommandSide) RemoveIDPConfig(ctx context.Context, idpID, orgID string) error { func (r *CommandSide) RemoveIDPConfig(ctx context.Context, idpID, orgID string) error {
_, err := r.pushIDPWriteModel(ctx, idpID, orgID, func(a *org.Aggregate, _ *OrgIDPConfigWriteModel) *org.Aggregate { existingIDP, err := r.orgIDPConfigWriteModelByID(ctx, idpID, orgID)
a.Aggregate = *a.PushEvents(org_repo.NewIDPConfigRemovedEvent(ctx, idpID))
return a
})
return err
}
func (r *CommandSide) pushIDPWriteModel(ctx context.Context, idpID, orgID string, eventSetter func(*org.Aggregate, *OrgIDPConfigWriteModel) *org.Aggregate) (*OrgIDPConfigWriteModel, error) {
writeModel := NewOrgIDPConfigWriteModel(idpID, orgID)
err := r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil { if err != nil {
return nil, err return err
} }
aggregate := eventSetter(OrgAggregateFromWriteModel(&writeModel.WriteModel), writeModel) if existingIDP.State == domain.IDPConfigStateRemoved || existingIDP.State == domain.IDPConfigStateUnspecified {
err = r.eventstore.PushAggregate(ctx, writeModel, aggregate) return caos_errs.ThrowNotFound(nil, "Org-Yx9vd", "Errors.Org.IDPConfig.NotExisting")
if err != nil {
return nil, err
} }
if existingIDP.State != domain.IDPConfigStateInactive {
return caos_errs.ThrowPreconditionFailed(nil, "Org-5Mo0d", "Errors.Org.IDPConfig.NotInactive")
}
orgAgg := OrgAggregateFromWriteModel(&existingIDP.WriteModel)
orgAgg.PushEvents(org_repo.NewIDPConfigRemovedEvent(ctx, existingIDP.ResourceOwner, idpID, existingIDP.Name))
return writeModel, nil return r.eventstore.PushAggregate(ctx, existingIDP, orgAgg)
} }
func (r *CommandSide) orgIDPConfigWriteModelByID(ctx context.Context, idpID, orgID string) (policy *OrgIDPConfigWriteModel, err error) { func (r *CommandSide) orgIDPConfigWriteModelByID(ctx context.Context, idpID, orgID string) (policy *OrgIDPConfigWriteModel, err error) {

View File

@ -29,7 +29,6 @@ func (r *CommandSide) addProject(ctx context.Context, projectAdd *domain.Project
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
// TODO: Add uniqueness check
addedProject := NewProjectWriteModel(projectAdd.AggregateID, resourceOwner) addedProject := NewProjectWriteModel(projectAdd.AggregateID, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&addedProject.WriteModel) projectAgg := ProjectAggregateFromWriteModel(&addedProject.WriteModel)
@ -38,7 +37,7 @@ func (r *CommandSide) addProject(ctx context.Context, projectAdd *domain.Project
// projectRole = domain.RoleProjectOwnerGlobal // projectRole = domain.RoleProjectOwnerGlobal
//} //}
projectAgg.PushEvents( projectAgg.PushEvents(
project.NewProjectAddedEvent(ctx, projectAdd.Name), project.NewProjectAddedEvent(ctx, projectAdd.Name, resourceOwner),
project.NewMemberAddedEvent(ctx, ownerUserID, projectRole), project.NewMemberAddedEvent(ctx, ownerUserID, projectRole),
) )
return projectAgg, addedProject, nil return projectAgg, addedProject, nil

View File

@ -88,7 +88,7 @@ func (r *CommandSide) setup(ctx context.Context, step Step, iamAggregateProvider
_, err = r.eventstore.PushAggregates(ctx, iamAgg) _, err = r.eventstore.PushAggregates(ctx, iamAgg)
if err != nil { if err != nil {
return caos_errs.ThrowPreconditionFailedf(nil, "EVENT-dbG31", "Setup %s failed", step.Step()) return caos_errs.ThrowPreconditionFailedf(nil, "EVENT-dbG31", "Setup %v failed", step.Step())
} }
logging.LogWithFields("SETUP-Sg1t1", "step", step.Step()).Info("setup step done") logging.LogWithFields("SETUP-Sg1t1", "step", step.Step()).Info("setup step done")
return nil return nil

View File

@ -32,9 +32,7 @@ func (r *CommandSide) ChangeUsername(ctx context.Context, orgID, userID, userNam
return err return err
} }
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel) userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUsernameChangedEvent(ctx, userName)) userAgg.PushEvents(user.NewUsernameChangedEvent(ctx, existingUser.UserName, userName, orgIAMPolicy.UserLoginMustBeDomain))
//TODO: Check Uniqueness
//TODO: release old username, set new unique username
return r.eventstore.PushAggregate(ctx, existingUser, userAgg) return r.eventstore.PushAggregate(ctx, existingUser, userAgg)
} }
@ -130,9 +128,12 @@ func (r *CommandSide) RemoveUser(ctx context.Context, userID, resourceOwner stri
if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted { if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted {
return caos_errs.ThrowNotFound(nil, "COMMAND-5M0od", "Errors.User.NotFound") return caos_errs.ThrowNotFound(nil, "COMMAND-5M0od", "Errors.User.NotFound")
} }
orgIAMPolicy, err := r.getOrgIAMPolicy(ctx, existingUser.ResourceOwner)
if err != nil {
return err
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel) userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserRemovedEvent(ctx)) userAgg.PushEvents(user.NewUserRemovedEvent(ctx, existingUser.ResourceOwner, existingUser.UserName, orgIAMPolicy.UserLoginMustBeDomain))
//TODO: release unqie username
//TODO: remove user grants //TODO: remove user grants
return r.eventstore.PushAggregate(ctx, existingUser, userAgg) return r.eventstore.PushAggregate(ctx, existingUser, userAgg)

View File

@ -27,6 +27,9 @@ func (r *CommandSide) AddHuman(ctx context.Context, orgID string, human *domain.
} }
err = r.eventstore.PushAggregate(ctx, addedHuman, userAgg) err = r.eventstore.PushAggregate(ctx, addedHuman, userAgg)
if err != nil { if err != nil {
if caos_errs.IsErrorAlreadyExists(err) {
return nil, caos_errs.ThrowAlreadyExists(err, "COMMAND-4kSff", "Errors.User.AlreadyExists")
}
return nil, err return nil, err
} }
@ -47,6 +50,9 @@ func (r *CommandSide) RegisterHuman(ctx context.Context, orgID string, human *do
} }
err = r.eventstore.PushAggregate(ctx, addedHuman, userAgg) err = r.eventstore.PushAggregate(ctx, addedHuman, userAgg)
if err != nil { if err != nil {
if caos_errs.IsErrorAlreadyExists(err) {
return nil, caos_errs.ThrowAlreadyExists(err, "COMMAND-4kSff", "Errors.User.AlreadyExists")
}
return nil, err return nil, err
} }
@ -76,7 +82,6 @@ func (r *CommandSide) createHuman(ctx context.Context, orgID string, human *doma
} }
addedHuman := NewHumanWriteModel(human.AggregateID, orgID) addedHuman := NewHumanWriteModel(human.AggregateID, orgID)
//TODO: Check Unique Username or unique external idp
if err := human.CheckOrgIAMPolicy(human.Username, orgIAMPolicy); err != nil { if err := human.CheckOrgIAMPolicy(human.Username, orgIAMPolicy); err != nil {
return nil, nil, err return nil, nil, err
} }
@ -88,9 +93,9 @@ func (r *CommandSide) createHuman(ctx context.Context, orgID string, human *doma
userAgg := UserAggregateFromWriteModel(&addedHuman.WriteModel) userAgg := UserAggregateFromWriteModel(&addedHuman.WriteModel)
var createEvent eventstore.EventPusher var createEvent eventstore.EventPusher
if selfregister { if selfregister {
createEvent = createRegisterHumanEvent(ctx, human.Username, human) createEvent = createRegisterHumanEvent(ctx, orgID, human, orgIAMPolicy.UserLoginMustBeDomain)
} else { } else {
createEvent = createAddHumanEvent(ctx, human.Username, human) createEvent = createAddHumanEvent(ctx, orgID, human, orgIAMPolicy.UserLoginMustBeDomain)
} }
userAgg.PushEvents(createEvent) userAgg.PushEvents(createEvent)
@ -152,10 +157,11 @@ func (r *CommandSide) ResendInitialMail(ctx context.Context, userID, email, reso
return r.eventstore.PushAggregate(ctx, existingEmail, userAgg) return r.eventstore.PushAggregate(ctx, existingEmail, userAgg)
} }
func createAddHumanEvent(ctx context.Context, username string, human *domain.Human) *user.HumanAddedEvent { func createAddHumanEvent(ctx context.Context, orgID string, human *domain.Human, userLoginMustBeDomain bool) *user.HumanAddedEvent {
addEvent := user.NewHumanAddedEvent( addEvent := user.NewHumanAddedEvent(
ctx, ctx,
username, orgID,
human.Username,
human.FirstName, human.FirstName,
human.LastName, human.LastName,
human.NickName, human.NickName,
@ -163,6 +169,7 @@ func createAddHumanEvent(ctx context.Context, username string, human *domain.Hum
human.PreferredLanguage, human.PreferredLanguage,
human.Gender, human.Gender,
human.EmailAddress, human.EmailAddress,
userLoginMustBeDomain,
) )
if human.Phone != nil { if human.Phone != nil {
addEvent.AddPhoneData(human.PhoneNumber) addEvent.AddPhoneData(human.PhoneNumber)
@ -181,10 +188,11 @@ func createAddHumanEvent(ctx context.Context, username string, human *domain.Hum
return addEvent return addEvent
} }
func createRegisterHumanEvent(ctx context.Context, username string, human *domain.Human) *user.HumanRegisteredEvent { func createRegisterHumanEvent(ctx context.Context, orgID string, human *domain.Human, userLoginMustBeDomain bool) *user.HumanRegisteredEvent {
addEvent := user.NewHumanRegisteredEvent( addEvent := user.NewHumanRegisteredEvent(
ctx, ctx,
username, orgID,
human.Username,
human.FirstName, human.FirstName,
human.LastName, human.LastName,
human.NickName, human.NickName,
@ -192,6 +200,7 @@ func createRegisterHumanEvent(ctx context.Context, username string, human *domai
human.PreferredLanguage, human.PreferredLanguage,
human.Gender, human.Gender,
human.EmailAddress, human.EmailAddress,
userLoginMustBeDomain,
) )
if human.Phone != nil { if human.Phone != nil {
addEvent.AddPhoneData(human.PhoneNumber) addEvent.AddPhoneData(human.PhoneNumber)

View File

@ -34,8 +34,6 @@ func (r *CommandSide) removeHumanExternalIDP(ctx context.Context, externalIDP *d
user.NewHumanExternalIDPCascadeRemovedEvent(ctx, externalIDP.IDPConfigID, externalIDP.ExternalUserID), user.NewHumanExternalIDPCascadeRemovedEvent(ctx, externalIDP.IDPConfigID, externalIDP.ExternalUserID),
) )
} }
//TODO: Release unique externalidp
return r.eventstore.PushAggregate(ctx, existingExternalIDP, userAgg) return r.eventstore.PushAggregate(ctx, existingExternalIDP, userAgg)
} }

View File

@ -16,7 +16,6 @@ func (r *CommandSide) AddMachine(ctx context.Context, orgID string, machine *dom
if err != nil { if err != nil {
return nil, err return nil, err
} }
//TODO: Check Unique username
machine.AggregateID = userID machine.AggregateID = userID
orgIAMPolicy, err := r.getOrgIAMPolicy(ctx, orgID) orgIAMPolicy, err := r.getOrgIAMPolicy(ctx, orgID)
if err != nil { if err != nil {
@ -34,6 +33,7 @@ func (r *CommandSide) AddMachine(ctx context.Context, orgID string, machine *dom
machine.Username, machine.Username,
machine.Name, machine.Name,
machine.Description, machine.Description,
orgIAMPolicy.UserLoginMustBeDomain,
), ),
) )
err = r.eventstore.PushAggregate(ctx, addedMachine, userAgg) err = r.eventstore.PushAggregate(ctx, addedMachine, userAgg)

View File

@ -23,6 +23,10 @@ func (e *ProjectSetEvent) Data() interface{} {
return e return e
} }
func (e *ProjectSetEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewIAMProjectSetEvent(ctx context.Context, projectID string) *ProjectSetEvent { func NewIAMProjectSetEvent(ctx context.Context, projectID string) *ProjectSetEvent {
return &ProjectSetEvent{ return &ProjectSetEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -23,6 +23,10 @@ func (e *GlobalOrgSetEvent) Data() interface{} {
return e return e
} }
func (e *GlobalOrgSetEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewGlobalOrgSetEventEvent(ctx context.Context, orgID string) *GlobalOrgSetEvent { func NewGlobalOrgSetEventEvent(ctx context.Context, orgID string) *GlobalOrgSetEvent {
return &GlobalOrgSetEvent{ return &GlobalOrgSetEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -26,6 +26,10 @@ func (e *SetupStepEvent) Data() interface{} {
return e return e
} }
func (e *SetupStepEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func SetupStepMapper(event *repository.Event) (eventstore.EventReader, error) { func SetupStepMapper(event *repository.Event) (eventstore.EventReader, error) {
step := &SetupStepEvent{ step := &SetupStepEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event), BaseEvent: *eventstore.BaseEventFromRepo(event),

View File

@ -23,7 +23,7 @@ type IDPConfigAddedEvent struct {
func NewIDPConfigAddedEvent( func NewIDPConfigAddedEvent(
ctx context.Context, ctx context.Context,
configID string, configID,
name string, name string,
configType domain.IDPConfigType, configType domain.IDPConfigType,
stylingType domain.IDPConfigStylingType, stylingType domain.IDPConfigStylingType,
@ -31,9 +31,10 @@ func NewIDPConfigAddedEvent(
return &IDPConfigAddedEvent{ return &IDPConfigAddedEvent{
IDPConfigAddedEvent: *idpconfig.NewIDPConfigAddedEvent( IDPConfigAddedEvent: *idpconfig.NewIDPConfigAddedEvent(
eventstore.NewBaseEventForPush( eventstore.NewBaseEventForPushWithResourceOwner(
ctx, ctx,
IDPConfigAddedEventType, IDPConfigAddedEventType,
domain.IAMID,
), ),
configID, configID,
name, name,
@ -87,16 +88,19 @@ type IDPConfigRemovedEvent struct {
func NewIDPConfigRemovedEvent( func NewIDPConfigRemovedEvent(
ctx context.Context, ctx context.Context,
configID string, resourceOwner,
configID,
name string,
) *IDPConfigRemovedEvent { ) *IDPConfigRemovedEvent {
return &IDPConfigRemovedEvent{ return &IDPConfigRemovedEvent{
IDPConfigRemovedEvent: *idpconfig.NewIDPConfigRemovedEvent( IDPConfigRemovedEvent: *idpconfig.NewIDPConfigRemovedEvent(
eventstore.NewBaseEventForPush( eventstore.NewBaseEventForPushWithResourceOwner(
ctx, ctx,
IDPConfigRemovedEventType, IDPConfigRemovedEventType,
resourceOwner,
), ),
configID, configID,
name,
), ),
} }
} }

View File

@ -9,6 +9,23 @@ import (
"github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/domain"
) )
const (
uniqueIDPConfigNameType = "idp_config_names"
)
func NewAddIDPConfigNameUniqueConstraint(idpConfigName, resourceOwner string) *eventstore.EventUniqueConstraint {
return eventstore.NewAddEventUniqueConstraint(
uniqueIDPConfigNameType,
idpConfigName+resourceOwner,
"Errors.IDPConfig.AlreadyExists")
}
func NewRemoveIDPConfigNameUniqueConstraint(idpConfigName, resourceOwner string) *eventstore.EventUniqueConstraint {
return eventstore.NewRemoveEventUniqueConstraint(
uniqueIDPConfigNameType,
idpConfigName+resourceOwner)
}
type IDPConfigAddedEvent struct { type IDPConfigAddedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
@ -20,12 +37,11 @@ type IDPConfigAddedEvent struct {
func NewIDPConfigAddedEvent( func NewIDPConfigAddedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
configID string, configID,
name string, name string,
configType domain.IDPConfigType, configType domain.IDPConfigType,
stylingType domain.IDPConfigStylingType, stylingType domain.IDPConfigStylingType,
) *IDPConfigAddedEvent { ) *IDPConfigAddedEvent {
return &IDPConfigAddedEvent{ return &IDPConfigAddedEvent{
BaseEvent: *base, BaseEvent: *base,
ConfigID: configID, ConfigID: configID,
@ -39,6 +55,10 @@ func (e *IDPConfigAddedEvent) Data() interface{} {
return e return e
} }
func (e *IDPConfigAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewAddIDPConfigNameUniqueConstraint(e.Name, e.ResourceOwner())}
}
func IDPConfigAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) { func IDPConfigAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
e := &IDPConfigAddedEvent{ e := &IDPConfigAddedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event), BaseEvent: *eventstore.BaseEventFromRepo(event),
@ -64,6 +84,10 @@ func (e *IDPConfigChangedEvent) Data() interface{} {
return e return e
} }
func (e *IDPConfigChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewIDPConfigChangedEvent( func NewIDPConfigChangedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
configID string, configID string,
@ -130,6 +154,10 @@ func (e *IDPConfigDeactivatedEvent) Data() interface{} {
return e return e
} }
func (e *IDPConfigDeactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func IDPConfigDeactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) { func IDPConfigDeactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
e := &IDPConfigDeactivatedEvent{ e := &IDPConfigDeactivatedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event), BaseEvent: *eventstore.BaseEventFromRepo(event),
@ -164,6 +192,10 @@ func (e *IDPConfigReactivatedEvent) Data() interface{} {
return e return e
} }
func (e *IDPConfigReactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func IDPConfigReactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) { func IDPConfigReactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
e := &IDPConfigReactivatedEvent{ e := &IDPConfigReactivatedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event), BaseEvent: *eventstore.BaseEventFromRepo(event),
@ -181,16 +213,19 @@ type IDPConfigRemovedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
ConfigID string `json:"idpConfigId"` ConfigID string `json:"idpConfigId"`
Name string
} }
func NewIDPConfigRemovedEvent( func NewIDPConfigRemovedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
configID string, configID string,
name string,
) *IDPConfigRemovedEvent { ) *IDPConfigRemovedEvent {
return &IDPConfigRemovedEvent{ return &IDPConfigRemovedEvent{
BaseEvent: *base, BaseEvent: *base,
ConfigID: configID, ConfigID: configID,
Name: name,
} }
} }
@ -198,6 +233,10 @@ func (e *IDPConfigRemovedEvent) Data() interface{} {
return e return e
} }
func (e *IDPConfigRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewRemoveIDPConfigNameUniqueConstraint(e.Name, e.ResourceOwner())}
}
func IDPConfigRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) { func IDPConfigRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
e := &IDPConfigRemovedEvent{ e := &IDPConfigRemovedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event), BaseEvent: *eventstore.BaseEventFromRepo(event),

View File

@ -32,6 +32,10 @@ func (e *OIDCConfigAddedEvent) Data() interface{} {
return e return e
} }
func (e *OIDCConfigAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewOIDCConfigAddedEvent( func NewOIDCConfigAddedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
clientID, clientID,
@ -86,6 +90,10 @@ func (e *OIDCConfigChangedEvent) Data() interface{} {
return e return e
} }
func (e *OIDCConfigChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewOIDCConfigChangedEvent( func NewOIDCConfigChangedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
idpConfigID string, idpConfigID string,

View File

@ -24,6 +24,10 @@ func (e *MemberAddedEvent) Data() interface{} {
return e return e
} }
func (e *MemberAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewMemberAddedEvent( func NewMemberAddedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
userID string, userID string,
@ -61,6 +65,10 @@ func (e *MemberChangedEvent) Data() interface{} {
return e return e
} }
func (e *MemberChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewMemberChangedEvent( func NewMemberChangedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
userID string, userID string,
@ -96,6 +104,10 @@ func (e *MemberRemovedEvent) Data() interface{} {
return e return e
} }
func (e *MemberRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewRemovedEvent( func NewRemovedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
userID string, userID string,

View File

@ -31,6 +31,10 @@ func (e *DomainAddedEvent) Data() interface{} {
return e return e
} }
func (e *DomainAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewDomainAddedEvent(ctx context.Context, domain string) *DomainAddedEvent { func NewDomainAddedEvent(ctx context.Context, domain string) *DomainAddedEvent {
return &DomainAddedEvent{ return &DomainAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -65,6 +69,10 @@ func (e *DomainVerificationAddedEvent) Data() interface{} {
return e return e
} }
func (e *DomainVerificationAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewDomainVerificationAddedEvent( func NewDomainVerificationAddedEvent(
ctx context.Context, ctx context.Context,
domain string, domain string,
@ -103,6 +111,10 @@ func (e *DomainVerificationFailedEvent) Data() interface{} {
return e return e
} }
func (e *DomainVerificationFailedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewDomainVerificationFailedEvent(ctx context.Context, domain string) *DomainVerificationFailedEvent { func NewDomainVerificationFailedEvent(ctx context.Context, domain string) *DomainVerificationFailedEvent {
return &DomainVerificationFailedEvent{ return &DomainVerificationFailedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -135,6 +147,10 @@ func (e *DomainVerifiedEvent) Data() interface{} {
return e return e
} }
func (e *DomainVerifiedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewDomainVerifiedEvent(ctx context.Context, domain string) *DomainVerifiedEvent { func NewDomainVerifiedEvent(ctx context.Context, domain string) *DomainVerifiedEvent {
return &DomainVerifiedEvent{ return &DomainVerifiedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -167,6 +183,10 @@ func (e *DomainPrimarySetEvent) Data() interface{} {
return e return e
} }
func (e *DomainPrimarySetEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewDomainPrimarySetEvent(ctx context.Context, domain string) *DomainPrimarySetEvent { func NewDomainPrimarySetEvent(ctx context.Context, domain string) *DomainPrimarySetEvent {
return &DomainPrimarySetEvent{ return &DomainPrimarySetEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -199,6 +219,10 @@ func (e *DomainRemovedEvent) Data() interface{} {
return e return e
} }
func (e *DomainRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewDomainRemovedEvent(ctx context.Context, domain string) *DomainRemovedEvent { func NewDomainRemovedEvent(ctx context.Context, domain string) *DomainRemovedEvent {
return &DomainRemovedEvent{ return &DomainRemovedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -22,7 +22,8 @@ type IDPConfigAddedEvent struct {
func NewIDPConfigAddedEvent( func NewIDPConfigAddedEvent(
ctx context.Context, ctx context.Context,
configID string, resourceOwner,
configID,
name string, name string,
configType domain.IDPConfigType, configType domain.IDPConfigType,
stylingType domain.IDPConfigStylingType, stylingType domain.IDPConfigStylingType,
@ -30,9 +31,10 @@ func NewIDPConfigAddedEvent(
return &IDPConfigAddedEvent{ return &IDPConfigAddedEvent{
IDPConfigAddedEvent: *idpconfig.NewIDPConfigAddedEvent( IDPConfigAddedEvent: *idpconfig.NewIDPConfigAddedEvent(
eventstore.NewBaseEventForPush( eventstore.NewBaseEventForPushWithResourceOwner(
ctx, ctx,
IDPConfigAddedEventType, IDPConfigAddedEventType,
resourceOwner,
), ),
configID, configID,
name, name,
@ -86,16 +88,20 @@ type IDPConfigRemovedEvent struct {
func NewIDPConfigRemovedEvent( func NewIDPConfigRemovedEvent(
ctx context.Context, ctx context.Context,
configID string, resourceOwner,
configID,
name string,
) *IDPConfigRemovedEvent { ) *IDPConfigRemovedEvent {
return &IDPConfigRemovedEvent{ return &IDPConfigRemovedEvent{
IDPConfigRemovedEvent: *idpconfig.NewIDPConfigRemovedEvent( IDPConfigRemovedEvent: *idpconfig.NewIDPConfigRemovedEvent(
eventstore.NewBaseEventForPush( eventstore.NewBaseEventForPushWithResourceOwner(
ctx, ctx,
IDPConfigRemovedEventType, IDPConfigRemovedEventType,
resourceOwner,
), ),
configID, configID,
name,
), ),
} }
} }

View File

@ -10,6 +10,7 @@ import (
) )
const ( const (
uniqueOrgname = "org_name"
OrgAddedEventType = orgEventTypePrefix + "added" OrgAddedEventType = orgEventTypePrefix + "added"
OrgChangedEventType = orgEventTypePrefix + "changed" OrgChangedEventType = orgEventTypePrefix + "changed"
OrgDeactivatedEventType = orgEventTypePrefix + "deactivated" OrgDeactivatedEventType = orgEventTypePrefix + "deactivated"
@ -17,6 +18,25 @@ const (
OrgRemovedEventType = orgEventTypePrefix + "removed" OrgRemovedEventType = orgEventTypePrefix + "removed"
) )
type OrgnameUniqueConstraint struct {
uniqueType string
orgName string
action eventstore.UniqueConstraintAction
}
func NewAddOrgnameUniqueConstraint(orgName string) *eventstore.EventUniqueConstraint {
return eventstore.NewAddEventUniqueConstraint(
uniqueOrgname,
orgName,
"Errors.Org.AlreadyExists")
}
func NewRemoveUsernameUniqueConstraint(orgName string) *eventstore.EventUniqueConstraint {
return eventstore.NewRemoveEventUniqueConstraint(
uniqueOrgname,
orgName)
}
type OrgAddedEvent struct { type OrgAddedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
@ -27,6 +47,10 @@ func (e *OrgAddedEvent) Data() interface{} {
return e return e
} }
func (e *OrgAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewAddOrgnameUniqueConstraint(e.Name)}
}
func NewOrgAddedEvent(ctx context.Context, name string) *OrgAddedEvent { func NewOrgAddedEvent(ctx context.Context, name string) *OrgAddedEvent {
return &OrgAddedEvent{ return &OrgAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -59,6 +83,10 @@ func (e *OrgChangedEvent) Data() interface{} {
return e return e
} }
func (e *OrgChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewOrgChangedEvent(ctx context.Context, name string) *OrgChangedEvent { func NewOrgChangedEvent(ctx context.Context, name string) *OrgChangedEvent {
return &OrgChangedEvent{ return &OrgChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -89,6 +117,10 @@ func (e *OrgDeactivatedEvent) Data() interface{} {
return e return e
} }
func (e *OrgDeactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewOrgDeactivatedEvent(ctx context.Context) *OrgDeactivatedEvent { func NewOrgDeactivatedEvent(ctx context.Context) *OrgDeactivatedEvent {
return &OrgDeactivatedEvent{ return &OrgDeactivatedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -118,6 +150,10 @@ func (e *OrgReactivatedEvent) Data() interface{} {
return e return e
} }
func (e *OrgReactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewOrgReactivatedEvent(ctx context.Context) *OrgReactivatedEvent { func NewOrgReactivatedEvent(ctx context.Context) *OrgReactivatedEvent {
return &OrgReactivatedEvent{ return &OrgReactivatedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -24,6 +24,10 @@ func (e *LabelPolicyAddedEvent) Data() interface{} {
return e return e
} }
func (e *LabelPolicyAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewLabelPolicyAddedEvent( func NewLabelPolicyAddedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
primaryColor, primaryColor,
@ -61,6 +65,10 @@ func (e *LabelPolicyChangedEvent) Data() interface{} {
return e return e
} }
func (e *LabelPolicyChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewLabelPolicyChangedEvent( func NewLabelPolicyChangedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
changes []LabelPolicyChanges, changes []LabelPolicyChanges,
@ -112,6 +120,10 @@ func (e *LabelPolicyRemovedEvent) Data() interface{} {
return nil return nil
} }
func (e *LabelPolicyRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewLabelPolicyRemovedEvent(base *eventstore.BaseEvent) *LabelPolicyRemovedEvent { func NewLabelPolicyRemovedEvent(base *eventstore.BaseEvent) *LabelPolicyRemovedEvent {
return &LabelPolicyRemovedEvent{ return &LabelPolicyRemovedEvent{
BaseEvent: *base, BaseEvent: *base,

View File

@ -29,6 +29,10 @@ func (e *LoginPolicyAddedEvent) Data() interface{} {
return e return e
} }
func (e *LoginPolicyAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewLoginPolicyAddedEvent( func NewLoginPolicyAddedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
allowUserNamePassword, allowUserNamePassword,
@ -77,6 +81,10 @@ func (e *LoginPolicyChangedEvent) Data() interface{} {
return e return e
} }
func (e *LoginPolicyChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewLoginPolicyChangedEvent( func NewLoginPolicyChangedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
changes []LoginPolicyChanges, changes []LoginPolicyChanges,
@ -146,6 +154,10 @@ func (e *LoginPolicyRemovedEvent) Data() interface{} {
return nil return nil
} }
func (e *LoginPolicyRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewLoginPolicyRemovedEvent(base *eventstore.BaseEvent) *LoginPolicyRemovedEvent { func NewLoginPolicyRemovedEvent(base *eventstore.BaseEvent) *LoginPolicyRemovedEvent {
return &LoginPolicyRemovedEvent{ return &LoginPolicyRemovedEvent{
BaseEvent: *base, BaseEvent: *base,

View File

@ -51,6 +51,10 @@ func (e *SecondFactorAddedEvent) Data() interface{} {
return e return e
} }
func (e *SecondFactorAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
type SecondFactorRemovedEvent struct { type SecondFactorRemovedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
MFAType domain.SecondFactorType `json:"mfaType"` MFAType domain.SecondFactorType `json:"mfaType"`
@ -83,6 +87,10 @@ func (e *SecondFactorRemovedEvent) Data() interface{} {
return e return e
} }
func (e *SecondFactorRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
type MultiFactorAddedEvent struct { type MultiFactorAddedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
@ -116,6 +124,10 @@ func (e *MultiFactorAddedEvent) Data() interface{} {
return e return e
} }
func (e *MultiFactorAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
type MultiFactorRemovedEvent struct { type MultiFactorRemovedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
MFAType domain.MultiFactorType `json:"mfaType"` MFAType domain.MultiFactorType `json:"mfaType"`
@ -147,3 +159,7 @@ func MultiFactorRemovedEventMapper(event *repository.Event) (eventstore.EventRea
func (e *MultiFactorRemovedEvent) Data() interface{} { func (e *MultiFactorRemovedEvent) Data() interface{} {
return e return e
} }
func (e *MultiFactorRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}

View File

@ -25,6 +25,10 @@ func (e *IdentityProviderAddedEvent) Data() interface{} {
return e return e
} }
func (e *IdentityProviderAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewIdentityProviderAddedEvent( func NewIdentityProviderAddedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
idpConfigID string, idpConfigID string,
@ -61,6 +65,10 @@ func (e *IdentityProviderRemovedEvent) Data() interface{} {
return e return e
} }
func (e *IdentityProviderRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewIdentityProviderRemovedEvent( func NewIdentityProviderRemovedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
idpConfigID string, idpConfigID string,

View File

@ -24,6 +24,10 @@ func (e *OrgIAMPolicyAddedEvent) Data() interface{} {
return e return e
} }
func (e *OrgIAMPolicyAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewOrgIAMPolicyAddedEvent( func NewOrgIAMPolicyAddedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
userLoginMustBeDomain bool, userLoginMustBeDomain bool,
@ -58,6 +62,10 @@ func (e *OrgIAMPolicyChangedEvent) Data() interface{} {
return e return e
} }
func (e *OrgIAMPolicyChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewOrgIAMPolicyChangedEvent( func NewOrgIAMPolicyChangedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
changes []OrgIAMPolicyChanges, changes []OrgIAMPolicyChanges,
@ -103,6 +111,10 @@ func (e *OrgIAMPolicyRemovedEvent) Data() interface{} {
return nil return nil
} }
func (e *OrgIAMPolicyRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewOrgIAMPolicyRemovedEvent(base *eventstore.BaseEvent) *OrgIAMPolicyRemovedEvent { func NewOrgIAMPolicyRemovedEvent(base *eventstore.BaseEvent) *OrgIAMPolicyRemovedEvent {
return &OrgIAMPolicyRemovedEvent{ return &OrgIAMPolicyRemovedEvent{
BaseEvent: *base, BaseEvent: *base,

View File

@ -24,6 +24,10 @@ func (e *PasswordAgePolicyAddedEvent) Data() interface{} {
return e return e
} }
func (e *PasswordAgePolicyAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewPasswordAgePolicyAddedEvent( func NewPasswordAgePolicyAddedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
expireWarnDays, expireWarnDays,
@ -61,6 +65,10 @@ func (e *PasswordAgePolicyChangedEvent) Data() interface{} {
return e return e
} }
func (e *PasswordAgePolicyChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewPasswordAgePolicyChangedEvent( func NewPasswordAgePolicyChangedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
changes []PasswordAgePolicyChanges, changes []PasswordAgePolicyChanges,
@ -112,6 +120,10 @@ func (e *PasswordAgePolicyRemovedEvent) Data() interface{} {
return nil return nil
} }
func (e *PasswordAgePolicyRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewPasswordAgePolicyRemovedEvent(base *eventstore.BaseEvent) *PasswordAgePolicyRemovedEvent { func NewPasswordAgePolicyRemovedEvent(base *eventstore.BaseEvent) *PasswordAgePolicyRemovedEvent {
return &PasswordAgePolicyRemovedEvent{ return &PasswordAgePolicyRemovedEvent{
BaseEvent: *base, BaseEvent: *base,

View File

@ -28,6 +28,10 @@ func (e *PasswordComplexityPolicyAddedEvent) Data() interface{} {
return e return e
} }
func (e *PasswordComplexityPolicyAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewPasswordComplexityPolicyAddedEvent( func NewPasswordComplexityPolicyAddedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
minLength uint64, minLength uint64,
@ -73,6 +77,10 @@ func (e *PasswordComplexityPolicyChangedEvent) Data() interface{} {
return e return e
} }
func (e *PasswordComplexityPolicyChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewPasswordComplexityPolicyChangedEvent( func NewPasswordComplexityPolicyChangedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
changes []PasswordComplexityPolicyChanges, changes []PasswordComplexityPolicyChanges,
@ -142,6 +150,10 @@ func (e *PasswordComplexityPolicyRemovedEvent) Data() interface{} {
return nil return nil
} }
func (e *PasswordComplexityPolicyRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewPasswordComplexityPolicyRemovedEvent(base *eventstore.BaseEvent) *PasswordComplexityPolicyRemovedEvent { func NewPasswordComplexityPolicyRemovedEvent(base *eventstore.BaseEvent) *PasswordComplexityPolicyRemovedEvent {
return &PasswordComplexityPolicyRemovedEvent{ return &PasswordComplexityPolicyRemovedEvent{
BaseEvent: *base, BaseEvent: *base,

View File

@ -25,6 +25,10 @@ func (e *PasswordLockoutPolicyAddedEvent) Data() interface{} {
return e return e
} }
func (e *PasswordLockoutPolicyAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewPasswordLockoutPolicyAddedEvent( func NewPasswordLockoutPolicyAddedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
maxAttempts uint64, maxAttempts uint64,
@ -62,6 +66,10 @@ func (e *PasswordLockoutPolicyChangedEvent) Data() interface{} {
return e return e
} }
func (e *PasswordLockoutPolicyChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewPasswordLockoutPolicyChangedEvent( func NewPasswordLockoutPolicyChangedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
changes []PasswordLockoutPolicyChanges, changes []PasswordLockoutPolicyChanges,
@ -113,6 +121,10 @@ func (e *PasswordLockoutPolicyRemovedEvent) Data() interface{} {
return nil return nil
} }
func (e *PasswordLockoutPolicyRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewPasswordLockoutPolicyRemovedEvent(base *eventstore.BaseEvent) *PasswordLockoutPolicyRemovedEvent { func NewPasswordLockoutPolicyRemovedEvent(base *eventstore.BaseEvent) *PasswordLockoutPolicyRemovedEvent {
return &PasswordLockoutPolicyRemovedEvent{ return &PasswordLockoutPolicyRemovedEvent{
BaseEvent: *base, BaseEvent: *base,

View File

@ -31,6 +31,10 @@ func (e *ApplicationAddedEvent) Data() interface{} {
return e return e
} }
func (e *ApplicationAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewApplicationAddedEvent(ctx context.Context, appID, name string, appType domain.AppType) *ApplicationAddedEvent { func NewApplicationAddedEvent(ctx context.Context, appID, name string, appType domain.AppType) *ApplicationAddedEvent {
return &ApplicationAddedEvent{ return &ApplicationAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -45,6 +45,10 @@ func (e *OIDCConfigAddedEvent) Data() interface{} {
return e return e
} }
func (e *OIDCConfigAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewOIDCConfigAddedEvent( func NewOIDCConfigAddedEvent(
ctx context.Context, ctx context.Context,
version domain.OIDCVersion, version domain.OIDCVersion,

View File

@ -10,6 +10,7 @@ import (
) )
const ( const (
uniqueProjectnameTable = "project_names"
projectEventTypePrefix = eventstore.EventType("project.") projectEventTypePrefix = eventstore.EventType("project.")
ProjectAdded = projectEventTypePrefix + "added" ProjectAdded = projectEventTypePrefix + "added"
ProjectChanged = projectEventTypePrefix + "changed" ProjectChanged = projectEventTypePrefix + "changed"
@ -18,6 +19,19 @@ const (
ProjectRemoved = projectEventTypePrefix + "removed" ProjectRemoved = projectEventTypePrefix + "removed"
) )
func NewAddProjectNameUniqueConstraint(projectName, resourceOwner string) *eventstore.EventUniqueConstraint {
return eventstore.NewAddEventUniqueConstraint(
uniqueProjectnameTable,
projectName+resourceOwner,
"Errors.Project.AlreadyExists")
}
func NewRemoveProjectNameUniqueConstraint(projectName, resourceOwner string) *eventstore.EventUniqueConstraint {
return eventstore.NewRemoveEventUniqueConstraint(
uniqueProjectnameTable,
projectName+resourceOwner)
}
type ProjectAddedEvent struct { type ProjectAddedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
@ -30,11 +44,16 @@ func (e *ProjectAddedEvent) Data() interface{} {
return e return e
} }
func NewProjectAddedEvent(ctx context.Context, name string) *ProjectAddedEvent { func (e *ProjectAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewAddProjectNameUniqueConstraint(e.Name, e.ResourceOwner())}
}
func NewProjectAddedEvent(ctx context.Context, name, resourceOwner string) *ProjectAddedEvent {
return &ProjectAddedEvent{ return &ProjectAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner(
ctx, ctx,
ProjectAdded, ProjectAdded,
resourceOwner,
), ),
Name: name, Name: name,
} }

View File

@ -26,7 +26,8 @@ const (
type HumanAddedEvent struct { type HumanAddedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
UserName string `json:"userName"` UserName string `json:"userName"`
userLoginMustBeDomain bool
FirstName string `json:"firstName,omitempty"` FirstName string `json:"firstName,omitempty"`
LastName string `json:"lastName,omitempty"` LastName string `json:"lastName,omitempty"`
@ -53,6 +54,10 @@ func (e *HumanAddedEvent) Data() interface{} {
return e return e
} }
func (e *HumanAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), e.userLoginMustBeDomain)}
}
func (e *HumanAddedEvent) AddAddressData( func (e *HumanAddedEvent) AddAddressData(
country, country,
locality, locality,
@ -83,6 +88,7 @@ func (e *HumanAddedEvent) AddPasswordData(
func NewHumanAddedEvent( func NewHumanAddedEvent(
ctx context.Context, ctx context.Context,
resourceOwner,
userName, userName,
firstName, firstName,
lastName, lastName,
@ -91,20 +97,23 @@ func NewHumanAddedEvent(
preferredLanguage language.Tag, preferredLanguage language.Tag,
gender domain.Gender, gender domain.Gender,
emailAddress string, emailAddress string,
userLoginMustBeDomain bool,
) *HumanAddedEvent { ) *HumanAddedEvent {
return &HumanAddedEvent{ return &HumanAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner(
ctx, ctx,
HumanAddedType, HumanAddedType,
resourceOwner,
), ),
UserName: userName, UserName: userName,
FirstName: firstName, FirstName: firstName,
LastName: lastName, LastName: lastName,
NickName: nickName, NickName: nickName,
DisplayName: displayName, DisplayName: displayName,
PreferredLanguage: preferredLanguage, PreferredLanguage: preferredLanguage,
Gender: gender, Gender: gender,
EmailAddress: emailAddress, EmailAddress: emailAddress,
userLoginMustBeDomain: userLoginMustBeDomain,
} }
} }
@ -123,7 +132,8 @@ func HumanAddedEventMapper(event *repository.Event) (eventstore.EventReader, err
type HumanRegisteredEvent struct { type HumanRegisteredEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
UserName string `json:"userName"` UserName string `json:"userName"`
userLoginMustBeDomain bool
FirstName string `json:"firstName,omitempty"` FirstName string `json:"firstName,omitempty"`
LastName string `json:"lastName,omitempty"` LastName string `json:"lastName,omitempty"`
@ -150,6 +160,10 @@ func (e *HumanRegisteredEvent) Data() interface{} {
return e return e
} }
func (e *HumanRegisteredEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), e.userLoginMustBeDomain)}
}
func (e *HumanRegisteredEvent) AddAddressData( func (e *HumanRegisteredEvent) AddAddressData(
country, country,
locality, locality,
@ -180,6 +194,7 @@ func (e *HumanRegisteredEvent) AddPasswordData(
func NewHumanRegisteredEvent( func NewHumanRegisteredEvent(
ctx context.Context, ctx context.Context,
resourceOwner,
userName, userName,
firstName, firstName,
lastName, lastName,
@ -188,20 +203,23 @@ func NewHumanRegisteredEvent(
preferredLanguage language.Tag, preferredLanguage language.Tag,
gender domain.Gender, gender domain.Gender,
emailAddress string, emailAddress string,
userLoginMustBeDomain bool,
) *HumanRegisteredEvent { ) *HumanRegisteredEvent {
return &HumanRegisteredEvent{ return &HumanRegisteredEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner(
ctx, ctx,
HumanRegisteredType, HumanRegisteredType,
resourceOwner,
), ),
UserName: userName, UserName: userName,
FirstName: firstName, FirstName: firstName,
LastName: lastName, LastName: lastName,
NickName: nickName, NickName: nickName,
DisplayName: displayName, DisplayName: displayName,
PreferredLanguage: preferredLanguage, PreferredLanguage: preferredLanguage,
Gender: gender, Gender: gender,
EmailAddress: emailAddress, EmailAddress: emailAddress,
userLoginMustBeDomain: userLoginMustBeDomain,
} }
} }
@ -227,6 +245,10 @@ func (e *HumanInitialCodeAddedEvent) Data() interface{} {
return e return e
} }
func (e *HumanInitialCodeAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanInitialCodeAddedEvent( func NewHumanInitialCodeAddedEvent(
ctx context.Context, ctx context.Context,
code *crypto.CryptoValue, code *crypto.CryptoValue,
@ -262,6 +284,10 @@ func (e *HumanInitialCodeSentEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanInitialCodeSentEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanInitialCodeSentEvent(ctx context.Context) *HumanInitialCodeSentEvent { func NewHumanInitialCodeSentEvent(ctx context.Context) *HumanInitialCodeSentEvent {
return &HumanInitialCodeSentEvent{ return &HumanInitialCodeSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -285,6 +311,10 @@ func (e *HumanInitializedCheckSucceededEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanInitializedCheckSucceededEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanInitializedCheckSucceededEvent(ctx context.Context) *HumanInitializedCheckSucceededEvent { func NewHumanInitializedCheckSucceededEvent(ctx context.Context) *HumanInitializedCheckSucceededEvent {
return &HumanInitializedCheckSucceededEvent{ return &HumanInitializedCheckSucceededEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -308,6 +338,10 @@ func (e *HumanInitializedCheckFailedEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanInitializedCheckFailedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanInitializedCheckFailedEvent(ctx context.Context) *HumanInitializedCheckFailedEvent { func NewHumanInitializedCheckFailedEvent(ctx context.Context) *HumanInitializedCheckFailedEvent {
return &HumanInitializedCheckFailedEvent{ return &HumanInitializedCheckFailedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -331,6 +365,10 @@ func (e *HumanSignedOutEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanSignedOutEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanSignedOutEvent(ctx context.Context) *HumanSignedOutEvent { func NewHumanSignedOutEvent(ctx context.Context) *HumanSignedOutEvent {
return &HumanSignedOutEvent{ return &HumanSignedOutEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -27,6 +27,10 @@ func (e *HumanAddressChangedEvent) Data() interface{} {
return e return e
} }
func (e *HumanAddressChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanAddressChangedEvent(ctx context.Context) *HumanAddressChangedEvent { func NewHumanAddressChangedEvent(ctx context.Context) *HumanAddressChangedEvent {
return &HumanAddressChangedEvent{ return &HumanAddressChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -29,6 +29,10 @@ func (e *HumanEmailChangedEvent) Data() interface{} {
return e return e
} }
func (e *HumanEmailChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanEmailChangedEvent(ctx context.Context) *HumanEmailChangedEvent { func NewHumanEmailChangedEvent(ctx context.Context) *HumanEmailChangedEvent {
return &HumanEmailChangedEvent{ return &HumanEmailChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -60,6 +64,10 @@ func (e *HumanEmailVerifiedEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanEmailVerifiedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanEmailVerifiedEvent(ctx context.Context) *HumanEmailVerifiedEvent { func NewHumanEmailVerifiedEvent(ctx context.Context) *HumanEmailVerifiedEvent {
return &HumanEmailVerifiedEvent{ return &HumanEmailVerifiedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -85,6 +93,10 @@ func (e *HumanEmailVerificationFailedEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanEmailVerificationFailedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanEmailVerificationFailedEvent(ctx context.Context) *HumanEmailVerificationFailedEvent { func NewHumanEmailVerificationFailedEvent(ctx context.Context) *HumanEmailVerificationFailedEvent {
return &HumanEmailVerificationFailedEvent{ return &HumanEmailVerificationFailedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -111,6 +123,10 @@ func (e *HumanEmailCodeAddedEvent) Data() interface{} {
return e return e
} }
func (e *HumanEmailCodeAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanEmailCodeAddedEvent( func NewHumanEmailCodeAddedEvent(
ctx context.Context, ctx context.Context,
code *crypto.CryptoValue, code *crypto.CryptoValue,
@ -145,6 +161,10 @@ func (e *HumanEmailCodeSentEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanEmailCodeSentEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanEmailCodeSentEvent(ctx context.Context) *HumanEmailCodeSentEvent { func NewHumanEmailCodeSentEvent(ctx context.Context) *HumanEmailCodeSentEvent {
return &HumanEmailCodeSentEvent{ return &HumanEmailCodeSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -9,6 +9,7 @@ import (
) )
const ( const (
uniqueExternalIDPType = "external_idps"
externalIDPEventPrefix = humanEventPrefix + "externalidp." externalIDPEventPrefix = humanEventPrefix + "externalidp."
externalLoginEventPrefix = humanEventPrefix + "externallogin." externalLoginEventPrefix = humanEventPrefix + "externallogin."
@ -23,38 +24,17 @@ const (
HumanExternalLoginCheckSucceededType = externalLoginEventPrefix + "check.succeeded" HumanExternalLoginCheckSucceededType = externalLoginEventPrefix + "check.succeeded"
) )
type HumanExternalIDPReservedEvent struct { func NewAddExternalIDPUniqueConstraint(idpConfigID, externalUserID string) *eventstore.EventUniqueConstraint {
eventstore.BaseEvent `json:"-"` return eventstore.NewAddEventUniqueConstraint(
uniqueExternalIDPType,
idpConfigID+externalUserID,
"Errors.User.ExternalIDP.AlreadyExists")
} }
func (e *HumanExternalIDPReservedEvent) Data() interface{} { func NewRemoveExternalIDPUniqueConstraint(idpConfigID, externalUserID string) *eventstore.EventUniqueConstraint {
return nil return eventstore.NewRemoveEventUniqueConstraint(
} uniqueExternalIDPType,
idpConfigID+externalUserID)
func NewHumanExternalIDPReservedEvent(ctx context.Context) *HumanExternalIDPReservedEvent {
return &HumanExternalIDPReservedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,
HumanExternalIDPReservedType,
),
}
}
type HumanExternalIDPReleasedEvent struct {
eventstore.BaseEvent `json:"-"`
}
func (e *HumanExternalIDPReleasedEvent) Data() interface{} {
return nil
}
func NewHumanExternalIDPReleasedEvent(ctx context.Context) *HumanExternalIDPReleasedEvent {
return &HumanExternalIDPReleasedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,
HumanExternalIDPReleasedType,
),
}
} }
type HumanExternalIDPAddedEvent struct { type HumanExternalIDPAddedEvent struct {
@ -69,6 +49,10 @@ func (e *HumanExternalIDPAddedEvent) Data() interface{} {
return e return e
} }
func (e *HumanExternalIDPAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewAddExternalIDPUniqueConstraint(e.IDPConfigID, e.UserID)}
}
func NewHumanExternalIDPAddedEvent(ctx context.Context, idpConfigID, displayName string) *HumanExternalIDPAddedEvent { func NewHumanExternalIDPAddedEvent(ctx context.Context, idpConfigID, displayName string) *HumanExternalIDPAddedEvent {
return &HumanExternalIDPAddedEvent{ return &HumanExternalIDPAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -104,6 +88,10 @@ func (e *HumanExternalIDPRemovedEvent) Data() interface{} {
return e return e
} }
func (e *HumanExternalIDPRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewRemoveExternalIDPUniqueConstraint(e.IDPConfigID, e.UserID)}
}
func NewHumanExternalIDPRemovedEvent(ctx context.Context, idpConfigID, externalUserID string) *HumanExternalIDPRemovedEvent { func NewHumanExternalIDPRemovedEvent(ctx context.Context, idpConfigID, externalUserID string) *HumanExternalIDPRemovedEvent {
return &HumanExternalIDPRemovedEvent{ return &HumanExternalIDPRemovedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -139,6 +127,10 @@ func (e *HumanExternalIDPCascadeRemovedEvent) Data() interface{} {
return e return e
} }
func (e *HumanExternalIDPCascadeRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewRemoveExternalIDPUniqueConstraint(e.IDPConfigID, e.UserID)}
}
func NewHumanExternalIDPCascadeRemovedEvent(ctx context.Context, idpConfigID, externalUserID string) *HumanExternalIDPCascadeRemovedEvent { func NewHumanExternalIDPCascadeRemovedEvent(ctx context.Context, idpConfigID, externalUserID string) *HumanExternalIDPCascadeRemovedEvent {
return &HumanExternalIDPCascadeRemovedEvent{ return &HumanExternalIDPCascadeRemovedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -171,6 +163,10 @@ func (e *HumanExternalIDPCheckSucceededEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanExternalIDPCheckSucceededEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanExternalIDPCheckSucceededEvent(ctx context.Context) *HumanExternalIDPCheckSucceededEvent { func NewHumanExternalIDPCheckSucceededEvent(ctx context.Context) *HumanExternalIDPCheckSucceededEvent {
return &HumanExternalIDPCheckSucceededEvent{ return &HumanExternalIDPCheckSucceededEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -19,6 +19,10 @@ func (e *HumanMFAInitSkippedEvent) Data() interface{} {
return e return e
} }
func (e *HumanMFAInitSkippedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanMFAInitSkippedEvent(ctx context.Context) *HumanMFAInitSkippedEvent { func NewHumanMFAInitSkippedEvent(ctx context.Context) *HumanMFAInitSkippedEvent {
return &HumanMFAInitSkippedEvent{ return &HumanMFAInitSkippedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -28,6 +28,10 @@ func (e *HumanOTPAddedEvent) Data() interface{} {
return e return e
} }
func (e *HumanOTPAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanOTPAddedEvent(ctx context.Context, func NewHumanOTPAddedEvent(ctx context.Context,
secret *crypto.CryptoValue) *HumanOTPAddedEvent { secret *crypto.CryptoValue) *HumanOTPAddedEvent {
return &HumanOTPAddedEvent{ return &HumanOTPAddedEvent{
@ -59,6 +63,10 @@ func (e *HumanOTPVerifiedEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanOTPVerifiedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanOTPVerifiedEvent(ctx context.Context, userAgentID string) *HumanOTPVerifiedEvent { func NewHumanOTPVerifiedEvent(ctx context.Context, userAgentID string) *HumanOTPVerifiedEvent {
return &HumanOTPVerifiedEvent{ return &HumanOTPVerifiedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -83,6 +91,10 @@ func (e *HumanOTPRemovedEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanOTPRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanOTPRemovedEvent(ctx context.Context) *HumanOTPRemovedEvent { func NewHumanOTPRemovedEvent(ctx context.Context) *HumanOTPRemovedEvent {
return &HumanOTPRemovedEvent{ return &HumanOTPRemovedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -106,6 +118,10 @@ func (e *HumanOTPCheckSucceededEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanOTPCheckSucceededEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanOTPCheckSucceededEvent(ctx context.Context) *HumanOTPCheckSucceededEvent { func NewHumanOTPCheckSucceededEvent(ctx context.Context) *HumanOTPCheckSucceededEvent {
return &HumanOTPCheckSucceededEvent{ return &HumanOTPCheckSucceededEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -129,6 +145,10 @@ func (e *HumanOTPCheckFailedEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanOTPCheckFailedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanOTPCheckFailedEvent(ctx context.Context) *HumanOTPCheckFailedEvent { func NewHumanOTPCheckFailedEvent(ctx context.Context) *HumanOTPCheckFailedEvent {
return &HumanOTPCheckFailedEvent{ return &HumanOTPCheckFailedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -40,6 +40,10 @@ func (e *HumanWebAuthNAddedEvent) Data() interface{} {
return e return e
} }
func (e *HumanWebAuthNAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanU2FAddedEvent( func NewHumanU2FAddedEvent(
ctx context.Context, ctx context.Context,
webAuthNTokenID, webAuthNTokenID,
@ -97,6 +101,10 @@ func (e *HumanWebAuthNVerifiedEvent) Data() interface{} {
return e return e
} }
func (e *HumanWebAuthNVerifiedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanU2FVerifiedEvent( func NewHumanU2FVerifiedEvent(
ctx context.Context, ctx context.Context,
webAuthNTokenID, webAuthNTokenID,
@ -169,6 +177,10 @@ func (e *HumanWebAuthNSignCountChangedEvent) Data() interface{} {
return e return e
} }
func (e *HumanWebAuthNSignCountChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanU2FSignCountChangedEvent( func NewHumanU2FSignCountChangedEvent(
ctx context.Context, ctx context.Context,
webAuthNTokenID string, webAuthNTokenID string,
@ -221,6 +233,10 @@ func (e *HumanWebAuthNRemovedEvent) Data() interface{} {
return e return e
} }
func (e *HumanWebAuthNRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanU2FRemovedEvent( func NewHumanU2FRemovedEvent(
ctx context.Context, ctx context.Context,
webAuthNTokenID string, webAuthNTokenID string,
@ -271,6 +287,10 @@ func (e *HumanWebAuthNBeginLoginEvent) Data() interface{} {
return e return e
} }
func (e *HumanWebAuthNBeginLoginEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanU2FBeginLoginEvent( func NewHumanU2FBeginLoginEvent(
ctx context.Context, ctx context.Context,
webAuthNTokenID, webAuthNTokenID,
@ -323,6 +343,10 @@ func (e *HumanWebAuthNCheckSucceededEvent) Data() interface{} {
return e return e
} }
func (e *HumanWebAuthNCheckSucceededEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanU2FCheckSucceededEvent(ctx context.Context) *HumanWebAuthNCheckSucceededEvent { func NewHumanU2FCheckSucceededEvent(ctx context.Context) *HumanWebAuthNCheckSucceededEvent {
return &HumanWebAuthNCheckSucceededEvent{ return &HumanWebAuthNCheckSucceededEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -363,6 +387,10 @@ func (e *HumanWebAuthNCheckFailedEvent) Data() interface{} {
return e return e
} }
func (e *HumanWebAuthNCheckFailedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanU2FCheckFailedEvent(ctx context.Context) *HumanWebAuthNCheckFailedEvent { func NewHumanU2FCheckFailedEvent(ctx context.Context) *HumanWebAuthNCheckFailedEvent {
return &HumanWebAuthNCheckFailedEvent{ return &HumanWebAuthNCheckFailedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -32,6 +32,10 @@ func (e *HumanPasswordChangedEvent) Data() interface{} {
return e return e
} }
func (e *HumanPasswordChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanPasswordChangedEvent( func NewHumanPasswordChangedEvent(
ctx context.Context, ctx context.Context,
secret *crypto.CryptoValue, secret *crypto.CryptoValue,
@ -73,6 +77,10 @@ func (e *HumanPasswordCodeAddedEvent) Data() interface{} {
return e return e
} }
func (e *HumanPasswordCodeAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanPasswordCodeAddedEvent( func NewHumanPasswordCodeAddedEvent(
ctx context.Context, ctx context.Context,
code *crypto.CryptoValue, code *crypto.CryptoValue,
@ -110,6 +118,10 @@ func (e *HumanPasswordCodeSentEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanPasswordCodeSentEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanPasswordCodeSentEvent(ctx context.Context) *HumanPasswordCodeSentEvent { func NewHumanPasswordCodeSentEvent(ctx context.Context) *HumanPasswordCodeSentEvent {
return &HumanPasswordCodeSentEvent{ return &HumanPasswordCodeSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -133,6 +145,10 @@ func (e *HumanPasswordCheckSucceededEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanPasswordCheckSucceededEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanPasswordCheckSucceededEvent(ctx context.Context) *HumanPasswordCheckSucceededEvent { func NewHumanPasswordCheckSucceededEvent(ctx context.Context) *HumanPasswordCheckSucceededEvent {
return &HumanPasswordCheckSucceededEvent{ return &HumanPasswordCheckSucceededEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -156,6 +172,10 @@ func (e *HumanPasswordCheckFailedEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanPasswordCheckFailedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanPasswordCheckFailedEvent(ctx context.Context) *HumanPasswordCheckFailedEvent { func NewHumanPasswordCheckFailedEvent(ctx context.Context) *HumanPasswordCheckFailedEvent {
return &HumanPasswordCheckFailedEvent{ return &HumanPasswordCheckFailedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -30,6 +30,10 @@ func (e *HumanPhoneChangedEvent) Data() interface{} {
return e return e
} }
func (e *HumanPhoneChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanPhoneChangedEvent(ctx context.Context) *HumanPhoneChangedEvent { func NewHumanPhoneChangedEvent(ctx context.Context) *HumanPhoneChangedEvent {
return &HumanPhoneChangedEvent{ return &HumanPhoneChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -59,6 +63,10 @@ func (e *HumanPhoneRemovedEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanPhoneRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanPhoneRemovedEvent(ctx context.Context) *HumanPhoneRemovedEvent { func NewHumanPhoneRemovedEvent(ctx context.Context) *HumanPhoneRemovedEvent {
return &HumanPhoneRemovedEvent{ return &HumanPhoneRemovedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -84,6 +92,10 @@ func (e *HumanPhoneVerifiedEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanPhoneVerifiedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanPhoneVerifiedEvent(ctx context.Context) *HumanPhoneVerifiedEvent { func NewHumanPhoneVerifiedEvent(ctx context.Context) *HumanPhoneVerifiedEvent {
return &HumanPhoneVerifiedEvent{ return &HumanPhoneVerifiedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -108,6 +120,10 @@ func (e *HumanPhoneVerificationFailedEvent) Data() interface{} {
return nil return nil
} }
func (e *HumanPhoneVerificationFailedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanPhoneVerificationFailedEvent(ctx context.Context) *HumanPhoneVerificationFailedEvent { func NewHumanPhoneVerificationFailedEvent(ctx context.Context) *HumanPhoneVerificationFailedEvent {
return &HumanPhoneVerificationFailedEvent{ return &HumanPhoneVerificationFailedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -134,6 +150,10 @@ func (e *HumanPhoneCodeAddedEvent) Data() interface{} {
return e return e
} }
func (e *HumanPhoneCodeAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanPhoneCodeAddedEvent( func NewHumanPhoneCodeAddedEvent(
ctx context.Context, ctx context.Context,
code *crypto.CryptoValue, code *crypto.CryptoValue,
@ -169,6 +189,10 @@ func (e *HumanPhoneCodeSentEvent) Data() interface{} {
return e return e
} }
func (e *HumanPhoneCodeSentEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanPhoneCodeSentEvent(ctx context.Context) *HumanPhoneCodeSentEvent { func NewHumanPhoneCodeSentEvent(ctx context.Context) *HumanPhoneCodeSentEvent {
return &HumanPhoneCodeSentEvent{ return &HumanPhoneCodeSentEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(

View File

@ -30,6 +30,10 @@ func (e *HumanProfileChangedEvent) Data() interface{} {
return e return e
} }
func (e *HumanProfileChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewHumanProfileChangedEvent( func NewHumanProfileChangedEvent(
ctx context.Context) *HumanProfileChangedEvent { ctx context.Context) *HumanProfileChangedEvent {
return &HumanProfileChangedEvent{ return &HumanProfileChangedEvent{

View File

@ -17,7 +17,8 @@ const (
type MachineAddedEvent struct { type MachineAddedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
UserName string `json:"userName"` UserName string `json:"userName"`
UserLoginMustBeDomain bool
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
@ -27,20 +28,26 @@ func (e *MachineAddedEvent) Data() interface{} {
return e return e
} }
func (e *MachineAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), e.UserLoginMustBeDomain)}
}
func NewMachineAddedEvent( func NewMachineAddedEvent(
ctx context.Context, ctx context.Context,
userName, userName,
name, name,
description string, description string,
userLoginMustBeDomain bool,
) *MachineAddedEvent { ) *MachineAddedEvent {
return &MachineAddedEvent{ return &MachineAddedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
ctx, ctx,
MachineAddedEventType, MachineAddedEventType,
), ),
UserName: userName, UserName: userName,
Name: name, Name: name,
Description: description, Description: description,
UserLoginMustBeDomain: userLoginMustBeDomain,
} }
} }
@ -69,6 +76,10 @@ func (e *MachineChangedEvent) Data() interface{} {
return e return e
} }
func (e *MachineChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewMachineChangedEvent( func NewMachineChangedEvent(
ctx context.Context, ctx context.Context,
) *MachineChangedEvent { ) *MachineChangedEvent {

View File

@ -29,6 +29,10 @@ func (e *MachineKeyAddedEvent) Data() interface{} {
return e return e
} }
func (e *MachineKeyAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewMachineKeyAddedEvent( func NewMachineKeyAddedEvent(
ctx context.Context, ctx context.Context,
keyID string, keyID string,
@ -70,6 +74,10 @@ func (e *MachineKeyRemovedEvent) Data() interface{} {
return e return e
} }
func (e *MachineKeyRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewMachineKeyRemovedEvent( func NewMachineKeyRemovedEvent(
ctx context.Context, ctx context.Context,
keyID string, keyID string,

View File

@ -10,6 +10,7 @@ import (
) )
const ( const (
uniqueUsername = "usernames"
userEventTypePrefix = eventstore.EventType("user.") userEventTypePrefix = eventstore.EventType("user.")
UserLockedType = userEventTypePrefix + "locked" UserLockedType = userEventTypePrefix + "locked"
UserUnlockedType = userEventTypePrefix + "unlocked" UserUnlockedType = userEventTypePrefix + "unlocked"
@ -22,6 +23,27 @@ const (
UserUserNameChangedType = userEventTypePrefix + "username.changed" UserUserNameChangedType = userEventTypePrefix + "username.changed"
) )
func NewAddUsernameUniqueConstraint(userName, resourceOwner string, userLoginMustBeDomain bool) *eventstore.EventUniqueConstraint {
uniqueUserName := userName
if userLoginMustBeDomain {
uniqueUserName = userName + resourceOwner
}
return eventstore.NewAddEventUniqueConstraint(
uniqueUsername,
uniqueUserName,
"Errors.User.AlreadyExists")
}
func NewRemoveUsernameUniqueConstraint(userName, resourceOwner string, userLoginMustBeDomain bool) *eventstore.EventUniqueConstraint {
uniqueUserName := userName
if userLoginMustBeDomain {
uniqueUserName = userName + resourceOwner
}
return eventstore.NewRemoveEventUniqueConstraint(
uniqueUsername,
uniqueUserName)
}
type UserLockedEvent struct { type UserLockedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
} }
@ -30,6 +52,10 @@ func (e *UserLockedEvent) Data() interface{} {
return nil return nil
} }
func (e *UserLockedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewUserLockedEvent(ctx context.Context) *UserLockedEvent { func NewUserLockedEvent(ctx context.Context) *UserLockedEvent {
return &UserLockedEvent{ return &UserLockedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -53,6 +79,10 @@ func (e *UserUnlockedEvent) Data() interface{} {
return nil return nil
} }
func (e *UserUnlockedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewUserUnlockedEvent(ctx context.Context) *UserUnlockedEvent { func NewUserUnlockedEvent(ctx context.Context) *UserUnlockedEvent {
return &UserUnlockedEvent{ return &UserUnlockedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -76,6 +106,10 @@ func (e *UserDeactivatedEvent) Data() interface{} {
return nil return nil
} }
func (e *UserDeactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewUserDeactivatedEvent(ctx context.Context) *UserDeactivatedEvent { func NewUserDeactivatedEvent(ctx context.Context) *UserDeactivatedEvent {
return &UserDeactivatedEvent{ return &UserDeactivatedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -99,6 +133,10 @@ func (e *UserReactivatedEvent) Data() interface{} {
return nil return nil
} }
func (e *UserReactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewUserReactivatedEvent(ctx context.Context) *UserReactivatedEvent { func NewUserReactivatedEvent(ctx context.Context) *UserReactivatedEvent {
return &UserReactivatedEvent{ return &UserReactivatedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
@ -116,18 +154,28 @@ func UserReactivatedEventMapper(event *repository.Event) (eventstore.EventReader
type UserRemovedEvent struct { type UserRemovedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
UserName string
UserLoginMustBeDomain bool
} }
func (e *UserRemovedEvent) Data() interface{} { func (e *UserRemovedEvent) Data() interface{} {
return nil return nil
} }
func NewUserRemovedEvent(ctx context.Context) *UserRemovedEvent { func (e *UserRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewRemoveUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), e.UserLoginMustBeDomain)}
}
func NewUserRemovedEvent(ctx context.Context, resourceOwner, userName string, userLoginMustBeDomain bool) *UserRemovedEvent {
return &UserRemovedEvent{ return &UserRemovedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner(
ctx, ctx,
UserRemovedType, UserRemovedType,
resourceOwner,
), ),
UserName: userName,
UserLoginMustBeDomain: userLoginMustBeDomain,
} }
} }
@ -153,6 +201,10 @@ func (e *UserTokenAddedEvent) Data() interface{} {
return e return e
} }
func (e *UserTokenAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewUserTokenAddedEvent( func NewUserTokenAddedEvent(
ctx context.Context, ctx context.Context,
tokenID, tokenID,
@ -168,12 +220,13 @@ func NewUserTokenAddedEvent(
ctx, ctx,
UserTokenAddedType, UserTokenAddedType,
), ),
TokenID: tokenID, TokenID: tokenID,
ApplicationID: applicationID, ApplicationID: applicationID,
UserAgentID: userAgentID, UserAgentID: userAgentID,
Audience: audience, Audience: audience,
Scopes: scopes, Scopes: scopes,
Expiration: expiration, Expiration: expiration,
PreferredLanguage: preferredLanguage,
} }
} }
@ -199,6 +252,10 @@ func (e *DomainClaimedEvent) Data() interface{} {
return e return e
} }
func (e *DomainClaimedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewDomainClaimedEvent( func NewDomainClaimedEvent(
ctx context.Context, ctx context.Context,
userName string, userName string,
@ -232,6 +289,10 @@ func (e *DomainClaimedSentEvent) Data() interface{} {
return nil return nil
} }
func (e *DomainClaimedSentEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewDomainClaimedSentEvent( func NewDomainClaimedSentEvent(
ctx context.Context, ctx context.Context,
) *DomainClaimedSentEvent { ) *DomainClaimedSentEvent {
@ -252,23 +313,36 @@ func DomainClaimedSentEventMapper(event *repository.Event) (eventstore.EventRead
type UsernameChangedEvent struct { type UsernameChangedEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
UserName string `json:"userName"` UserName string `json:"userName"`
OldUserName string
UserLoginMustBeDomain bool
} }
func (e *UsernameChangedEvent) Data() interface{} { func (e *UsernameChangedEvent) Data() interface{} {
return e return e
} }
func (e *UsernameChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{
NewRemoveUsernameUniqueConstraint(e.OldUserName, e.ResourceOwner(), e.UserLoginMustBeDomain),
NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), e.UserLoginMustBeDomain),
}
}
func NewUsernameChangedEvent( func NewUsernameChangedEvent(
ctx context.Context, ctx context.Context,
userName string, oldUserName,
newUserName string,
userLoginMustBeDomain bool,
) *UsernameChangedEvent { ) *UsernameChangedEvent {
return &UsernameChangedEvent{ return &UsernameChangedEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
ctx, ctx,
UserUserNameChangedType, UserUserNameChangedType,
), ),
UserName: userName, UserName: newUserName,
OldUserName: oldUserName,
UserLoginMustBeDomain: userLoginMustBeDomain,
} }
} }

View File

@ -2,14 +2,15 @@ package view
import ( import (
"github.com/caos/zitadel/internal/eventstore/v2" "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/iam"
) )
type IAM struct { type IAM struct {
eventstore.ReadModel eventstore.ReadModel
SetUpStarted iam.Step SetUpStarted domain.Step
SetUpDone iam.Step SetUpDone domain.Step
GlobalOrgID string GlobalOrgID string
ProjectID string ProjectID string

View File

@ -0,0 +1,5 @@
CREATE TABLE eventstore.unique_constraints (
unique_type TEXT,
unique_field TEXT,
PRIMARY KEY (unique_type, unique_field)
);