diff --git a/internal/command/main_test.go b/internal/command/main_test.go index b2effffbb0..9eb2e38f54 100644 --- a/internal/command/main_test.go +++ b/internal/command/main_test.go @@ -234,7 +234,7 @@ func (m *mockInstance) DefaultLanguage() language.Tag { } func (m *mockInstance) DefaultOrganisationID() string { - return "orgID" + return "defaultOrgID" } func (m *mockInstance) RequestedDomain() string { diff --git a/internal/command/org.go b/internal/command/org.go index 25aaf4315d..04f38877d4 100644 --- a/internal/command/org.go +++ b/internal/command/org.go @@ -314,6 +314,19 @@ func (c *Commands) RemoveOrg(ctx context.Context, id string) (*domain.ObjectDeta func (c *Commands) prepareRemoveOrg(a *org.Aggregate) preparation.Validation { return func() (preparation.CreateCommands, error) { return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { + instance := authz.GetInstance(ctx) + if a.ID == instance.DefaultOrganisationID() { + return nil, errors.ThrowPreconditionFailed(nil, "COMMA-wG9p1", "Errors.Org.DefaultOrgNotDeletable") + } + err := c.checkProjectExists(ctx, instance.ProjectID(), a.ID) + // if there is no error, the ZITADEL project was found on the org to be deleted + if err == nil { + return nil, errors.ThrowPreconditionFailed(err, "COMMA-AF3JW", "Errors.Org.ZitadelOrgNotDeletable") + } + // "precondition failed" error means the project does not exist, return other errors + if !errors.IsPreconditionFailed(err) { + return nil, err + } writeModel, err := c.getOrgWriteModelByID(ctx, a.ID) if err != nil { return nil, errors.ThrowPreconditionFailed(err, "COMMA-wG9p1", "Errors.Org.NotFound") diff --git a/internal/command/org_test.go b/internal/command/org_test.go index 5ef15301fe..a107964129 100644 --- a/internal/command/org_test.go +++ b/internal/command/org_test.go @@ -1026,11 +1026,53 @@ func TestCommandSide_RemoveOrg(t *testing.T) { args args res res }{ + { + name: "default org, error", + fields: fields{ + eventstore: eventstoreExpect( + t, + ), + }, + args: args{ + ctx: authz.WithInstance(context.Background(), &mockInstance{}), + orgID: "defaultOrgID", + }, + res: res{ + err: errors.IsPreconditionFailed, + }, + }, + { + name: "zitadel org, error", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + project.NewProjectAddedEvent(context.Background(), + &project.NewAggregate("projectID", "org1").Aggregate, + "ZITADEL", + false, + false, + false, + domain.PrivateLabelingSettingUnspecified, + ), + )), + ), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + }, + res: res{ + err: errors.IsPreconditionFailed, + }, + }, { name: "org not found, error", fields: fields{ eventstore: eventstoreExpect( t, + expectFilter(), // zitadel project check expectFilter(), ), }, @@ -1047,6 +1089,7 @@ func TestCommandSide_RemoveOrg(t *testing.T) { fields: fields{ eventstore: eventstoreExpect( t, + expectFilter(), // zitadel project check expectFilter( eventFromEventPusher( org.NewOrgAddedEvent(context.Background(), @@ -1074,6 +1117,7 @@ func TestCommandSide_RemoveOrg(t *testing.T) { fields: fields{ eventstore: eventstoreExpect( t, + expectFilter(), // zitadel project check expectFilter( eventFromEventPusher( org.NewOrgAddedEvent(context.Background(), @@ -1121,6 +1165,7 @@ func TestCommandSide_RemoveOrg(t *testing.T) { fields: fields{ eventstore: eventstoreExpect( t, + expectFilter(), // zitadel project check expectFilter( eventFromEventPusher( org.NewOrgAddedEvent(context.Background(), @@ -1165,6 +1210,7 @@ func TestCommandSide_RemoveOrg(t *testing.T) { fields: fields{ eventstore: eventstoreExpect( t, + expectFilter(), // zitadel project check expectFilter( eventFromEventPusher( org.NewOrgAddedEvent(context.Background(), diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index c91ef5e39b..efe3a28a82 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -155,6 +155,8 @@ Errors: Empty: Organisation ist leer NotFound: Organisation konnte nicht gefunden werden NotChanged: Organisation wurde nicht verändert + DefaultOrgNotDeletable: Default Organisation kann nicht gelöscht werden + ZitadelOrgNotDeletable: Organisation mit ZITADEL Projekt kann nicht gelöscht werden InvalidDomain: Domäne ist ungültig DomainMissing: Domäne fehlt DomainNotOnOrg: Domäne fehlt auf Organisation @@ -928,4 +930,4 @@ Action: PreCreation: Vor Erstellung PostCreation: Nach Erstellung PreUserinfoCreation: Vor Userinfo Erstellung - PreAccessTokenCreation: Vor Access Token Erstellung \ No newline at end of file + PreAccessTokenCreation: Vor Access Token Erstellung diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index 82b107a9f9..580f3b76e2 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -155,6 +155,8 @@ Errors: Empty: Organisation is empty NotFound: Organisation not found NotChanged: Organisation not changed + DefaultOrgNotDeletable: Default Organisation must not be deleted + ZitadelOrgNotDeletable: Organisation with ZITADEL project must not be deleted InvalidDomain: Invalid domain DomainMissing: Domain missing DomainNotOnOrg: Domain doesn't exist on organization @@ -928,4 +930,4 @@ Action: PreCreation: Pre Creation PostCreation: Post Creation PreUserinfoCreation: Pre Userinfo creation - PreAccessTokenCreation: Pre access token creation \ No newline at end of file + PreAccessTokenCreation: Pre access token creation diff --git a/internal/static/i18n/fr.yaml b/internal/static/i18n/fr.yaml index b76df02da8..e04fd4c066 100644 --- a/internal/static/i18n/fr.yaml +++ b/internal/static/i18n/fr.yaml @@ -155,6 +155,8 @@ Errors: Empty: L'organisation est vide NotFound: Organisation non trouvée NotChanged: L'organisation n'a pas changé + DefaultOrgNotDeletable: L'organisation par défault ne doit pas être supprimée + ZitadelOrgNotDeletable: L'organisation avec ZITADEL project ne doit pas être supprimée InvalidDomain: Domaine non valide DomainMissing: Domaine manquant DomainNotOnOrg: Le domaine n'existe pas dans l'organisation @@ -928,4 +930,4 @@ Action: PreCreation: Pré création PostCreation: Post-création PreUserinfoCreation: Pré Userinfo création - PreAccessTokenCreation: Pré access token création \ No newline at end of file + PreAccessTokenCreation: Pré access token création diff --git a/internal/static/i18n/it.yaml b/internal/static/i18n/it.yaml index 6eafdbf4d4..271185ebb8 100644 --- a/internal/static/i18n/it.yaml +++ b/internal/static/i18n/it.yaml @@ -155,6 +155,8 @@ Errors: Empty: L'organizzazione è vuota NotFound: Organizzazione non trovata NotChanged: Organizzazione non cambiata + DefaultOrgNotDeletable: L'organizzazione predefinita non deve essere cancellata + ZitadelOrgNotDeletable: L'organizzazione con il progetto ZITADEL non deve essere cancellata InvalidDomain: Dominio non valido DomainMissing: Dominio mancante DomainNotOnOrg: Il dominio non esistente nell'organizzazione @@ -928,4 +930,4 @@ Action: PreCreation: Pre-creazione PostCreation: Creazione successiva PreUserinfoCreation: Pre userinfo creazione - PreAccessTokenCreation: Pre access token creazione \ No newline at end of file + PreAccessTokenCreation: Pre access token creazione diff --git a/internal/static/i18n/zh.yaml b/internal/static/i18n/zh.yaml index 9e993fe88a..1547e4265b 100644 --- a/internal/static/i18n/zh.yaml +++ b/internal/static/i18n/zh.yaml @@ -155,6 +155,8 @@ Errors: Empty: 组织为空 NotFound: 未找到组织 NotChanged: 组织信息未改变 + DefaultOrgNotDeletable: 默认组织不应删除 + ZitadelOrgNotDeletable: 不得删除与ZITADEL项目有关的组织 InvalidDomain: 无效的域名 DomainMissing: 域名缺失 DomainNotOnOrg: 组织中不存在域