fix(org): adding unique constrants to not allow an org to be added twice with same id

This commit is contained in:
Iraq Jaber
2025-06-26 19:05:58 +02:00
parent 1ebbe275b9
commit 38e12de79c
5 changed files with 82 additions and 18 deletions

View File

@@ -47,14 +47,17 @@ func TestMain(m *testing.M) {
func TestServer_CreateOrganization(t *testing.T) {
idpResp := Instance.AddGenericOAuthProvider(CTX, Instance.DefaultOrg.Id)
tests := []struct {
type test struct {
name string
ctx context.Context
req *v2beta_org.CreateOrganizationRequest
id string
testfunc func(ctx context.Context, t *testing.T)
want *v2beta_org.CreateOrganizationResponse
wantErr bool
}{
}
tests := []test{
{
name: "missing permission",
ctx: Instance.WithAuthorization(CTX, integration.UserTypeOrgOwner),
@@ -73,6 +76,25 @@ func TestServer_CreateOrganization(t *testing.T) {
},
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",
ctx: CTX,
@@ -210,9 +232,33 @@ func TestServer_CreateOrganization(t *testing.T) {
},
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 {
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)
if tt.wantErr {
require.Error(t, err)

View File

@@ -54,16 +54,16 @@ func (mr *MockMessageMockRecorder) GetContent() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContent", reflect.TypeOf((*MockMessage)(nil).GetContent))
}
// GetTriggeringEvent mocks base method.
func (m *MockMessage) GetTriggeringEvent() eventstore.Event {
// GetTriggeringEventType mocks base method.
func (m *MockMessage) GetTriggeringEventType() eventstore.EventType {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTriggeringEvent")
ret0, _ := ret[0].(eventstore.Event)
ret := m.ctrl.Call(m, "GetTriggeringEventType")
ret0, _ := ret[0].(eventstore.EventType)
return ret0
}
// GetTriggeringEvent indicates an expected call of GetTriggeringEvent.
func (mr *MockMessageMockRecorder) GetTriggeringEvent() *gomock.Call {
// GetTriggeringEventType indicates an expected call of GetTriggeringEventType.
func (mr *MockMessageMockRecorder) GetTriggeringEventType() *gomock.Call {
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))
}

View File

@@ -23,6 +23,19 @@ const (
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 {
return eventstore.NewAddEventUniqueConstraint(
uniqueOrgname,
@@ -39,6 +52,7 @@ func NewRemoveOrgNameUniqueConstraint(orgName string) *eventstore.UniqueConstrai
type OrgAddedEvent struct {
eventstore.BaseEvent `json:"-"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
}
@@ -47,7 +61,7 @@ func (e *OrgAddedEvent) Payload() interface{} {
}
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 {
@@ -94,6 +108,7 @@ func NewOrgAddedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name
aggregate,
OrgAddedEventType,
),
ID: aggregate.ID,
Name: name,
}
}
@@ -276,6 +291,7 @@ func OrgReactivatedEventMapper(event eventstore.Event) (eventstore.Event, error)
type OrgRemovedEvent struct {
eventstore.BaseEvent `json:"-"`
id string
name string
usernames []string
loginMustBeDomain bool
@@ -290,6 +306,7 @@ func (e *OrgRemovedEvent) Payload() interface{} {
func (e *OrgRemovedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
constraints := []*eventstore.UniqueConstraint{
NewRemoveOrgIDUniqueConstraint(e.id),
NewRemoveOrgNameUniqueConstraint(e.name),
}
for _, name := range e.usernames {
@@ -321,6 +338,7 @@ func NewOrgRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, na
aggregate,
OrgRemovedEventType,
),
id: aggregate.ID,
name: name,
usernames: usernames,
domains: domains,

View File

@@ -195,7 +195,7 @@ Errors:
AlreadyExists: Instance already exists
NotChanged: Instance not changed
Org:
AlreadyExists: Organisation's name already taken
AlreadyExists: Organisation's name or id already taken
Invalid: Organisation is invalid
AlreadyDeactivated: Organisation is already deactivated
AlreadyActive: Organisation is already active

View File

@@ -177,7 +177,7 @@ service OrganizationService {
responses: {
key: "409"
value: {
description: "Organisation's name already taken";
description: "Organisation's name or id already taken";
}
};
};