mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 22:47:35 +00:00
fix(org): adding unique constrants to not allow an org to be added twice with same id
This commit is contained in:
@@ -47,14 +47,17 @@ func TestMain(m *testing.M) {
|
|||||||
func TestServer_CreateOrganization(t *testing.T) {
|
func TestServer_CreateOrganization(t *testing.T) {
|
||||||
idpResp := Instance.AddGenericOAuthProvider(CTX, Instance.DefaultOrg.Id)
|
idpResp := Instance.AddGenericOAuthProvider(CTX, Instance.DefaultOrg.Id)
|
||||||
|
|
||||||
tests := []struct {
|
type test struct {
|
||||||
name string
|
name string
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
req *v2beta_org.CreateOrganizationRequest
|
req *v2beta_org.CreateOrganizationRequest
|
||||||
id string
|
id string
|
||||||
|
testfunc func(ctx context.Context, t *testing.T)
|
||||||
want *v2beta_org.CreateOrganizationResponse
|
want *v2beta_org.CreateOrganizationResponse
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}
|
||||||
|
|
||||||
|
tests := []test{
|
||||||
{
|
{
|
||||||
name: "missing permission",
|
name: "missing permission",
|
||||||
ctx: Instance.WithAuthorization(CTX, integration.UserTypeOrgOwner),
|
ctx: Instance.WithAuthorization(CTX, integration.UserTypeOrgOwner),
|
||||||
@@ -73,6 +76,25 @@ func TestServer_CreateOrganization(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
|
func() test {
|
||||||
|
orgName := gofakeit.Name()
|
||||||
|
return test{
|
||||||
|
name: "adding org with same name twice",
|
||||||
|
ctx: CTX,
|
||||||
|
req: &v2beta_org.CreateOrganizationRequest{
|
||||||
|
Name: orgName,
|
||||||
|
Admins: nil,
|
||||||
|
},
|
||||||
|
testfunc: func(ctx context.Context, t *testing.T) {
|
||||||
|
// create org initally
|
||||||
|
_, err := Client.CreateOrganization(ctx, &v2beta_org.CreateOrganizationRequest{
|
||||||
|
Name: orgName,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
}
|
||||||
|
}(),
|
||||||
{
|
{
|
||||||
name: "invalid admin type",
|
name: "invalid admin type",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
@@ -210,9 +232,33 @@ func TestServer_CreateOrganization(t *testing.T) {
|
|||||||
},
|
},
|
||||||
want: &v2beta_org.CreateOrganizationResponse{},
|
want: &v2beta_org.CreateOrganizationResponse{},
|
||||||
},
|
},
|
||||||
|
func() test {
|
||||||
|
orgID := gofakeit.Name()
|
||||||
|
return test{
|
||||||
|
name: "adding org with same ID twice",
|
||||||
|
ctx: CTX,
|
||||||
|
req: &v2beta_org.CreateOrganizationRequest{
|
||||||
|
Name: orgID,
|
||||||
|
Admins: nil,
|
||||||
|
},
|
||||||
|
testfunc: func(ctx context.Context, t *testing.T) {
|
||||||
|
// create org initally
|
||||||
|
_, err := Client.CreateOrganization(ctx, &v2beta_org.CreateOrganizationRequest{
|
||||||
|
Name: gofakeit.AppName(),
|
||||||
|
Id: &orgID,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
}
|
||||||
|
}(),
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.testfunc != nil {
|
||||||
|
tt.testfunc(tt.ctx, t)
|
||||||
|
}
|
||||||
|
|
||||||
got, err := Client.CreateOrganization(tt.ctx, tt.req)
|
got, err := Client.CreateOrganization(tt.ctx, tt.req)
|
||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
@@ -54,16 +54,16 @@ func (mr *MockMessageMockRecorder) GetContent() *gomock.Call {
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContent", reflect.TypeOf((*MockMessage)(nil).GetContent))
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContent", reflect.TypeOf((*MockMessage)(nil).GetContent))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTriggeringEvent mocks base method.
|
// GetTriggeringEventType mocks base method.
|
||||||
func (m *MockMessage) GetTriggeringEvent() eventstore.Event {
|
func (m *MockMessage) GetTriggeringEventType() eventstore.EventType {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "GetTriggeringEvent")
|
ret := m.ctrl.Call(m, "GetTriggeringEventType")
|
||||||
ret0, _ := ret[0].(eventstore.Event)
|
ret0, _ := ret[0].(eventstore.EventType)
|
||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTriggeringEvent indicates an expected call of GetTriggeringEvent.
|
// GetTriggeringEventType indicates an expected call of GetTriggeringEventType.
|
||||||
func (mr *MockMessageMockRecorder) GetTriggeringEvent() *gomock.Call {
|
func (mr *MockMessageMockRecorder) GetTriggeringEventType() *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTriggeringEvent", reflect.TypeOf((*MockMessage)(nil).GetTriggeringEvent))
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTriggeringEventType", reflect.TypeOf((*MockMessage)(nil).GetTriggeringEventType))
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,19 @@ const (
|
|||||||
OrgStateSearchField = "state"
|
OrgStateSearchField = "state"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NewAddOrgIDUniqueConstraint(orgID string) *eventstore.UniqueConstraint {
|
||||||
|
return eventstore.NewAddEventUniqueConstraint(
|
||||||
|
uniqueOrgname,
|
||||||
|
orgID,
|
||||||
|
"Errors.Org.AlreadyExists")
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRemoveOrgIDUniqueConstraint(orgID string) *eventstore.UniqueConstraint {
|
||||||
|
return eventstore.NewRemoveUniqueConstraint(
|
||||||
|
uniqueOrgname,
|
||||||
|
orgID)
|
||||||
|
}
|
||||||
|
|
||||||
func NewAddOrgNameUniqueConstraint(orgName string) *eventstore.UniqueConstraint {
|
func NewAddOrgNameUniqueConstraint(orgName string) *eventstore.UniqueConstraint {
|
||||||
return eventstore.NewAddEventUniqueConstraint(
|
return eventstore.NewAddEventUniqueConstraint(
|
||||||
uniqueOrgname,
|
uniqueOrgname,
|
||||||
@@ -39,6 +52,7 @@ func NewRemoveOrgNameUniqueConstraint(orgName string) *eventstore.UniqueConstrai
|
|||||||
type OrgAddedEvent struct {
|
type OrgAddedEvent struct {
|
||||||
eventstore.BaseEvent `json:"-"`
|
eventstore.BaseEvent `json:"-"`
|
||||||
|
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +61,7 @@ func (e *OrgAddedEvent) Payload() interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *OrgAddedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
|
func (e *OrgAddedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
|
||||||
return []*eventstore.UniqueConstraint{NewAddOrgNameUniqueConstraint(e.Name)}
|
return []*eventstore.UniqueConstraint{NewAddOrgIDUniqueConstraint(e.ID), NewAddOrgNameUniqueConstraint(e.Name)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *OrgAddedEvent) Fields() []*eventstore.FieldOperation {
|
func (e *OrgAddedEvent) Fields() []*eventstore.FieldOperation {
|
||||||
@@ -94,6 +108,7 @@ func NewOrgAddedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name
|
|||||||
aggregate,
|
aggregate,
|
||||||
OrgAddedEventType,
|
OrgAddedEventType,
|
||||||
),
|
),
|
||||||
|
ID: aggregate.ID,
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,6 +291,7 @@ func OrgReactivatedEventMapper(event eventstore.Event) (eventstore.Event, error)
|
|||||||
|
|
||||||
type OrgRemovedEvent struct {
|
type OrgRemovedEvent struct {
|
||||||
eventstore.BaseEvent `json:"-"`
|
eventstore.BaseEvent `json:"-"`
|
||||||
|
id string
|
||||||
name string
|
name string
|
||||||
usernames []string
|
usernames []string
|
||||||
loginMustBeDomain bool
|
loginMustBeDomain bool
|
||||||
@@ -290,6 +306,7 @@ func (e *OrgRemovedEvent) Payload() interface{} {
|
|||||||
|
|
||||||
func (e *OrgRemovedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
|
func (e *OrgRemovedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
|
||||||
constraints := []*eventstore.UniqueConstraint{
|
constraints := []*eventstore.UniqueConstraint{
|
||||||
|
NewRemoveOrgIDUniqueConstraint(e.id),
|
||||||
NewRemoveOrgNameUniqueConstraint(e.name),
|
NewRemoveOrgNameUniqueConstraint(e.name),
|
||||||
}
|
}
|
||||||
for _, name := range e.usernames {
|
for _, name := range e.usernames {
|
||||||
@@ -321,6 +338,7 @@ func NewOrgRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, na
|
|||||||
aggregate,
|
aggregate,
|
||||||
OrgRemovedEventType,
|
OrgRemovedEventType,
|
||||||
),
|
),
|
||||||
|
id: aggregate.ID,
|
||||||
name: name,
|
name: name,
|
||||||
usernames: usernames,
|
usernames: usernames,
|
||||||
domains: domains,
|
domains: domains,
|
||||||
|
@@ -195,7 +195,7 @@ Errors:
|
|||||||
AlreadyExists: Instance already exists
|
AlreadyExists: Instance already exists
|
||||||
NotChanged: Instance not changed
|
NotChanged: Instance not changed
|
||||||
Org:
|
Org:
|
||||||
AlreadyExists: Organisation's name already taken
|
AlreadyExists: Organisation's name or id already taken
|
||||||
Invalid: Organisation is invalid
|
Invalid: Organisation is invalid
|
||||||
AlreadyDeactivated: Organisation is already deactivated
|
AlreadyDeactivated: Organisation is already deactivated
|
||||||
AlreadyActive: Organisation is already active
|
AlreadyActive: Organisation is already active
|
||||||
|
@@ -177,7 +177,7 @@ service OrganizationService {
|
|||||||
responses: {
|
responses: {
|
||||||
key: "409"
|
key: "409"
|
||||||
value: {
|
value: {
|
||||||
description: "Organisation's name already taken";
|
description: "Organisation's name or id already taken";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user