From d721f725fd9e59b3cf99978bf499e562d5dc2869 Mon Sep 17 00:00:00 2001 From: Livio Spring Date: Wed, 26 Oct 2022 15:06:48 +0200 Subject: [PATCH] fix: instance remove (#4602) --- .../eventsourcing/handler/styling.go | 10 + .../repository/eventsourcing/view/styling.go | 8 + internal/api/grpc/system/instance.go | 1 + .../eventsourcing/handler/idp_config.go | 2 + .../eventsourcing/handler/idp_providers.go | 2 + .../handler/org_project_mapping.go | 5 +- .../eventsourcing/handler/refresh_token.go | 5 +- .../repository/eventsourcing/handler/token.go | 5 +- .../repository/eventsourcing/handler/user.go | 14 +- .../handler/user_external_idps.go | 2 + .../eventsourcing/handler/user_session.go | 5 +- .../eventsourcing/view/external_idps.go | 8 + .../eventsourcing/view/idp_configs.go | 8 + .../eventsourcing/view/idp_providers.go | 8 + .../eventsourcing/view/org_project_mapping.go | 8 + .../eventsourcing/view/refresh_token.go | 8 + .../repository/eventsourcing/view/token.go | 8 + .../repository/eventsourcing/view/user.go | 8 + .../eventsourcing/view/user_session.go | 8 + internal/command/instance.go | 19 +- internal/command/instance_model.go | 13 +- internal/command/instance_test.go | 173 ++++++++++++++++-- internal/domain/instance.go | 8 +- internal/eventstore/eventstore.go | 20 +- internal/eventstore/repository/sql/crdb.go | 13 +- .../eventstore/repository/sql/crdb_test.go | 39 +++- .../repository/unique_constraint.go | 3 +- internal/eventstore/unique_constraint.go | 7 + .../iam/repository/view/idp_provider_view.go | 5 + internal/iam/repository/view/idp_view.go | 4 + internal/iam/repository/view/styling.go | 5 +- .../view/org_project_mapping_view.go | 5 + internal/query/projection/action_test.go | 2 +- internal/query/projection/app_test.go | 2 +- internal/query/projection/authn_key_test.go | 2 +- internal/query/projection/custom_text_test.go | 2 +- .../debug_notification_provider_test.go | 2 +- .../query/projection/domain_policy_test.go | 2 +- internal/query/projection/flow_test.go | 2 +- .../projection/idp_login_policy_link_test.go | 2 +- internal/query/projection/idp_test.go | 2 +- .../query/projection/idp_user_link_test.go | 2 +- .../query/projection/instance_domain_test.go | 2 +- .../query/projection/instance_member_test.go | 2 +- internal/query/projection/instance_test.go | 2 +- internal/query/projection/key_test.go | 2 +- .../query/projection/label_policy_test.go | 2 +- .../query/projection/lockout_policy_test.go | 2 +- internal/query/projection/login_name.go | 31 +++- internal/query/projection/login_name_test.go | 18 +- .../query/projection/login_policy_test.go | 2 +- internal/query/projection/mail_template.go | 5 - .../query/projection/mail_template_test.go | 2 +- .../query/projection/message_text_test.go | 2 +- internal/query/projection/oidc_settings.go | 5 - .../query/projection/oidc_settings_test.go | 2 +- internal/query/projection/org_domain_test.go | 2 +- internal/query/projection/org_member_test.go | 2 +- internal/query/projection/org_metadata.go | 10 + .../query/projection/org_metadata_test.go | 27 +++ internal/query/projection/org_test.go | 2 +- .../projection/password_age_policy_test.go | 2 +- .../password_complexity_policy_test.go | 2 +- .../query/projection/privacy_policy_test.go | 2 +- .../projection/project_grant_member_test.go | 2 +- .../query/projection/project_grant_test.go | 2 +- .../query/projection/project_member_test.go | 2 +- .../query/projection/project_role_test.go | 2 +- internal/query/projection/project_test.go | 2 +- internal/query/projection/secret_generator.go | 4 + .../query/projection/secret_generator_test.go | 26 +++ internal/query/projection/sms_test.go | 2 +- internal/query/projection/smtp_test.go | 2 +- .../query/projection/user_auth_method_test.go | 2 +- internal/query/projection/user_grant_test.go | 2 +- .../query/projection/user_metadata_test.go | 2 +- .../user_personal_access_token_test.go | 2 +- internal/query/projection/user_test.go | 2 +- internal/repository/instance/instance.go | 29 +-- internal/static/database/crdb.go | 17 ++ internal/static/database/crdb_test.go | 46 +++++ internal/static/mock/storage_mock.go | 14 ++ internal/static/s3/minio.go | 5 + internal/static/storage.go | 1 + .../user/repository/view/external_idp_view.go | 5 + .../repository/view/refresh_token_view.go | 5 + internal/user/repository/view/token_view.go | 5 + .../user/repository/view/user_session_view.go | 5 + internal/user/repository/view/user_view.go | 5 + 89 files changed, 655 insertions(+), 121 deletions(-) diff --git a/internal/admin/repository/eventsourcing/handler/styling.go b/internal/admin/repository/eventsourcing/handler/styling.go index 3b598a6ac..028e116cc 100644 --- a/internal/admin/repository/eventsourcing/handler/styling.go +++ b/internal/admin/repository/eventsourcing/handler/styling.go @@ -150,6 +150,12 @@ func (m *Styling) processLabelPolicy(event *models.Event) (err error) { return err } err = m.generateStylingFile(policy) + case instance.InstanceRemovedEventType: + err = m.deleteInstanceFilesFromStorage(event.InstanceID) + if err != nil { + return err + } + return m.view.DeleteInstanceStyling(event) default: return m.view.ProcessedStylingSequence(event) } @@ -262,6 +268,10 @@ func (m *Styling) uploadFilesToStorage(instanceID, aggregateID, contentType stri return err } +func (m *Styling) deleteInstanceFilesFromStorage(instanceID string) error { + return m.static.RemoveInstanceObjects(context.Background(), instanceID) +} + func (m *Styling) generateColorPaletteRGBA255(hex string) map[string]string { palette := make(map[string]string) defaultColor := gamut.Hex(hex) diff --git a/internal/admin/repository/eventsourcing/view/styling.go b/internal/admin/repository/eventsourcing/view/styling.go index fcecfde64..e0b3aa24a 100644 --- a/internal/admin/repository/eventsourcing/view/styling.go +++ b/internal/admin/repository/eventsourcing/view/styling.go @@ -23,6 +23,14 @@ func (v *View) PutStyling(policy *model.LabelPolicyView, event *models.Event) er return v.ProcessedStylingSequence(event) } +func (v *View) DeleteInstanceStyling(event *models.Event) error { + err := view.DeleteInstanceStyling(v.Db, stylingTyble, event.InstanceID) + if err != nil { + return err + } + return v.ProcessedStylingSequence(event) +} + func (v *View) GetLatestStylingSequence(instanceID string) (*global_view.CurrentSequence, error) { return v.latestSequence(stylingTyble, instanceID) } diff --git a/internal/api/grpc/system/instance.go b/internal/api/grpc/system/instance.go index b5213b7d9..029c8b762 100644 --- a/internal/api/grpc/system/instance.go +++ b/internal/api/grpc/system/instance.go @@ -63,6 +63,7 @@ func (s *Server) UpdateInstance(ctx context.Context, req *system_pb.UpdateInstan } func (s *Server) RemoveInstance(ctx context.Context, req *system_pb.RemoveInstanceRequest) (*system_pb.RemoveInstanceResponse, error) { + ctx = authz.WithInstanceID(ctx, req.InstanceId) details, err := s.command.RemoveInstance(ctx, req.InstanceId) if err != nil { return nil, err diff --git a/internal/auth/repository/eventsourcing/handler/idp_config.go b/internal/auth/repository/eventsourcing/handler/idp_config.go index f5eec3f65..de0315d85 100644 --- a/internal/auth/repository/eventsourcing/handler/idp_config.go +++ b/internal/auth/repository/eventsourcing/handler/idp_config.go @@ -117,6 +117,8 @@ func (i *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve return err } return i.view.DeleteIDPConfig(idp.IDPConfigID, event) + case instance.InstanceRemovedEventType: + return i.view.DeleteInstanceIDPs(event) default: return i.view.ProcessedIDPConfigSequence(event) } diff --git a/internal/auth/repository/eventsourcing/handler/idp_providers.go b/internal/auth/repository/eventsourcing/handler/idp_providers.go index 817b8cf94..7d71340ba 100644 --- a/internal/auth/repository/eventsourcing/handler/idp_providers.go +++ b/internal/auth/repository/eventsourcing/handler/idp_providers.go @@ -138,6 +138,8 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) { return i.view.PutIDPProviders(event, providers...) case org.LoginPolicyRemovedEventType: return i.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event.InstanceID, event) + case instance.InstanceRemovedEventType: + return i.view.DeleteInstanceIDPs(event) default: return i.view.ProcessedIDPProviderSequence(event) } diff --git a/internal/auth/repository/eventsourcing/handler/org_project_mapping.go b/internal/auth/repository/eventsourcing/handler/org_project_mapping.go index d4a87dfc7..414829282 100644 --- a/internal/auth/repository/eventsourcing/handler/org_project_mapping.go +++ b/internal/auth/repository/eventsourcing/handler/org_project_mapping.go @@ -9,6 +9,7 @@ import ( "github.com/zitadel/zitadel/internal/eventstore/v1/query" "github.com/zitadel/zitadel/internal/eventstore/v1/spooler" view_model "github.com/zitadel/zitadel/internal/project/repository/view/model" + "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/project" ) @@ -51,7 +52,7 @@ func (p *OrgProjectMapping) Subscription() *v1.Subscription { } func (_ *OrgProjectMapping) AggregateTypes() []es_models.AggregateType { - return []es_models.AggregateType{project.AggregateType} + return []es_models.AggregateType{project.AggregateType, instance.AggregateType} } func (p *OrgProjectMapping) CurrentSequence(instanceID string) (uint64, error) { @@ -96,6 +97,8 @@ func (p *OrgProjectMapping) Reduce(event *es_models.Event) (err error) { if err == nil { return p.view.ProcessedOrgProjectMappingSequence(event) } + case instance.InstanceRemovedEventType: + return p.view.DeleteInstanceOrgProjectMappings(event) default: return p.view.ProcessedOrgProjectMappingSequence(event) } diff --git a/internal/auth/repository/eventsourcing/handler/refresh_token.go b/internal/auth/repository/eventsourcing/handler/refresh_token.go index 465d5f6a1..7dce7d7c3 100644 --- a/internal/auth/repository/eventsourcing/handler/refresh_token.go +++ b/internal/auth/repository/eventsourcing/handler/refresh_token.go @@ -11,6 +11,7 @@ import ( es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" "github.com/zitadel/zitadel/internal/eventstore/v1/query" "github.com/zitadel/zitadel/internal/eventstore/v1/spooler" + "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/user" view_model "github.com/zitadel/zitadel/internal/user/repository/view/model" @@ -55,7 +56,7 @@ func (t *RefreshToken) Subscription() *v1.Subscription { } func (t *RefreshToken) AggregateTypes() []es_models.AggregateType { - return []es_models.AggregateType{user.AggregateType, project.AggregateType} + return []es_models.AggregateType{user.AggregateType, project.AggregateType, instance.AggregateType} } func (t *RefreshToken) CurrentSequence(instanceID string) (uint64, error) { @@ -109,6 +110,8 @@ func (t *RefreshToken) Reduce(event *es_models.Event) (err error) { user.UserDeactivatedType, user.UserRemovedType: return t.view.DeleteUserRefreshTokens(event.AggregateID, event.InstanceID, event) + case instance.InstanceRemovedEventType: + return t.view.DeleteInstanceRefreshTokens(event) default: return t.view.ProcessedRefreshTokenSequence(event) } diff --git a/internal/auth/repository/eventsourcing/handler/token.go b/internal/auth/repository/eventsourcing/handler/token.go index ddc2d982e..e93ef7b14 100644 --- a/internal/auth/repository/eventsourcing/handler/token.go +++ b/internal/auth/repository/eventsourcing/handler/token.go @@ -16,6 +16,7 @@ import ( proj_model "github.com/zitadel/zitadel/internal/project/model" project_es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model" proj_view "github.com/zitadel/zitadel/internal/project/repository/view" + "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/user" user_repo "github.com/zitadel/zitadel/internal/repository/user" @@ -61,7 +62,7 @@ func (t *Token) Subscription() *v1.Subscription { } func (_ *Token) AggregateTypes() []es_models.AggregateType { - return []es_models.AggregateType{user.AggregateType, project.AggregateType} + return []es_models.AggregateType{user.AggregateType, project.AggregateType, instance.AggregateType} } func (p *Token) CurrentSequence(instanceID string) (uint64, error) { @@ -144,6 +145,8 @@ func (t *Token) Reduce(event *es_models.Event) (err error) { applicationsIDs = append(applicationsIDs, app.AppID) } return t.view.DeleteApplicationTokens(event, applicationsIDs...) + case instance.InstanceRemovedEventType: + return t.view.DeleteInstanceTokens(event) default: return t.view.ProcessedTokenSequence(event) } diff --git a/internal/auth/repository/eventsourcing/handler/user.go b/internal/auth/repository/eventsourcing/handler/user.go index 4ef26886e..e17ecffc9 100644 --- a/internal/auth/repository/eventsourcing/handler/user.go +++ b/internal/auth/repository/eventsourcing/handler/user.go @@ -16,6 +16,7 @@ import ( org_es_model "github.com/zitadel/zitadel/internal/org/repository/eventsourcing/model" "github.com/zitadel/zitadel/internal/org/repository/view" query2 "github.com/zitadel/zitadel/internal/query" + "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/org" user_repo "github.com/zitadel/zitadel/internal/repository/user" usr_view "github.com/zitadel/zitadel/internal/user/repository/view" @@ -63,7 +64,7 @@ func (u *User) Subscription() *v1.Subscription { return u.subscription } func (_ *User) AggregateTypes() []es_models.AggregateType { - return []es_models.AggregateType{user_repo.AggregateType, org.AggregateType} + return []es_models.AggregateType{user_repo.AggregateType, org.AggregateType, instance.AggregateType} } func (u *User) CurrentSequence(instanceID string) (uint64, error) { @@ -88,6 +89,8 @@ func (u *User) Reduce(event *es_models.Event) (err error) { return u.ProcessUser(event) case org.AggregateType: return u.ProcessOrg(event) + case instance.AggregateType: + return u.ProcessInstance(event) default: return nil } @@ -229,6 +232,15 @@ func (u *User) ProcessOrg(event *es_models.Event) (err error) { } } +func (u *User) ProcessInstance(event *es_models.Event) (err error) { + switch eventstore.EventType(event.Type) { + case instance.InstanceRemovedEventType: + return u.view.DeleteInstanceUsers(event) + default: + return u.view.ProcessedUserSequence(event) + } +} + func (u *User) fillLoginNamesOnOrgUsers(event *es_models.Event) error { userLoginMustBeDomain, _, domains, err := u.loginNameInformation(context.Background(), event.ResourceOwner, event.InstanceID) if err != nil { diff --git a/internal/auth/repository/eventsourcing/handler/user_external_idps.go b/internal/auth/repository/eventsourcing/handler/user_external_idps.go index ea8dad08e..101c9e05f 100644 --- a/internal/auth/repository/eventsourcing/handler/user_external_idps.go +++ b/internal/auth/repository/eventsourcing/handler/user_external_idps.go @@ -150,6 +150,8 @@ func (i *ExternalIDP) processIdpConfig(event *es_models.Event) (err error) { i.fillConfigData(provider, config) } return i.view.PutExternalIDPs(event, exterinalIDPs...) + case instance.InstanceRemovedEventType: + return i.view.DeleteInstanceExternalIDPs(event) default: return i.view.ProcessedExternalIDPSequence(event) } diff --git a/internal/auth/repository/eventsourcing/handler/user_session.go b/internal/auth/repository/eventsourcing/handler/user_session.go index 8e3b77eb9..2d81f189f 100644 --- a/internal/auth/repository/eventsourcing/handler/user_session.go +++ b/internal/auth/repository/eventsourcing/handler/user_session.go @@ -17,6 +17,7 @@ import ( org_es_model "github.com/zitadel/zitadel/internal/org/repository/eventsourcing/model" "github.com/zitadel/zitadel/internal/org/repository/view" query2 "github.com/zitadel/zitadel/internal/query" + "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/org" "github.com/zitadel/zitadel/internal/repository/user" view_model "github.com/zitadel/zitadel/internal/user/repository/view/model" @@ -61,7 +62,7 @@ func (u *UserSession) Subscription() *v1.Subscription { } func (_ *UserSession) AggregateTypes() []models.AggregateType { - return []models.AggregateType{user.AggregateType, org.AggregateType} + return []models.AggregateType{user.AggregateType, org.AggregateType, instance.AggregateType} } func (u *UserSession) CurrentSequence(instanceID string) (uint64, error) { @@ -153,6 +154,8 @@ func (u *UserSession) Reduce(event *models.Event) (err error) { return u.fillLoginNamesOnOrgUsers(event) case user.UserRemovedType: return u.view.DeleteUserSessions(event.AggregateID, event.InstanceID, event) + case instance.InstanceRemovedEventType: + return u.view.DeleteInstanceUserSessions(event) default: return u.view.ProcessedUserSessionSequence(event) } diff --git a/internal/auth/repository/eventsourcing/view/external_idps.go b/internal/auth/repository/eventsourcing/view/external_idps.go index 913a145d1..5b7506c18 100644 --- a/internal/auth/repository/eventsourcing/view/external_idps.go +++ b/internal/auth/repository/eventsourcing/view/external_idps.go @@ -56,6 +56,14 @@ func (v *View) DeleteExternalIDPsByUserID(userID, instanceID string, event *mode return v.ProcessedExternalIDPSequence(event) } +func (v *View) DeleteInstanceExternalIDPs(event *models.Event) error { + err := view.DeleteInstanceExternalIDPs(v.Db, externalIDPTable, event.InstanceID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedExternalIDPSequence(event) +} + func (v *View) GetLatestExternalIDPSequence(instanceID string) (*global_view.CurrentSequence, error) { return v.latestSequence(externalIDPTable, instanceID) } diff --git a/internal/auth/repository/eventsourcing/view/idp_configs.go b/internal/auth/repository/eventsourcing/view/idp_configs.go index 1755eba81..15d2f965f 100644 --- a/internal/auth/repository/eventsourcing/view/idp_configs.go +++ b/internal/auth/repository/eventsourcing/view/idp_configs.go @@ -41,6 +41,14 @@ func (v *View) DeleteIDPConfig(idpID string, event *models.Event) error { return v.ProcessedIDPConfigSequence(event) } +func (v *View) DeleteInstanceIDPs(event *models.Event) error { + err := view.DeleteInstanceIDPs(v.Db, idpConfigTable, event.InstanceID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedIDPConfigSequence(event) +} + func (v *View) GetLatestIDPConfigSequence(instanceID string) (*global_view.CurrentSequence, error) { return v.latestSequence(idpConfigTable, instanceID) } diff --git a/internal/auth/repository/eventsourcing/view/idp_providers.go b/internal/auth/repository/eventsourcing/view/idp_providers.go index 4219dbeb4..ff96e5634 100644 --- a/internal/auth/repository/eventsourcing/view/idp_providers.go +++ b/internal/auth/repository/eventsourcing/view/idp_providers.go @@ -61,6 +61,14 @@ func (v *View) DeleteIDPProvidersByAggregateID(aggregateID, instanceID string, e return v.ProcessedIDPProviderSequence(event) } +func (v *View) DeleteInstanceIDPProviders(event *models.Event) error { + err := view.DeleteInstanceIDPProviders(v.Db, idpProviderTable, event.InstanceID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedIDPProviderSequence(event) +} + func (v *View) GetLatestIDPProviderSequence(instanceID string) (*global_view.CurrentSequence, error) { return v.latestSequence(idpProviderTable, instanceID) } diff --git a/internal/auth/repository/eventsourcing/view/org_project_mapping.go b/internal/auth/repository/eventsourcing/view/org_project_mapping.go index 16798544c..6c6ed4e57 100644 --- a/internal/auth/repository/eventsourcing/view/org_project_mapping.go +++ b/internal/auth/repository/eventsourcing/view/org_project_mapping.go @@ -32,6 +32,14 @@ func (v *View) DeleteOrgProjectMapping(orgID, projectID, instanceID string, even return v.ProcessedOrgProjectMappingSequence(event) } +func (v *View) DeleteInstanceOrgProjectMappings(event *models.Event) error { + err := view.DeleteInstanceOrgProjectMappings(v.Db, orgPrgojectMappingTable, event.InstanceID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedOrgProjectMappingSequence(event) +} + func (v *View) DeleteOrgProjectMappingsByProjectID(projectID, instanceID string) error { return view.DeleteOrgProjectMappingsByProjectID(v.Db, orgPrgojectMappingTable, projectID, instanceID) } diff --git a/internal/auth/repository/eventsourcing/view/refresh_token.go b/internal/auth/repository/eventsourcing/view/refresh_token.go index 1c3ea58a2..638c5d44b 100644 --- a/internal/auth/repository/eventsourcing/view/refresh_token.go +++ b/internal/auth/repository/eventsourcing/view/refresh_token.go @@ -65,6 +65,14 @@ func (v *View) DeleteApplicationRefreshTokens(event *models.Event, ids ...string return v.ProcessedRefreshTokenSequence(event) } +func (v *View) DeleteInstanceRefreshTokens(event *models.Event) error { + err := usr_view.DeleteInstanceRefreshTokens(v.Db, refreshTokenTable, event.InstanceID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedRefreshTokenSequence(event) +} + func (v *View) GetLatestRefreshTokenSequence(instanceID string) (*repository.CurrentSequence, error) { return v.latestSequence(refreshTokenTable, instanceID) } diff --git a/internal/auth/repository/eventsourcing/view/token.go b/internal/auth/repository/eventsourcing/view/token.go index a5289f2ef..ffd6f2845 100644 --- a/internal/auth/repository/eventsourcing/view/token.go +++ b/internal/auth/repository/eventsourcing/view/token.go @@ -76,6 +76,14 @@ func (v *View) DeleteTokensFromRefreshToken(refreshTokenID, instanceID string, e return v.ProcessedTokenSequence(event) } +func (v *View) DeleteInstanceTokens(event *models.Event) error { + err := usr_view.DeleteInstanceTokens(v.Db, tokenTable, event.InstanceID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedTokenSequence(event) +} + func (v *View) GetLatestTokenSequence(instanceID string) (*repository.CurrentSequence, error) { return v.latestSequence(tokenTable, instanceID) } diff --git a/internal/auth/repository/eventsourcing/view/user.go b/internal/auth/repository/eventsourcing/view/user.go index e9e14a189..300e69765 100644 --- a/internal/auth/repository/eventsourcing/view/user.go +++ b/internal/auth/repository/eventsourcing/view/user.go @@ -181,6 +181,14 @@ func (v *View) DeleteUser(userID, instanceID string, event *models.Event) error return v.ProcessedUserSequence(event) } +func (v *View) DeleteInstanceUsers(event *models.Event) error { + err := view.DeleteInstanceUsers(v.Db, userTable, event.InstanceID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedUserSequence(event) +} + func (v *View) GetLatestUserSequence(instanceID string) (*repository.CurrentSequence, error) { return v.latestSequence(userTable, instanceID) } diff --git a/internal/auth/repository/eventsourcing/view/user_session.go b/internal/auth/repository/eventsourcing/view/user_session.go index 7c39a98ac..1947ee6e6 100644 --- a/internal/auth/repository/eventsourcing/view/user_session.go +++ b/internal/auth/repository/eventsourcing/view/user_session.go @@ -56,6 +56,14 @@ func (v *View) DeleteUserSessions(userID, instanceID string, event *models.Event return v.ProcessedUserSessionSequence(event) } +func (v *View) DeleteInstanceUserSessions(event *models.Event) error { + err := view.DeleteInstanceUserSessions(v.Db, userSessionTable, event.InstanceID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedUserSessionSequence(event) +} + func (v *View) GetLatestUserSessionSequence(instanceID string) (*repository.CurrentSequence, error) { return v.latestSequence(userSessionTable, instanceID) } diff --git a/internal/command/instance.go b/internal/command/instance.go index 7bf855a63..75a51fc07 100644 --- a/internal/command/instance.go +++ b/internal/command/instance.go @@ -550,7 +550,7 @@ func (c *Commands) prepareUpdateInstance(a *instance.Aggregate, name string) pre if err != nil { return nil, err } - if writeModel.State == domain.InstanceStateUnspecified { + if !writeModel.State.Exists() { return nil, errors.ThrowNotFound(nil, "INST-nuso2m", "Errors.Instance.NotFound") } if writeModel.Name == name { @@ -631,17 +631,16 @@ func (c *Commands) prepareRemoveInstance(a *instance.Aggregate) preparation.Vali return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { writeModel, err := c.getInstanceWriteModelByID(ctx, a.ID) if err != nil { - return nil, errors.ThrowPreconditionFailed(err, "COMMA-pax9m3", "Errors.Instance.NotFound") + return nil, errors.ThrowNotFound(err, "COMMA-pax9m3", "Errors.Instance.NotFound") } - events := []eventstore.Command{instance.NewInstanceRemovedEvent(ctx, &a.Aggregate, writeModel.Name)} - - domainsWriteModel, err := c.getInstanceDomainsWriteModel(ctx, a.ID) - if err == nil { - for _, domainName := range domainsWriteModel.Domains { - events = append(events, instance.NewDomainRemovedEvent(ctx, &a.Aggregate, domainName)) - } + if !writeModel.State.Exists() { + return nil, errors.ThrowNotFound(err, "COMMA-AE3GS", "Errors.Instance.NotFound") } - return events, nil + return []eventstore.Command{instance.NewInstanceRemovedEvent(ctx, + &a.Aggregate, + writeModel.Name, + writeModel.Domains)}, + nil }, nil } } diff --git a/internal/command/instance_model.go b/internal/command/instance_model.go index 17437ec1a..6db058aff 100644 --- a/internal/command/instance_model.go +++ b/internal/command/instance_model.go @@ -14,6 +14,7 @@ type InstanceWriteModel struct { Name string State domain.InstanceState GeneratedDomain string + Domains []string DefaultOrgID string ProjectID string @@ -41,10 +42,16 @@ func (wm *InstanceWriteModel) Reduce() error { case *instance.InstanceRemovedEvent: wm.State = domain.InstanceStateRemoved case *instance.DomainAddedEvent: - if !e.Generated { - continue + if e.Generated { + wm.GeneratedDomain = e.Domain + } + wm.Domains = append(wm.Domains, e.Domain) + case *instance.DomainRemovedEvent: + for _, customDomain := range wm.Domains { + if customDomain == e.Domain { + wm.Domains = removeDomainFromDomains(wm.Domains, e.Domain) + } } - wm.GeneratedDomain = e.Domain case *instance.ProjectSetEvent: wm.ProjectID = e.ProjectID case *instance.DefaultOrgSetEvent: diff --git a/internal/command/instance_test.go b/internal/command/instance_test.go index 5aa88231d..3d29804d0 100644 --- a/internal/command/instance_test.go +++ b/internal/command/instance_test.go @@ -14,14 +14,13 @@ import ( "github.com/zitadel/zitadel/internal/repository/instance" ) -func TestCommandSide_ChangeInstance(t *testing.T) { +func TestCommandSide_UpdateInstance(t *testing.T) { type fields struct { eventstore *eventstore.Eventstore } type args struct { - ctx context.Context - name string - instanceID string + ctx context.Context + name string } type res struct { want *domain.ObjectDetails @@ -41,9 +40,8 @@ func TestCommandSide_ChangeInstance(t *testing.T) { ), }, args: args{ - ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), - instanceID: "INSTANCE", - name: "", + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + name: "", }, res: res{ err: caos_errs.IsErrorInvalidArgument, @@ -58,17 +56,15 @@ func TestCommandSide_ChangeInstance(t *testing.T) { ), }, args: args{ - ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), - instanceID: "INSTANCE", - name: "INSTANCE_CHANGED", + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + name: "INSTANCE_CHANGED", }, res: res{ err: caos_errs.IsNotFound, }, }, - /* instance removed is not yet implemented { - name: "generator removed, not found error", + name: "instance removed, not found error", fields: fields{ eventstore: eventstoreExpect( t, @@ -84,6 +80,7 @@ func TestCommandSide_ChangeInstance(t *testing.T) { instance.NewInstanceRemovedEvent(context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, "INSTANCE", + nil, ), ), ), @@ -96,7 +93,7 @@ func TestCommandSide_ChangeInstance(t *testing.T) { res: res{ err: caos_errs.IsNotFound, }, - },*/ + }, { name: "no changes, precondition error", fields: fields{ @@ -114,9 +111,8 @@ func TestCommandSide_ChangeInstance(t *testing.T) { ), }, args: args{ - ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), - instanceID: "INSTANCE", - name: "INSTANCE", + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + name: "INSTANCE", }, res: res{ err: caos_errs.IsPreconditionFailed, @@ -178,3 +174,148 @@ func TestCommandSide_ChangeInstance(t *testing.T) { }) } } + +func TestCommandSide_RemoveInstance(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + } + type args struct { + ctx context.Context + instanceID string + } + type res struct { + want *domain.ObjectDetails + err func(error) bool + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "instance not existing, not found error", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter(), + ), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + instanceID: "INSTANCE", + }, + res: res{ + err: caos_errs.IsNotFound, + }, + }, + { + name: "instance removed, not found error", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + instance.NewInstanceAddedEvent( + context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "INSTANCE", + ), + ), + eventFromEventPusher( + instance.NewInstanceRemovedEvent(context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "INSTANCE", + nil, + ), + ), + ), + ), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + instanceID: "INSTANCE", + }, + res: res{ + err: caos_errs.IsNotFound, + }, + }, + { + name: "instance remove, ok", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusherWithInstanceID( + "INSTANCE", + instance.NewInstanceAddedEvent(context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "INSTANCE", + ), + ), + eventFromEventPusherWithInstanceID( + "INSTANCE", + instance.NewDomainAddedEvent(context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "instance.domain", + true, + ), + ), + eventFromEventPusherWithInstanceID( + "INSTANCE", + instance.NewDomainAddedEvent(context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "custom.domain", + false, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID( + "INSTANCE", + instance.NewInstanceRemovedEvent(context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "INSTANCE", + []string{ + "instance.domain", + "custom.domain", + }, + ), + ), + }, + uniqueConstraintsFromEventConstraint(instance.NewRemoveInstanceDomainUniqueConstraint("instance.domain")), + uniqueConstraintsFromEventConstraint(instance.NewRemoveInstanceDomainUniqueConstraint("custom.domain")), + uniqueConstraintsFromEventConstraintWithInstanceID("INSTANCE", eventstore.NewRemoveInstanceUniqueConstraints()), + ), + ), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + instanceID: "INSTANCE", + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "INSTANCE", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore, + } + got, err := r.RemoveInstance(tt.args.ctx, tt.args.instanceID) + if tt.res.err == nil { + assert.NoError(t, err) + } + if tt.res.err != nil && !tt.res.err(err) { + t.Errorf("got wrong err: %v ", err) + } + if tt.res.err == nil { + assert.Equal(t, tt.res.want, got) + } + }) + } +} diff --git a/internal/domain/instance.go b/internal/domain/instance.go index 4a53cdc10..a2d1b7134 100644 --- a/internal/domain/instance.go +++ b/internal/domain/instance.go @@ -14,6 +14,10 @@ const ( instanceStateCount ) -func (f InstanceState) Valid() bool { - return f >= 0 && f < instanceStateCount +func (s InstanceState) Valid() bool { + return s >= 0 && s < instanceStateCount +} + +func (s InstanceState) Exists() bool { + return s != InstanceStateUnspecified && s != InstanceStateRemoved } diff --git a/internal/eventstore/eventstore.go b/internal/eventstore/eventstore.go index 5340b0c3e..962466498 100644 --- a/internal/eventstore/eventstore.go +++ b/internal/eventstore/eventstore.go @@ -12,7 +12,7 @@ import ( "github.com/zitadel/zitadel/internal/eventstore/repository" ) -//Eventstore abstracts all functions needed to store valid events +// Eventstore abstracts all functions needed to store valid events // and filters the stored events type Eventstore struct { repo repository.Repository @@ -32,13 +32,13 @@ func NewEventstore(repo repository.Repository) *Eventstore { } } -//Health checks if the eventstore can properly work +// Health checks if the eventstore can properly work // It checks if the repository can serve load func (es *Eventstore) Health(ctx context.Context) error { return es.repo.Health(ctx) } -//Push pushes the events in a single transaction +// Push pushes the events in a single transaction // an event needs at least an aggregate func (es *Eventstore) Push(ctx context.Context, cmds ...Command) ([]Event, error) { events, constraints, err := commandsToRepository(authz.GetInstance(ctx).InstanceID(), cmds) @@ -119,7 +119,7 @@ func uniqueConstraintsToRepository(instanceID string, constraints []*EventUnique return uniqueConstraints } -//Filter filters the stored events based on the searchQuery +// Filter filters the stored events based on the searchQuery // and maps the events to the defined event structs func (es *Eventstore) Filter(ctx context.Context, queryFactory *SearchQueryBuilder) ([]Event, error) { query, err := queryFactory.build(authz.GetInstance(ctx).InstanceID()) @@ -165,7 +165,7 @@ type reducer interface { AppendEvents(...Event) } -//FilterToReducer filters the events based on the search query, appends all events to the reducer and calls it's reduce function +// FilterToReducer filters the events based on the search query, appends all events to the reducer and calls it's reduce function func (es *Eventstore) FilterToReducer(ctx context.Context, searchQuery *SearchQueryBuilder, r reducer) error { events, err := es.Filter(ctx, searchQuery) if err != nil { @@ -177,7 +177,7 @@ func (es *Eventstore) FilterToReducer(ctx context.Context, searchQuery *SearchQu return r.Reduce() } -//LatestSequence filters the latest sequence for the given search query +// LatestSequence filters the latest sequence for the given search query func (es *Eventstore) LatestSequence(ctx context.Context, queryFactory *SearchQueryBuilder) (uint64, error) { query, err := queryFactory.build(authz.GetInstance(ctx).InstanceID()) if err != nil { @@ -186,7 +186,7 @@ func (es *Eventstore) LatestSequence(ctx context.Context, queryFactory *SearchQu return es.repo.LatestSequence(ctx, query) } -//InstanceIDs returns the instance ids found by the search query +// InstanceIDs returns the instance ids found by the search query func (es *Eventstore) InstanceIDs(ctx context.Context, queryFactory *SearchQueryBuilder) ([]string, error) { query, err := queryFactory.build(authz.GetInstance(ctx).InstanceID()) if err != nil { @@ -201,7 +201,7 @@ type QueryReducer interface { Query() *SearchQueryBuilder } -//FilterToQueryReducer filters the events based on the search query of the query function, +// FilterToQueryReducer filters the events based on the search query of the query function, // appends all events to the reducer and calls it's reduce function func (es *Eventstore) FilterToQueryReducer(ctx context.Context, r QueryReducer) error { events, err := es.Filter(ctx, r.Query()) @@ -213,7 +213,7 @@ func (es *Eventstore) FilterToQueryReducer(ctx context.Context, r QueryReducer) return r.Reduce() } -//RegisterFilterEventMapper registers a function for mapping an eventstore event to an event +// RegisterFilterEventMapper registers a function for mapping an eventstore event to an event func (es *Eventstore) RegisterFilterEventMapper(eventType EventType, mapper func(*repository.Event) (Event, error)) *Eventstore { if mapper == nil || eventType == "" { return es @@ -258,6 +258,8 @@ func uniqueConstraintActionToRepository(action UniqueConstraintAction) repositor return repository.UniqueConstraintAdd case UniqueConstraintRemove: return repository.UniqueConstraintRemoved + case UniqueConstraintInstanceRemove: + return repository.UniqueConstraintInstanceRemoved default: return repository.UniqueConstraintAdd } diff --git a/internal/eventstore/repository/sql/crdb.go b/internal/eventstore/repository/sql/crdb.go index afd475dde..d78311aaa 100644 --- a/internal/eventstore/repository/sql/crdb.go +++ b/internal/eventstore/repository/sql/crdb.go @@ -92,6 +92,8 @@ const ( uniqueDelete = `DELETE FROM eventstore.unique_constraints WHERE unique_type = $1 and unique_field = $2 and instance_id = $3` + uniqueDeleteInstance = `DELETE FROM eventstore.unique_constraints + WHERE instance_id = $1` ) type CRDB struct { @@ -193,7 +195,7 @@ func (db *CRDB) handleUniqueConstraints(ctx context.Context, tx *sql.Tx, uniqueC return caos_errs.ThrowAlreadyExists(err, "SQL-M0dsf", uniqueConstraint.ErrorMessage) } - return caos_errs.ThrowInternal(err, "SQL-dM9ds", "unable to create unique constraint ") + return caos_errs.ThrowInternal(err, "SQL-dM9ds", "unable to create unique constraint") } case repository.UniqueConstraintRemoved: _, err := tx.ExecContext(ctx, uniqueDelete, uniqueConstraint.UniqueType, uniqueConstraint.UniqueField, uniqueConstraint.InstanceID) @@ -201,7 +203,14 @@ func (db *CRDB) handleUniqueConstraints(ctx context.Context, tx *sql.Tx, uniqueC logging.WithFields( "unique_type", uniqueConstraint.UniqueType, "unique_field", uniqueConstraint.UniqueField).WithError(err).Info("delete unique constraint failed") - return caos_errs.ThrowInternal(err, "SQL-6n88i", "unable to remove unique constraint ") + return caos_errs.ThrowInternal(err, "SQL-6n88i", "unable to remove unique constraint") + } + case repository.UniqueConstraintInstanceRemoved: + _, err := tx.ExecContext(ctx, uniqueDeleteInstance, uniqueConstraint.InstanceID) + if err != nil { + logging.WithFields( + "instance_id", uniqueConstraint.InstanceID).WithError(err).Info("delete instance unique constraints failed") + return caos_errs.ThrowInternal(err, "SQL-6n88i", "unable to remove unique constraints of instance") } } } diff --git a/internal/eventstore/repository/sql/crdb_test.go b/internal/eventstore/repository/sql/crdb_test.go index 369012baa..5bae721be 100644 --- a/internal/eventstore/repository/sql/crdb_test.go +++ b/internal/eventstore/repository/sql/crdb_test.go @@ -379,24 +379,28 @@ func TestCRDB_Push_OneAggregate(t *testing.T) { }}, }, { - name: "push 1 event and add asset", + name: "push 1 event and remove instance unique constraints", args: args{ ctx: context.Background(), events: []*repository.Event{ generateEvent(t, "12"), }, + uniqueConstraints: generateRemoveInstanceUniqueConstraints(t, "instanceID"), + uniqueDataType: "usernames", + uniqueDataField: "testremove", + uniqueDataInstanceID: "instanceID", }, res: res{ wantErr: false, eventsRes: eventsRes{ pushedEventsCount: 1, - assetCount: 1, + uniqueCount: 0, aggID: []string{"12"}, aggType: repository.AggregateType(t.Name()), }}, }, { - name: "push 1 event and remove asset", + name: "push 1 event and add asset", args: args{ ctx: context.Background(), events: []*repository.Event{ @@ -407,11 +411,28 @@ func TestCRDB_Push_OneAggregate(t *testing.T) { wantErr: false, eventsRes: eventsRes{ pushedEventsCount: 1, - assetCount: 0, + assetCount: 1, aggID: []string{"13"}, aggType: repository.AggregateType(t.Name()), }}, }, + { + name: "push 1 event and remove asset", + args: args{ + ctx: context.Background(), + events: []*repository.Event{ + generateEvent(t, "14"), + }, + }, + res: res{ + wantErr: false, + eventsRes: eventsRes{ + pushedEventsCount: 1, + assetCount: 0, + aggID: []string{"14"}, + aggType: repository.AggregateType(t.Name()), + }}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1201,3 +1222,13 @@ func generateRemoveUniqueConstraint(t *testing.T, table, uniqueField string) *re return e } + +func generateRemoveInstanceUniqueConstraints(t *testing.T, instanceID string) *repository.UniqueConstraint { + t.Helper() + e := &repository.UniqueConstraint{ + InstanceID: instanceID, + Action: repository.UniqueConstraintInstanceRemoved, + } + + return e +} diff --git a/internal/eventstore/repository/unique_constraint.go b/internal/eventstore/repository/unique_constraint.go index 0a3643228..96d05d1e2 100644 --- a/internal/eventstore/repository/unique_constraint.go +++ b/internal/eventstore/repository/unique_constraint.go @@ -1,6 +1,6 @@ package repository -//UniqueCheck represents all information about a unique attribute +// UniqueCheck represents all information about a unique attribute type UniqueConstraint struct { //UniqueField is the field which should be unique UniqueField string @@ -23,6 +23,7 @@ type UniqueConstraintAction int32 const ( UniqueConstraintAdd UniqueConstraintAction = iota UniqueConstraintRemoved + UniqueConstraintInstanceRemoved uniqueConstraintActionCount ) diff --git a/internal/eventstore/unique_constraint.go b/internal/eventstore/unique_constraint.go index 36a9f3a1a..4c329c456 100644 --- a/internal/eventstore/unique_constraint.go +++ b/internal/eventstore/unique_constraint.go @@ -18,6 +18,7 @@ type UniqueConstraintAction int32 const ( UniqueConstraintAdd UniqueConstraintAction = iota UniqueConstraintRemove + UniqueConstraintInstanceRemove ) func NewAddEventUniqueConstraint( @@ -42,6 +43,12 @@ func NewRemoveEventUniqueConstraint( } } +func NewRemoveInstanceUniqueConstraints() *EventUniqueConstraint { + return &EventUniqueConstraint{ + Action: UniqueConstraintInstanceRemove, + } +} + func NewAddGlobalEventUniqueConstraint( uniqueType, uniqueField, diff --git a/internal/iam/repository/view/idp_provider_view.go b/internal/iam/repository/view/idp_provider_view.go index 1c0e00ad7..913038adf 100644 --- a/internal/iam/repository/view/idp_provider_view.go +++ b/internal/iam/repository/view/idp_provider_view.go @@ -112,3 +112,8 @@ func DeleteIDPProvidersByAggregateID(db *gorm.DB, table, aggregateID, instanceID ) return delete(db) } + +func DeleteInstanceIDPProviders(db *gorm.DB, table, instanceID string) error { + delete := repository.PrepareDeleteByKey(table, model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), instanceID) + return delete(db) +} diff --git a/internal/iam/repository/view/idp_view.go b/internal/iam/repository/view/idp_view.go index 965c64196..d88a03b95 100644 --- a/internal/iam/repository/view/idp_view.go +++ b/internal/iam/repository/view/idp_view.go @@ -63,6 +63,10 @@ func DeleteIDP(db *gorm.DB, table, idpID, instanceID string) error { repository.Key{model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyIdpConfigID), idpID}, repository.Key{model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), instanceID}, ) + return delete(db) +} +func DeleteInstanceIDPs(db *gorm.DB, table, instanceID string) error { + delete := repository.PrepareDeleteByKey(table, model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), instanceID) return delete(db) } diff --git a/internal/iam/repository/view/styling.go b/internal/iam/repository/view/styling.go index cc29b1bbc..2d337717b 100644 --- a/internal/iam/repository/view/styling.go +++ b/internal/iam/repository/view/styling.go @@ -28,8 +28,7 @@ func PutStyling(db *gorm.DB, table string, policy *model.LabelPolicyView) error return save(db, policy) } -func DeleteStyling(db *gorm.DB, table, aggregateID string) error { - delete := repository.PrepareDeleteByKey(table, model.LabelPolicySearchKey(iam_model.LabelPolicySearchKeyAggregateID), aggregateID) - +func DeleteInstanceStyling(db *gorm.DB, table, instanceID string) error { + delete := repository.PrepareDeleteByKey(table, model.LabelPolicySearchKey(iam_model.LabelPolicySearchKeyInstanceID), instanceID) return delete(db) } diff --git a/internal/project/repository/view/org_project_mapping_view.go b/internal/project/repository/view/org_project_mapping_view.go index f1326fd7a..ac4299461 100644 --- a/internal/project/repository/view/org_project_mapping_view.go +++ b/internal/project/repository/view/org_project_mapping_view.go @@ -37,6 +37,11 @@ func DeleteOrgProjectMapping(db *gorm.DB, table, orgID, projectID, instanceID st return delete(db) } +func DeleteInstanceOrgProjectMappings(db *gorm.DB, table, instanceID string) error { + delete := repository.PrepareDeleteByKey(table, model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyInstanceID), instanceID) + return delete(db) +} + func DeleteOrgProjectMappingsByProjectID(db *gorm.DB, table, projectID, instanceID string) error { delete := repository.PrepareDeleteByKeys(table, repository.Key{model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyProjectID), projectID}, diff --git a/internal/query/projection/action_test.go b/internal/query/projection/action_test.go index d3fabf497..44116604e 100644 --- a/internal/query/projection/action_test.go +++ b/internal/query/projection/action_test.go @@ -179,7 +179,7 @@ func TestActionProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(ActionInstanceIDCol), diff --git a/internal/query/projection/app_test.go b/internal/query/projection/app_test.go index d4671518f..256e27d2b 100644 --- a/internal/query/projection/app_test.go +++ b/internal/query/projection/app_test.go @@ -220,7 +220,7 @@ func TestAppProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(AppColumnInstanceID), diff --git a/internal/query/projection/authn_key_test.go b/internal/query/projection/authn_key_test.go index de7d8f91b..d7fa8bdeb 100644 --- a/internal/query/projection/authn_key_test.go +++ b/internal/query/projection/authn_key_test.go @@ -226,7 +226,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(AuthNKeyInstanceIDCol), diff --git a/internal/query/projection/custom_text_test.go b/internal/query/projection/custom_text_test.go index 92ad372ed..d98e93974 100644 --- a/internal/query/projection/custom_text_test.go +++ b/internal/query/projection/custom_text_test.go @@ -132,7 +132,7 @@ func TestCustomTextProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(CustomTextInstanceIDCol), diff --git a/internal/query/projection/debug_notification_provider_test.go b/internal/query/projection/debug_notification_provider_test.go index 8a4a457fd..79446f759 100644 --- a/internal/query/projection/debug_notification_provider_test.go +++ b/internal/query/projection/debug_notification_provider_test.go @@ -217,7 +217,7 @@ func TestDebugNotificationProviderProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(DebugNotificationProviderInstanceIDCol), diff --git a/internal/query/projection/domain_policy_test.go b/internal/query/projection/domain_policy_test.go index 927c57c6a..d0e72bf76 100644 --- a/internal/query/projection/domain_policy_test.go +++ b/internal/query/projection/domain_policy_test.go @@ -129,7 +129,7 @@ func TestDomainPolicyProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(DomainPolicyInstanceIDCol), diff --git a/internal/query/projection/flow_test.go b/internal/query/projection/flow_test.go index 2716cfb01..faadcc985 100644 --- a/internal/query/projection/flow_test.go +++ b/internal/query/projection/flow_test.go @@ -109,7 +109,7 @@ func TestFlowProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(FlowInstanceIDCol), diff --git a/internal/query/projection/idp_login_policy_link_test.go b/internal/query/projection/idp_login_policy_link_test.go index 1a4c7043f..ee61e4ea2 100644 --- a/internal/query/projection/idp_login_policy_link_test.go +++ b/internal/query/projection/idp_login_policy_link_test.go @@ -190,7 +190,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(IDPUserLinkInstanceIDCol), diff --git a/internal/query/projection/idp_test.go b/internal/query/projection/idp_test.go index 6fe3a3abe..8f5c46e91 100644 --- a/internal/query/projection/idp_test.go +++ b/internal/query/projection/idp_test.go @@ -201,7 +201,7 @@ func TestIDPProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(IDPInstanceIDCol), diff --git a/internal/query/projection/idp_user_link_test.go b/internal/query/projection/idp_user_link_test.go index e30953fc8..a72eaaa8c 100644 --- a/internal/query/projection/idp_user_link_test.go +++ b/internal/query/projection/idp_user_link_test.go @@ -154,7 +154,7 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(IDPUserLinkInstanceIDCol), diff --git a/internal/query/projection/instance_domain_test.go b/internal/query/projection/instance_domain_test.go index adc6a272d..68eb2e1f7 100644 --- a/internal/query/projection/instance_domain_test.go +++ b/internal/query/projection/instance_domain_test.go @@ -85,7 +85,7 @@ func TestInstanceDomainProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(InstanceDomainInstanceIDCol), diff --git a/internal/query/projection/instance_member_test.go b/internal/query/projection/instance_member_test.go index 63353c0d0..debfb8bf8 100644 --- a/internal/query/projection/instance_member_test.go +++ b/internal/query/projection/instance_member_test.go @@ -178,7 +178,7 @@ func TestInstanceMemberProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(MemberInstanceID), diff --git a/internal/query/projection/instance_test.go b/internal/query/projection/instance_test.go index 251316885..8287c3669 100644 --- a/internal/query/projection/instance_test.go +++ b/internal/query/projection/instance_test.go @@ -56,7 +56,7 @@ func TestInstanceProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(InstanceColumnID), diff --git a/internal/query/projection/key_test.go b/internal/query/projection/key_test.go index 5aeb3c53c..a915b8fc2 100644 --- a/internal/query/projection/key_test.go +++ b/internal/query/projection/key_test.go @@ -106,7 +106,7 @@ func TestKeyProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(KeyColumnInstanceID), diff --git a/internal/query/projection/label_policy_test.go b/internal/query/projection/label_policy_test.go index a5a1743aa..50616f5ab 100644 --- a/internal/query/projection/label_policy_test.go +++ b/internal/query/projection/label_policy_test.go @@ -131,7 +131,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(LabelPolicyInstanceIDCol), diff --git a/internal/query/projection/lockout_policy_test.go b/internal/query/projection/lockout_policy_test.go index 1b07e5c4b..d1792d1b5 100644 --- a/internal/query/projection/lockout_policy_test.go +++ b/internal/query/projection/lockout_policy_test.go @@ -125,7 +125,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(LockoutPolicyInstanceIDCol), diff --git a/internal/query/projection/login_name.go b/internal/query/projection/login_name.go index cb7b29128..49a916d6c 100644 --- a/internal/query/projection/login_name.go +++ b/internal/query/projection/login_name.go @@ -213,7 +213,7 @@ func (p *loginNameProjection) reducers() []handler.AggregateReducer { }, { Event: instance.InstanceRemovedEventType, - Reduce: reduceInstanceRemovedHelper(LoginNameUserInstanceIDCol), + Reduce: p.reduceInstanceRemoved, }, }, }, @@ -432,3 +432,32 @@ func (p *loginNameProjection) reduceDomainRemoved(event eventstore.Event) (*hand crdb.WithTableSuffix(loginNameDomainSuffix), ), nil } + +func (p *loginNameProjection) reduceInstanceRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*instance.InstanceRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-ASeg3", "reduce.wrong.event.type %s", instance.InstanceRemovedEventType) + } + + return crdb.NewMultiStatement( + event, + crdb.AddDeleteStatement( + []handler.Condition{ + handler.NewCond(LoginNameDomainInstanceIDCol, e.Aggregate().ID), + }, + crdb.WithTableSuffix(loginNameDomainSuffix), + ), + crdb.AddDeleteStatement( + []handler.Condition{ + handler.NewCond(LoginNamePoliciesInstanceIDCol, e.Aggregate().ID), + }, + crdb.WithTableSuffix(loginNamePolicySuffix), + ), + crdb.AddDeleteStatement( + []handler.Condition{ + handler.NewCond(LoginNameUserInstanceIDCol, e.Aggregate().ID), + }, + crdb.WithTableSuffix(loginNameUserSuffix), + ), + ), nil +} diff --git a/internal/query/projection/login_name_test.go b/internal/query/projection/login_name_test.go index 36602192e..c18961e50 100644 --- a/internal/query/projection/login_name_test.go +++ b/internal/query/projection/login_name_test.go @@ -486,10 +486,10 @@ func TestLoginNameProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, - reduce: reduceInstanceRemovedHelper(LoginNameUserInstanceIDCol), + reduce: (&loginNameProjection{}).reduceInstanceRemoved, want: wantReduce{ aggregateType: eventstore.AggregateType("instance"), sequence: 15, @@ -497,7 +497,19 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.login_names WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.login_names_domains WHERE (instance_id = $1)", + expectedArgs: []interface{}{ + "agg-id", + }, + }, + { + expectedStmt: "DELETE FROM projections.login_names_policies WHERE (instance_id = $1)", + expectedArgs: []interface{}{ + "agg-id", + }, + }, + { + expectedStmt: "DELETE FROM projections.login_names_users WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/login_policy_test.go b/internal/query/projection/login_policy_test.go index 35ebc9377..b98a41075 100644 --- a/internal/query/projection/login_policy_test.go +++ b/internal/query/projection/login_policy_test.go @@ -543,7 +543,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(LoginPolicyInstanceIDCol), diff --git a/internal/query/projection/mail_template.go b/internal/query/projection/mail_template.go index d7bb7e553..8bc939381 100644 --- a/internal/query/projection/mail_template.go +++ b/internal/query/projection/mail_template.go @@ -82,11 +82,6 @@ func (p *mailTemplateProjection) reducers() []handler.AggregateReducer { Event: instance.MailTemplateChangedEventType, Reduce: p.reduceChanged, }, - }, - }, - { - Aggregate: instance.AggregateType, - EventRedusers: []handler.EventReducer{ { Event: instance.InstanceRemovedEventType, Reduce: reduceInstanceRemovedHelper(MailTemplateInstanceIDCol), diff --git a/internal/query/projection/mail_template_test.go b/internal/query/projection/mail_template_test.go index 86188c8cc..25f744148 100644 --- a/internal/query/projection/mail_template_test.go +++ b/internal/query/projection/mail_template_test.go @@ -120,7 +120,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(MailTemplateInstanceIDCol), diff --git a/internal/query/projection/message_text_test.go b/internal/query/projection/message_text_test.go index 1eb7fe549..659aa8b87 100644 --- a/internal/query/projection/message_text_test.go +++ b/internal/query/projection/message_text_test.go @@ -336,7 +336,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(MessageTextInstanceIDCol), diff --git a/internal/query/projection/oidc_settings.go b/internal/query/projection/oidc_settings.go index c603d254d..7e1cf0cad 100644 --- a/internal/query/projection/oidc_settings.go +++ b/internal/query/projection/oidc_settings.go @@ -66,11 +66,6 @@ func (p *oidcSettingsProjection) reducers() []handler.AggregateReducer { Event: instance.OIDCSettingsChangedEventType, Reduce: p.reduceOIDCSettingsChanged, }, - }, - }, - { - Aggregate: instance.AggregateType, - EventRedusers: []handler.EventReducer{ { Event: instance.InstanceRemovedEventType, Reduce: reduceInstanceRemovedHelper(OIDCSettingsColumnInstanceID), diff --git a/internal/query/projection/oidc_settings_test.go b/internal/query/projection/oidc_settings_test.go index 832d06fd6..35a9dbe46 100644 --- a/internal/query/projection/oidc_settings_test.go +++ b/internal/query/projection/oidc_settings_test.go @@ -94,7 +94,7 @@ func TestOIDCSettingsProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(OIDCSettingsColumnInstanceID), diff --git a/internal/query/projection/org_domain_test.go b/internal/query/projection/org_domain_test.go index 4395d2abe..14538088e 100644 --- a/internal/query/projection/org_domain_test.go +++ b/internal/query/projection/org_domain_test.go @@ -194,7 +194,7 @@ func TestOrgDomainProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(OrgDomainInstanceIDCol), diff --git a/internal/query/projection/org_member_test.go b/internal/query/projection/org_member_test.go index 2c8d9d083..dfed98867 100644 --- a/internal/query/projection/org_member_test.go +++ b/internal/query/projection/org_member_test.go @@ -208,7 +208,7 @@ func TestOrgMemberProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(MemberInstanceID), diff --git a/internal/query/projection/org_metadata.go b/internal/query/projection/org_metadata.go index 095b39379..cc2040015 100644 --- a/internal/query/projection/org_metadata.go +++ b/internal/query/projection/org_metadata.go @@ -7,6 +7,7 @@ import ( "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler" "github.com/zitadel/zitadel/internal/eventstore/handler/crdb" + "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/org" ) @@ -73,6 +74,15 @@ func (p *orgMetadataProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: instance.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: instance.InstanceRemovedEventType, + Reduce: reduceInstanceRemovedHelper(OrgMetadataColumnInstanceID), + }, + }, + }, } } diff --git a/internal/query/projection/org_metadata_test.go b/internal/query/projection/org_metadata_test.go index 7578396ba..5df31353a 100644 --- a/internal/query/projection/org_metadata_test.go +++ b/internal/query/projection/org_metadata_test.go @@ -7,6 +7,7 @@ import ( "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler" "github.com/zitadel/zitadel/internal/eventstore/repository" + "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/org" ) @@ -137,6 +138,32 @@ func TestOrgMetadataProjection_reduces(t *testing.T) { }, }, }, + { + name: "reduceInstanceRemoved", + args: args{ + event: getEvent(testEvent( + repository.EventType(instance.InstanceRemovedEventType), + instance.AggregateType, + nil, + ), instance.InstanceRemovedEventMapper), + }, + reduce: reduceInstanceRemovedHelper(MemberInstanceID), + want: wantReduce{ + aggregateType: eventstore.AggregateType("instance"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "DELETE FROM projections.org_metadata WHERE (instance_id = $1)", + expectedArgs: []interface{}{ + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/org_test.go b/internal/query/projection/org_test.go index 2dbd07159..1bfda2ead 100644 --- a/internal/query/projection/org_test.go +++ b/internal/query/projection/org_test.go @@ -194,7 +194,7 @@ func TestOrgProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(OrgColumnInstanceID), diff --git a/internal/query/projection/password_age_policy_test.go b/internal/query/projection/password_age_policy_test.go index a6f256f31..c4e020624 100644 --- a/internal/query/projection/password_age_policy_test.go +++ b/internal/query/projection/password_age_policy_test.go @@ -125,7 +125,7 @@ func TestPasswordAgeProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(AgePolicyInstanceIDCol), diff --git a/internal/query/projection/password_complexity_policy_test.go b/internal/query/projection/password_complexity_policy_test.go index e8bd38d56..46f901515 100644 --- a/internal/query/projection/password_complexity_policy_test.go +++ b/internal/query/projection/password_complexity_policy_test.go @@ -137,7 +137,7 @@ func TestPasswordComplexityProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(ComplexityPolicyInstanceIDCol), diff --git a/internal/query/projection/privacy_policy_test.go b/internal/query/projection/privacy_policy_test.go index 89fcb2e42..5186039ba 100644 --- a/internal/query/projection/privacy_policy_test.go +++ b/internal/query/projection/privacy_policy_test.go @@ -128,7 +128,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(PrivacyPolicyInstanceIDCol), diff --git a/internal/query/projection/project_grant_member_test.go b/internal/query/projection/project_grant_member_test.go index a8ad644e1..358818859 100644 --- a/internal/query/projection/project_grant_member_test.go +++ b/internal/query/projection/project_grant_member_test.go @@ -216,7 +216,7 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(MemberInstanceID), diff --git a/internal/query/projection/project_grant_test.go b/internal/query/projection/project_grant_test.go index 37ea862bd..961f1ed10 100644 --- a/internal/query/projection/project_grant_test.go +++ b/internal/query/projection/project_grant_test.go @@ -55,7 +55,7 @@ func TestProjectGrantProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(ProjectGrantColumnInstanceID), diff --git a/internal/query/projection/project_member_test.go b/internal/query/projection/project_member_test.go index fcf08a1d7..85174795b 100644 --- a/internal/query/projection/project_member_test.go +++ b/internal/query/projection/project_member_test.go @@ -209,7 +209,7 @@ func TestProjectMemberProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(MemberInstanceID), diff --git a/internal/query/projection/project_role_test.go b/internal/query/projection/project_role_test.go index ec277551c..31ed5ddca 100644 --- a/internal/query/projection/project_role_test.go +++ b/internal/query/projection/project_role_test.go @@ -53,7 +53,7 @@ func TestProjectRoleProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(ProjectRoleColumnInstanceID), diff --git a/internal/query/projection/project_test.go b/internal/query/projection/project_test.go index c034bbd66..5d7e4766e 100644 --- a/internal/query/projection/project_test.go +++ b/internal/query/projection/project_test.go @@ -54,7 +54,7 @@ func TestProjectProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(ProjectColumnInstanceID), diff --git a/internal/query/projection/secret_generator.go b/internal/query/projection/secret_generator.go index 610374f97..a9c65bdb6 100644 --- a/internal/query/projection/secret_generator.go +++ b/internal/query/projection/secret_generator.go @@ -76,6 +76,10 @@ func (p *secretGeneratorProjection) reducers() []handler.AggregateReducer { Event: instance.SecretGeneratorRemovedEventType, Reduce: p.reduceSecretGeneratorRemoved, }, + { + Event: instance.InstanceRemovedEventType, + Reduce: reduceInstanceRemovedHelper(SecretGeneratorColumnInstanceID), + }, }, }, } diff --git a/internal/query/projection/secret_generator_test.go b/internal/query/projection/secret_generator_test.go index ceb17ea8e..9274290ff 100644 --- a/internal/query/projection/secret_generator_test.go +++ b/internal/query/projection/secret_generator_test.go @@ -122,6 +122,32 @@ func TestSecretGeneratorProjection_reduces(t *testing.T) { }, }, }, + { + name: "reduceInstanceRemoved", + args: args{ + event: getEvent(testEvent( + repository.EventType(instance.InstanceRemovedEventType), + instance.AggregateType, + nil, + ), instance.InstanceRemovedEventMapper), + }, + reduce: reduceInstanceRemovedHelper(MemberInstanceID), + want: wantReduce{ + aggregateType: eventstore.AggregateType("instance"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "DELETE FROM projections.secret_generators2 WHERE (instance_id = $1)", + expectedArgs: []interface{}{ + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/sms_test.go b/internal/query/projection/sms_test.go index 2ab84d47c..f0d4abcdf 100644 --- a/internal/query/projection/sms_test.go +++ b/internal/query/projection/sms_test.go @@ -271,7 +271,7 @@ func TestSMSProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(SMSColumnInstanceID), diff --git a/internal/query/projection/smtp_test.go b/internal/query/projection/smtp_test.go index de5044af7..d5e576e29 100644 --- a/internal/query/projection/smtp_test.go +++ b/internal/query/projection/smtp_test.go @@ -151,7 +151,7 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(SMTPConfigColumnInstanceID), diff --git a/internal/query/projection/user_auth_method_test.go b/internal/query/projection/user_auth_method_test.go index fe3cad91c..6a1edbcda 100644 --- a/internal/query/projection/user_auth_method_test.go +++ b/internal/query/projection/user_auth_method_test.go @@ -244,7 +244,7 @@ func TestUserAuthMethodProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(UserAuthMethodInstanceIDCol), diff --git a/internal/query/projection/user_grant_test.go b/internal/query/projection/user_grant_test.go index d5e408b9a..37b60cbd5 100644 --- a/internal/query/projection/user_grant_test.go +++ b/internal/query/projection/user_grant_test.go @@ -159,7 +159,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(UserGrantInstanceID), diff --git a/internal/query/projection/user_metadata_test.go b/internal/query/projection/user_metadata_test.go index 5cbfaa672..8812d2b01 100644 --- a/internal/query/projection/user_metadata_test.go +++ b/internal/query/projection/user_metadata_test.go @@ -144,7 +144,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(UserMetadataColumnInstanceID), diff --git a/internal/query/projection/user_personal_access_token_test.go b/internal/query/projection/user_personal_access_token_test.go index 4e5dfb783..f67881ed2 100644 --- a/internal/query/projection/user_personal_access_token_test.go +++ b/internal/query/projection/user_personal_access_token_test.go @@ -115,7 +115,7 @@ func TestPersonalAccessTokenProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(PersonalAccessTokenColumnInstanceID), diff --git a/internal/query/projection/user_test.go b/internal/query/projection/user_test.go index fd55583d7..81b0bff3d 100644 --- a/internal/query/projection/user_test.go +++ b/internal/query/projection/user_test.go @@ -1623,7 +1623,7 @@ func TestUserProjection_reduces(t *testing.T) { event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), instance.AggregateType, - []byte(`{"name": "Name"}`), + nil, ), instance.InstanceRemovedEventMapper), }, reduce: reduceInstanceRemovedHelper(UserInstanceIDCol), diff --git a/internal/repository/instance/instance.go b/internal/repository/instance/instance.go index 2e24684c5..cb5dd220a 100644 --- a/internal/repository/instance/instance.go +++ b/internal/repository/instance/instance.go @@ -92,35 +92,36 @@ func InstanceChangedEventMapper(event *repository.Event) (eventstore.Event, erro type InstanceRemovedEvent struct { eventstore.BaseEvent `json:"-"` name string + domains []string } func (e *InstanceRemovedEvent) Data() interface{} { - return e -} - -func (e *InstanceRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { return nil } -func NewInstanceRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name string) *InstanceRemovedEvent { +func (e *InstanceRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + constraints := make([]*eventstore.EventUniqueConstraint, len(e.domains)+1) + for i, domain := range e.domains { + constraints[i] = NewRemoveInstanceDomainUniqueConstraint(domain) + } + constraints[len(e.domains)] = eventstore.NewRemoveInstanceUniqueConstraints() + return constraints +} + +func NewInstanceRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name string, domains []string) *InstanceRemovedEvent { return &InstanceRemovedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, InstanceRemovedEventType, ), - name: name, + name: name, + domains: domains, } } func InstanceRemovedEventMapper(event *repository.Event) (eventstore.Event, error) { - instanceRemoved := &InstanceRemovedEvent{ + return &InstanceRemovedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), - } - err := json.Unmarshal(event.Data, instanceRemoved) - if err != nil { - return nil, errors.ThrowInternal(err, "INSTANCE-39jlW", "unable to unmarshal instance removed") - } - - return instanceRemoved, nil + }, nil } diff --git a/internal/static/database/crdb.go b/internal/static/database/crdb.go index e03be3114..5a012a591 100644 --- a/internal/static/database/crdb.go +++ b/internal/static/database/crdb.go @@ -180,3 +180,20 @@ func (c *crdbStorage) RemoveObjects(ctx context.Context, instanceID, resourceOwn } return nil } + +func (c *crdbStorage) RemoveInstanceObjects(ctx context.Context, instanceID string) error { + stmt, args, err := squirrel.Delete(assetsTable). + Where(squirrel.Eq{ + AssetColInstanceID: instanceID, + }). + PlaceholderFormat(squirrel.Dollar). + ToSql() + if err != nil { + return caos_errors.ThrowInternal(err, "DATAB-Sfgeq", "Errors.Internal") + } + _, err = c.client.ExecContext(ctx, stmt, args...) + if err != nil { + return caos_errors.ThrowInternal(err, "DATAB-Efgt2", "Errors.Assets.Object.RemoveFailed") + } + return nil +} diff --git a/internal/static/database/crdb_test.go b/internal/static/database/crdb_test.go index 49cb5c029..f53f8a819 100644 --- a/internal/static/database/crdb_test.go +++ b/internal/static/database/crdb_test.go @@ -35,6 +35,8 @@ const ( " WHERE asset_type = $1" + " AND instance_id = $2" + " AND resource_owner = $3" + removeInstanceObjectsStmt = "DELETE FROM system.assets" + + " WHERE instance_id = $1" ) func Test_crdbStorage_CreateObject(t *testing.T) { @@ -224,6 +226,50 @@ func Test_crdbStorage_RemoveObjects(t *testing.T) { }) } } +func Test_crdbStorage_RemoveInstanceObjects(t *testing.T) { + type fields struct { + client db + } + type args struct { + ctx context.Context + instanceID string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + "remove ok", + fields{ + client: prepareDB(t, + expectExec( + removeInstanceObjectsStmt, + nil, + "instanceID", + )), + }, + args{ + ctx: context.Background(), + instanceID: "instanceID", + }, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &crdbStorage{ + client: tt.fields.client.db, + } + err := c.RemoveInstanceObjects(tt.args.ctx, tt.args.instanceID) + if (err != nil) != tt.wantErr { + t.Errorf("RemoveInstanceObjects() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} type db struct { mock sqlmock.Sqlmock diff --git a/internal/static/mock/storage_mock.go b/internal/static/mock/storage_mock.go index e0d5156a5..c0fa230db 100644 --- a/internal/static/mock/storage_mock.go +++ b/internal/static/mock/storage_mock.go @@ -82,6 +82,20 @@ func (mr *MockStorageMockRecorder) PutObject(ctx, instanceID, location, resource return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutObject", reflect.TypeOf((*MockStorage)(nil).PutObject), ctx, instanceID, location, resourceOwner, name, contentType, objectType, object, objectSize) } +// RemoveInstanceObjects mocks base method. +func (m *MockStorage) RemoveInstanceObjects(ctx context.Context, instanceID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveInstanceObjects", ctx, instanceID) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveInstanceObjects indicates an expected call of RemoveInstanceObjects. +func (mr *MockStorageMockRecorder) RemoveInstanceObjects(ctx, instanceID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveInstanceObjects", reflect.TypeOf((*MockStorage)(nil).RemoveInstanceObjects), ctx, instanceID) +} + // RemoveObject mocks base method. func (m *MockStorage) RemoveObject(ctx context.Context, instanceID, resourceOwner, name string) error { m.ctrl.T.Helper() diff --git a/internal/static/s3/minio.go b/internal/static/s3/minio.go index dbc211185..e8506955e 100644 --- a/internal/static/s3/minio.go +++ b/internal/static/s3/minio.go @@ -136,6 +136,11 @@ func (m *Minio) RemoveObjects(ctx context.Context, instanceID, resourceOwner str return g.Wait() } +func (m *Minio) RemoveInstanceObjects(ctx context.Context, instanceID string) error { + bucketName := m.prefixBucketName(instanceID) + return m.Client.RemoveBucket(ctx, bucketName) +} + func (m *Minio) createBucket(ctx context.Context, name, location string) error { if location == "" { location = m.Location diff --git a/internal/static/storage.go b/internal/static/storage.go index 1a39b4455..89fca47d6 100644 --- a/internal/static/storage.go +++ b/internal/static/storage.go @@ -15,6 +15,7 @@ type Storage interface { GetObjectInfo(ctx context.Context, instanceID, resourceOwner, name string) (*Asset, error) RemoveObject(ctx context.Context, instanceID, resourceOwner, name string) error RemoveObjects(ctx context.Context, instanceID, resourceOwner string, objectType ObjectType) error + RemoveInstanceObjects(ctx context.Context, instanceID string) error //TODO: add functionality to move asset location } diff --git a/internal/user/repository/view/external_idp_view.go b/internal/user/repository/view/external_idp_view.go index 269b23537..28da8e5c1 100644 --- a/internal/user/repository/view/external_idp_view.go +++ b/internal/user/repository/view/external_idp_view.go @@ -115,3 +115,8 @@ func DeleteExternalIDPsByUserID(db *gorm.DB, table, userID, instanceID string) e ) return delete(db) } + +func DeleteInstanceExternalIDPs(db *gorm.DB, table, instanceID string) error { + delete := repository.PrepareDeleteByKey(table, model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyInstanceID), instanceID) + return delete(db) +} diff --git a/internal/user/repository/view/refresh_token_view.go b/internal/user/repository/view/refresh_token_view.go index dabb64edb..168d4e771 100644 --- a/internal/user/repository/view/refresh_token_view.go +++ b/internal/user/repository/view/refresh_token_view.go @@ -94,3 +94,8 @@ func DeleteApplicationRefreshTokens(db *gorm.DB, table string, appIDs []string) delete := repository.PrepareDeleteByKey(table, usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyApplicationID), appIDs) return delete(db) } + +func DeleteInstanceRefreshTokens(db *gorm.DB, table string, instanceID string) error { + delete := repository.PrepareDeleteByKey(table, usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyInstanceID), instanceID) + return delete(db) +} diff --git a/internal/user/repository/view/token_view.go b/internal/user/repository/view/token_view.go index e74ca66ec..405b66dc6 100644 --- a/internal/user/repository/view/token_view.go +++ b/internal/user/repository/view/token_view.go @@ -97,3 +97,8 @@ func DeleteApplicationTokens(db *gorm.DB, table, instanceID string, appIDs []str ) return delete(db) } + +func DeleteInstanceTokens(db *gorm.DB, table, instanceID string) error { + delete := repository.PrepareDeleteByKey(table, usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), instanceID) + return delete(db) +} diff --git a/internal/user/repository/view/user_session_view.go b/internal/user/repository/view/user_session_view.go index 4784c1b45..cc6dbf80b 100644 --- a/internal/user/repository/view/user_session_view.go +++ b/internal/user/repository/view/user_session_view.go @@ -125,3 +125,8 @@ func DeleteUserSessions(db *gorm.DB, table, userID, instanceID string) error { ) return delete(db) } + +func DeleteInstanceUserSessions(db *gorm.DB, table, instanceID string) error { + delete := repository.PrepareDeleteByKey(table, model.UserSessionSearchKey(usr_model.UserSessionSearchKeyInstanceID), instanceID) + return delete(db) +} diff --git a/internal/user/repository/view/user_view.go b/internal/user/repository/view/user_view.go index 8484f8a9e..d0d2d0e71 100644 --- a/internal/user/repository/view/user_view.go +++ b/internal/user/repository/view/user_view.go @@ -204,3 +204,8 @@ func DeleteUser(db *gorm.DB, table, userID, instanceID string) error { ) return delete(db) } + +func DeleteInstanceUsers(db *gorm.DB, table, instanceID string) error { + delete := repository.PrepareDeleteByKey(table, model.UserSearchKey(usr_model.UserSearchKeyInstanceID), instanceID) + return delete(db) +}