diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index 76c6def756..35007b184f 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -566,6 +566,7 @@ InternalAuthZ: - "org.global.read" - "org.create" - "org.write" + - "org.delete" - "org.member.read" - "org.member.write" - "org.member.delete" @@ -639,6 +640,7 @@ InternalAuthZ: - "org.global.read" - "org.create" - "org.write" + - "org.delete" - "org.member.read" - "org.member.write" - "org.member.delete" @@ -710,6 +712,7 @@ InternalAuthZ: - "org.global.read" - "org.create" - "org.write" + - "org.delete" - "org.member.read" - "org.member.write" - "org.member.delete" diff --git a/cmd/setup/06.go b/cmd/setup/06.go new file mode 100644 index 0000000000..5a33745433 --- /dev/null +++ b/cmd/setup/06.go @@ -0,0 +1,28 @@ +package setup + +import ( + "context" + "database/sql" + _ "embed" +) + +var ( + //go:embed 06/adminapi.sql + createAdminViews06 string + //go:embed 06/auth.sql + createAuthViews06 string +) + +type OwnerRemoveColumns struct { + dbClient *sql.DB +} + +func (mig *OwnerRemoveColumns) Execute(ctx context.Context) error { + stmt := createAdminViews06 + createAuthViews06 + _, err := mig.dbClient.ExecContext(ctx, stmt) + return err +} + +func (mig *OwnerRemoveColumns) String() string { + return "06_resource_owner_columns" +} diff --git a/cmd/setup/06/adminapi.sql b/cmd/setup/06/adminapi.sql new file mode 100644 index 0000000000..f87ef6e5d7 --- /dev/null +++ b/cmd/setup/06/adminapi.sql @@ -0,0 +1,30 @@ + +CREATE TABLE adminapi.styling2 ( + aggregate_id TEXT NOT NULL, + creation_date TIMESTAMPTZ NULL, + change_date TIMESTAMPTZ NULL, + label_policy_state INT2 NOT NULL DEFAULT 0::INT2, + sequence INT8 NULL, + primary_color TEXT NULL, + background_color TEXT NULL, + warn_color TEXT NULL, + font_color TEXT NULL, + primary_color_dark TEXT NULL, + background_color_dark TEXT NULL, + warn_color_dark TEXT NULL, + font_color_dark TEXT NULL, + logo_url TEXT NULL, + icon_url TEXT NULL, + logo_dark_url TEXT NULL, + icon_dark_url TEXT NULL, + font_url TEXT NULL, + err_msg_popup BOOL NULL, + disable_watermark BOOL NULL, + hide_login_name_suffix BOOL NULL, + instance_id TEXT NOT NULL, + owner_removed BOOL DEFAULT false, + + PRIMARY KEY (instance_id, aggregate_id, label_policy_state) +); + +CREATE INDEX owner_removed_idx ON adminapi.styling2 (owner_removed); \ No newline at end of file diff --git a/cmd/setup/06/auth.sql b/cmd/setup/06/auth.sql new file mode 100644 index 0000000000..8271723df4 --- /dev/null +++ b/cmd/setup/06/auth.sql @@ -0,0 +1,124 @@ +CREATE TABLE auth.users2 ( + id TEXT NULL, + creation_date TIMESTAMPTZ NULL, + change_date TIMESTAMPTZ NULL, + resource_owner TEXT NULL, + user_state INT2 NULL, + password_set BOOL NULL, + password_change_required BOOL NULL, + password_change TIMESTAMPTZ NULL, + last_login TIMESTAMPTZ NULL, + user_name TEXT NULL, + login_names TEXT[] NULL, + preferred_login_name TEXT NULL, + first_name TEXT NULL, + last_name TEXT NULL, + nick_name TEXT NULL, + display_name TEXT NULL, + preferred_language TEXT NULL, + gender INT2 NULL, + email TEXT NULL, + is_email_verified BOOL NULL, + phone TEXT NULL, + is_phone_verified BOOL NULL, + country TEXT NULL, + locality TEXT NULL, + postal_code TEXT NULL, + region TEXT NULL, + street_address TEXT NULL, + otp_state INT2 NULL, + mfa_max_set_up INT2 NULL, + mfa_init_skipped TIMESTAMPTZ NULL, + sequence INT8 NULL, + init_required BOOL NULL, + username_change_required BOOL NULL, + machine_name TEXT NULL, + machine_description TEXT NULL, + user_type TEXT NULL, + u2f_tokens BYTEA NULL, + passwordless_tokens BYTEA NULL, + avatar_key TEXT NULL, + passwordless_init_required BOOL NULL, + password_init_required BOOL NULL, + instance_id TEXT NOT NULL, + owner_removed BOOL DEFAULT false, + + PRIMARY KEY (instance_id, id) +); +CREATE INDEX owner_removed_idx ON auth.users2 (owner_removed); + +CREATE TABLE auth.user_external_idps2 ( + external_user_id TEXT NOT NULL, + idp_config_id TEXT NOT NULL, + user_id TEXT NULL, + idp_name TEXT NULL, + user_display_name TEXT NULL, + creation_date TIMESTAMPTZ NULL, + change_date TIMESTAMPTZ NULL, + sequence INT8 NULL, + resource_owner TEXT NULL, + instance_id TEXT NOT NULL, + owner_removed BOOL DEFAULT false, + + PRIMARY KEY (instance_id, external_user_id, idp_config_id) +); +CREATE INDEX owner_removed_idx ON auth.user_external_idps2 (owner_removed); + +CREATE TABLE auth.org_project_mapping2 ( + org_id TEXT NOT NULL, + project_id TEXT NOT NULL, + project_grant_id TEXT NULL, + instance_id TEXT NOT NULL, + owner_removed BOOL DEFAULT false, + + PRIMARY KEY (instance_id, org_id, project_id) +); +CREATE INDEX owner_removed_idx ON auth.org_project_mapping2 (owner_removed); + +CREATE TABLE auth.idp_providers2 ( + aggregate_id TEXT NOT NULL, + idp_config_id TEXT NOT NULL, + creation_date TIMESTAMPTZ NULL, + change_date TIMESTAMPTZ NULL, + sequence INT8 NULL, + name TEXT NULL, + idp_config_type INT2 NULL, + idp_provider_type INT2 NULL, + idp_state INT2 NULL, + styling_type INT2 NULL, + instance_id TEXT NOT NULL, + owner_removed BOOL DEFAULT false, + + PRIMARY KEY (instance_id, aggregate_id, idp_config_id) +); +CREATE INDEX owner_removed_idx ON auth.idp_providers2 (owner_removed); + +CREATE TABLE auth.idp_configs2 ( + idp_config_id TEXT NOT NULL, + creation_date TIMESTAMPTZ NULL, + change_date TIMESTAMPTZ NULL, + sequence INT8 NULL, + aggregate_id TEXT NULL, + name TEXT NULL, + idp_state INT2 NULL, + idp_provider_type INT2 NULL, + is_oidc BOOL NULL, + oidc_client_id TEXT NULL, + oidc_client_secret JSONB NULL, + oidc_issuer TEXT NULL, + oidc_scopes TEXT[] NULL, + oidc_idp_display_name_mapping INT2 NULL, + oidc_idp_username_mapping INT2 NULL, + styling_type INT2 NULL, + oauth_authorization_endpoint TEXT NULL, + oauth_token_endpoint TEXT NULL, + auto_register BOOL NULL, + jwt_endpoint TEXT NULL, + jwt_keys_endpoint TEXT NULL, + jwt_header_name TEXT NULL, + instance_id TEXT NOT NULL, + owner_removed BOOL DEFAULT false, + + PRIMARY KEY (instance_id, idp_config_id) +); +CREATE INDEX owner_removed_idx ON auth.idp_configs2 (owner_removed); diff --git a/cmd/setup/config.go b/cmd/setup/config.go index 0390c5f0c1..84be4310a0 100644 --- a/cmd/setup/config.go +++ b/cmd/setup/config.go @@ -54,11 +54,12 @@ func MustNewConfig(v *viper.Viper) *Config { } type Steps struct { - s1ProjectionTable *ProjectionTable - s2AssetsTable *AssetTable - FirstInstance *FirstInstance - s4EventstoreIndexes *EventstoreIndexes - s5LastFailed *LastFailed + s1ProjectionTable *ProjectionTable + s2AssetsTable *AssetTable + FirstInstance *FirstInstance + s4EventstoreIndexes *EventstoreIndexes + s5LastFailed *LastFailed + s6OwnerRemoveColumns *OwnerRemoveColumns } type encryptionKeyConfig struct { diff --git a/cmd/setup/setup.go b/cmd/setup/setup.go index 185b574733..bc4883ad34 100644 --- a/cmd/setup/setup.go +++ b/cmd/setup/setup.go @@ -83,6 +83,7 @@ func Setup(config *Config, steps *Steps, masterKey string) { steps.s4EventstoreIndexes = &EventstoreIndexes{dbClient: dbClient, dbType: config.Database.Type()} steps.s5LastFailed = &LastFailed{dbClient: dbClient} + steps.s6OwnerRemoveColumns = &OwnerRemoveColumns{dbClient: dbClient} err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil) logging.OnError(err).Fatal("unable to start projections") @@ -110,6 +111,8 @@ func Setup(config *Config, steps *Steps, masterKey string) { logging.OnError(err).Fatal("unable to migrate step 4") err = migration.Migrate(ctx, eventstoreClient, steps.s5LastFailed) logging.OnError(err).Fatal("unable to migrate step 5") + err = migration.Migrate(ctx, eventstoreClient, steps.s6OwnerRemoveColumns) + logging.OnError(err).Fatal("unable to migrate step 6") for _, repeatableStep := range repeatableSteps { err = migration.Migrate(ctx, eventstoreClient, repeatableStep) diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index 21185b5bfc..a8fedbb52c 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -829,7 +829,8 @@ "STATE": { "0": "Nicht definiert", "1": "Aktiv", - "2": "Inaktiv" + "2": "Inaktiv", + "3": "Entfernt" }, "MEMBER": { "TITLE": "Manager der Organisation verwalten", diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index 274e20f05d..7b93b54246 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -829,7 +829,8 @@ "STATE": { "0": "Not defined", "1": "Active", - "2": "Deactivated" + "2": "Deactivated", + "3": "Removed" }, "MEMBER": { "TITLE": "Organization Managers", diff --git a/console/src/assets/i18n/fr.json b/console/src/assets/i18n/fr.json index 65b3ed2efd..9a55ee878d 100644 --- a/console/src/assets/i18n/fr.json +++ b/console/src/assets/i18n/fr.json @@ -829,7 +829,8 @@ "STATE": { "0": "Non défini", "1": "Actif", - "2": "Désactivé" + "2": "Désactivé", + "3": "Supprimé" }, "MEMBER": { "TITLE": "Gestionnaires de l'organisation", diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json index b34ff04d81..d50bd1bb93 100644 --- a/console/src/assets/i18n/it.json +++ b/console/src/assets/i18n/it.json @@ -829,7 +829,8 @@ "STATE": { "0": "Non definito", "1": "Attivo", - "2": "Disattivato" + "2": "Disattivato", + "3": "Rimosso" }, "MEMBER": { "TITLE": "Manager dell'organizzazione", diff --git a/console/src/assets/i18n/zh.json b/console/src/assets/i18n/zh.json index 066e24df3f..5360e34441 100644 --- a/console/src/assets/i18n/zh.json +++ b/console/src/assets/i18n/zh.json @@ -829,7 +829,8 @@ "STATE": { "0": "未定义", "1": "启用", - "2": "停用" + "2": "停用", + "3": "移除" }, "MEMBER": { "TITLE": "组织管理者", diff --git a/docs/docs/apis/proto/management.md b/docs/docs/apis/proto/management.md index 77b950965b..e2341425a8 100644 --- a/docs/docs/apis/proto/management.md +++ b/docs/docs/apis/proto/management.md @@ -804,6 +804,19 @@ Sets the state of my organisation to active POST: /orgs/me/_reactivate +### RemoveOrg + +> **rpc** RemoveOrg([RemoveOrgRequest](#removeorgrequest)) +[RemoveOrgResponse](#removeorgresponse) + +Sets the state of my organisation and all its resource (Users, Projects, Grants to and from the org) to removed +Users of this organisation will not be able login + + + + DELETE: /orgs/me + + ### SetOrgMetadata > **rpc** SetOrgMetadata([SetOrgMetadataRequest](#setorgmetadatarequest)) @@ -7051,6 +7064,23 @@ This is an empty response +### RemoveOrgRequest + + + + + +### RemoveOrgResponse + + + +| Field | Type | Description | Validation | +| ----- | ---- | ----------- | ----------- | +| details | zitadel.v1.ObjectDetails | - | | + + + + ### RemovePersonalAccessTokenRequest diff --git a/docs/docs/apis/proto/org.md b/docs/docs/apis/proto/org.md index 7152a114e8..8f9895093f 100644 --- a/docs/docs/apis/proto/org.md +++ b/docs/docs/apis/proto/org.md @@ -135,6 +135,7 @@ title: zitadel/org.proto | ORG_STATE_UNSPECIFIED | 0 | - | | ORG_STATE_ACTIVE | 1 | - | | ORG_STATE_INACTIVE | 2 | - | +| ORG_STATE_REMOVED | 3 | - | diff --git a/internal/admin/repository/eventsourcing/handler/styling.go b/internal/admin/repository/eventsourcing/handler/styling.go index 8a8553b528..53a7f89812 100644 --- a/internal/admin/repository/eventsourcing/handler/styling.go +++ b/internal/admin/repository/eventsourcing/handler/styling.go @@ -25,7 +25,7 @@ import ( ) const ( - stylingTable = "adminapi.styling" + stylingTable = "adminapi.styling2" ) type Styling struct { @@ -156,6 +156,8 @@ func (m *Styling) processLabelPolicy(event *models.Event) (err error) { return err } return m.view.DeleteInstanceStyling(event) + case org.OrgRemovedEventType: + return m.view.UpdateOrgOwnerRemovedStyling(event) default: return m.view.ProcessedStylingSequence(event) } diff --git a/internal/admin/repository/eventsourcing/view/styling.go b/internal/admin/repository/eventsourcing/view/styling.go index b688a5544b..25ac4c882a 100644 --- a/internal/admin/repository/eventsourcing/view/styling.go +++ b/internal/admin/repository/eventsourcing/view/styling.go @@ -8,7 +8,7 @@ import ( ) const ( - stylingTyble = "adminapi.styling" + stylingTyble = "adminapi.styling2" ) func (v *View) StylingByAggregateIDAndState(aggregateID, instanceID string, state int32) (*model.LabelPolicyView, error) { @@ -31,6 +31,14 @@ func (v *View) DeleteInstanceStyling(event *models.Event) error { return v.ProcessedStylingSequence(event) } +func (v *View) UpdateOrgOwnerRemovedStyling(event *models.Event) error { + err := view.UpdateOrgOwnerRemovedStyling(v.Db, stylingTyble, event.InstanceID, event.AggregateID) + 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/assets/login_policy.go b/internal/api/assets/login_policy.go index a55f3d0e6d..9ed00cdb25 100644 --- a/internal/api/assets/login_policy.go +++ b/internal/api/assets/login_policy.go @@ -376,7 +376,7 @@ func getLabelPolicy(ctx context.Context, defaultPolicy, preview bool, queries *q if preview { return queries.PreviewLabelPolicyByOrg(ctx, authz.GetCtxData(ctx).OrgID) } - return queries.ActiveLabelPolicyByOrg(ctx, authz.GetCtxData(ctx).OrgID) + return queries.ActiveLabelPolicyByOrg(ctx, authz.GetCtxData(ctx).OrgID, false) } func getLabelPolicyResourceOwner(ctx context.Context, defaultPolicy, preview bool, queries *query.Queries) string { diff --git a/internal/api/grpc/admin/custom_text.go b/internal/api/grpc/admin/custom_text.go index 13b49e5ec7..187318659f 100644 --- a/internal/api/grpc/admin/custom_text.go +++ b/internal/api/grpc/admin/custom_text.go @@ -23,7 +23,7 @@ func (s *Server) GetDefaultInitMessageText(ctx context.Context, req *admin_pb.Ge } func (s *Server) GetCustomInitMessageText(ctx context.Context, req *admin_pb.GetCustomInitMessageTextRequest) (*admin_pb.GetCustomInitMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.InitCodeMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.InitCodeMessageType, req.Language, false) if err != nil { return nil, err } @@ -71,7 +71,7 @@ func (s *Server) GetDefaultPasswordResetMessageText(ctx context.Context, req *ad } func (s *Server) GetCustomPasswordResetMessageText(ctx context.Context, req *admin_pb.GetCustomPasswordResetMessageTextRequest) (*admin_pb.GetCustomPasswordResetMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.PasswordResetMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.PasswordResetMessageType, req.Language, false) if err != nil { return nil, err } @@ -119,7 +119,7 @@ func (s *Server) GetDefaultVerifyEmailMessageText(ctx context.Context, req *admi } func (s *Server) GetCustomVerifyEmailMessageText(ctx context.Context, req *admin_pb.GetCustomVerifyEmailMessageTextRequest) (*admin_pb.GetCustomVerifyEmailMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.VerifyEmailMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.VerifyEmailMessageType, req.Language, false) if err != nil { return nil, err } @@ -167,7 +167,7 @@ func (s *Server) GetDefaultVerifyPhoneMessageText(ctx context.Context, req *admi } func (s *Server) GetCustomVerifyPhoneMessageText(ctx context.Context, req *admin_pb.GetCustomVerifyPhoneMessageTextRequest) (*admin_pb.GetCustomVerifyPhoneMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.VerifyPhoneMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.VerifyPhoneMessageType, req.Language, false) if err != nil { return nil, err } @@ -215,7 +215,7 @@ func (s *Server) GetDefaultDomainClaimedMessageText(ctx context.Context, req *ad } func (s *Server) GetCustomDomainClaimedMessageText(ctx context.Context, req *admin_pb.GetCustomDomainClaimedMessageTextRequest) (*admin_pb.GetCustomDomainClaimedMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.DomainClaimedMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.DomainClaimedMessageType, req.Language, false) if err != nil { return nil, err } @@ -263,7 +263,7 @@ func (s *Server) GetDefaultPasswordlessRegistrationMessageText(ctx context.Conte } func (s *Server) GetCustomPasswordlessRegistrationMessageText(ctx context.Context, req *admin_pb.GetCustomPasswordlessRegistrationMessageTextRequest) (*admin_pb.GetCustomPasswordlessRegistrationMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.PasswordlessRegistrationMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetInstance(ctx).InstanceID(), domain.PasswordlessRegistrationMessageType, req.Language, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/admin/domain_policy.go b/internal/api/grpc/admin/domain_policy.go index b7628d33bb..3222f40d6c 100644 --- a/internal/api/grpc/admin/domain_policy.go +++ b/internal/api/grpc/admin/domain_policy.go @@ -19,7 +19,7 @@ func (s *Server) GetDomainPolicy(ctx context.Context, _ *admin_pb.GetDomainPolic } func (s *Server) GetCustomDomainPolicy(ctx context.Context, req *admin_pb.GetCustomDomainPolicyRequest) (*admin_pb.GetCustomDomainPolicyResponse, error) { - policy, err := s.query.DomainPolicyByOrg(ctx, true, req.OrgId) + policy, err := s.query.DomainPolicyByOrg(ctx, true, req.OrgId, false) if err != nil { return nil, err } @@ -154,7 +154,7 @@ func (s *Server) GetOrgIAMPolicy(ctx context.Context, _ *admin_pb.GetOrgIAMPolic } func (s *Server) GetCustomOrgIAMPolicy(ctx context.Context, req *admin_pb.GetCustomOrgIAMPolicyRequest) (*admin_pb.GetCustomOrgIAMPolicyResponse, error) { - policy, err := s.query.DomainPolicyByOrg(ctx, true, req.OrgId) + policy, err := s.query.DomainPolicyByOrg(ctx, true, req.OrgId, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/admin/export.go b/internal/api/grpc/admin/export.go index 9d38c6c99b..784bd05c2b 100644 --- a/internal/api/grpc/admin/export.go +++ b/internal/api/grpc/admin/export.go @@ -254,7 +254,7 @@ func (s *Server) getDomainPolicy(ctx context.Context, orgID string) (_ *admin_pb ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - queriedDomain, err := s.query.DomainPolicyByOrg(ctx, true, orgID) + queriedDomain, err := s.query.DomainPolicyByOrg(ctx, true, orgID, false) if err != nil { return nil, err } @@ -277,7 +277,7 @@ func (s *Server) getDomains(ctx context.Context, orgID string) (_ []*org_pb.Doma if err != nil { return nil, err } - orgDomainsQuery, err := s.query.SearchOrgDomains(ctx, &query.OrgDomainSearchQueries{Queries: []query.SearchQuery{orgDomainOrgIDQuery}}) + orgDomainsQuery, err := s.query.SearchOrgDomains(ctx, &query.OrgDomainSearchQueries{Queries: []query.SearchQuery{orgDomainOrgIDQuery}}, false) if err != nil { return nil, err } @@ -306,7 +306,7 @@ func (s *Server) getIDPs(ctx context.Context, orgID string) (_ []*v1_pb.DataOIDC if err != nil { return nil, nil, err } - idps, err := s.query.IDPs(ctx, &query.IDPSearchQueries{Queries: []query.SearchQuery{idpQuery, ownerType}}) + idps, err := s.query.IDPs(ctx, &query.IDPSearchQueries{Queries: []query.SearchQuery{idpQuery, ownerType}}, false) if err != nil { return nil, nil, err } @@ -314,7 +314,7 @@ func (s *Server) getIDPs(ctx context.Context, orgID string) (_ []*v1_pb.DataOIDC jwtIdps := make([]*v1_pb.DataJWTIDP, 0) for _, idp := range idps.IDPs { if idp.OIDCIDP != nil { - clientSecret, err := s.query.GetOIDCIDPClientSecret(ctx, false, orgID, idp.ID) + clientSecret, err := s.query.GetOIDCIDPClientSecret(ctx, false, orgID, idp.ID, false) if err != nil && !caos_errors.IsNotFound(err) { return nil, nil, err } @@ -354,7 +354,7 @@ func (s *Server) getLabelPolicy(ctx context.Context, orgID string) (_ *managemen ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - queriedLabel, err := s.query.ActiveLabelPolicyByOrg(ctx, orgID) + queriedLabel, err := s.query.ActiveLabelPolicyByOrg(ctx, orgID, false) if err != nil { return nil, err } @@ -379,7 +379,7 @@ func (s *Server) getLoginPolicy(ctx context.Context, orgID string, orgIDPs []str ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - queriedLogin, err := s.query.LoginPolicyByID(ctx, false, orgID) + queriedLogin, err := s.query.LoginPolicyByID(ctx, false, orgID, false) if err != nil { return nil, err } @@ -400,7 +400,7 @@ func (s *Server) getLoginPolicy(ctx context.Context, orgID string, orgIDPs []str multiFactors = append(multiFactors, policy_pb.MultiFactorType(factor)) } - idpLinksQuery, err := s.query.IDPLoginPolicyLinks(ctx, orgID, &query.IDPLoginPolicyLinksSearchQuery{}) + idpLinksQuery, err := s.query.IDPLoginPolicyLinks(ctx, orgID, &query.IDPLoginPolicyLinksSearchQuery{}, false) if err != nil { return nil, err } @@ -456,7 +456,7 @@ func (s *Server) getUserLinks(ctx context.Context, orgID string) (_ []*idp_pb.ID if err != nil { return nil, err } - idpUserLinks, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: []query.SearchQuery{userLinksResourceOwner}}) + idpUserLinks, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: []query.SearchQuery{userLinksResourceOwner}}, false) if err != nil { return nil, err } @@ -479,7 +479,7 @@ func (s *Server) getLockoutPolicy(ctx context.Context, orgID string) (_ *managem ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - queriedLockout, err := s.query.LockoutPolicyByOrg(ctx, false, orgID) + queriedLockout, err := s.query.LockoutPolicyByOrg(ctx, false, orgID, false) if err != nil { return nil, err } @@ -495,7 +495,7 @@ func (s *Server) getPasswordComplexityPolicy(ctx context.Context, orgID string) ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - queriedPasswordComplexity, err := s.query.PasswordComplexityPolicyByOrg(ctx, false, orgID) + queriedPasswordComplexity, err := s.query.PasswordComplexityPolicyByOrg(ctx, false, orgID, false) if err != nil { return nil, err } @@ -515,7 +515,7 @@ func (s *Server) getPrivacyPolicy(ctx context.Context, orgID string) (_ *managem ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - queriedPrivacy, err := s.query.PrivacyPolicyByOrg(ctx, false, orgID) + queriedPrivacy, err := s.query.PrivacyPolicyByOrg(ctx, false, orgID, false) if err != nil { return nil, err } @@ -537,7 +537,7 @@ func (s *Server) getUsers(ctx context.Context, org string, withPasswords bool, w if err != nil { return nil, nil, nil, nil, err } - users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{orgSearch}}) + users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{orgSearch}}, false) if err != nil { return nil, nil, nil, nil, err } @@ -619,7 +619,7 @@ func (s *Server) getUsers(ctx context.Context, org string, withPasswords bool, w return nil, nil, nil, nil, err } - keys, err := s.query.SearchAuthNKeysData(ctx, &query.AuthNKeySearchQueries{Queries: []query.SearchQuery{userIDQuery, orgIDQuery}}) + keys, err := s.query.SearchAuthNKeysData(ctx, &query.AuthNKeySearchQueries{Queries: []query.SearchQuery{userIDQuery, orgIDQuery}}, false) if err != nil { return nil, nil, nil, nil, err } @@ -640,7 +640,7 @@ func (s *Server) getUsers(ctx context.Context, org string, withPasswords bool, w if err != nil { return nil, nil, nil, nil, err } - metadataList, err := s.query.SearchUserMetadata(ctx, false, user.ID, &query.UserMetadataSearchQueries{Queries: []query.SearchQuery{metadataOrgSearch}}) + metadataList, err := s.query.SearchUserMetadata(ctx, false, user.ID, &query.UserMetadataSearchQueries{Queries: []query.SearchQuery{metadataOrgSearch}}, false) metaspan.EndWithError(err) if err != nil { return nil, nil, nil, nil, err @@ -663,7 +663,7 @@ func (s *Server) getTriggerActions(ctx context.Context, org string, processedAct triggerActions := make([]*management_pb.SetTriggerActionsRequest, 0) for _, flowType := range flowTypes { - flow, err := s.query.GetFlow(ctx, flowType, org) + flow, err := s.query.GetFlow(ctx, flowType, org, false) if err != nil { return nil, err } @@ -693,7 +693,7 @@ func (s *Server) getActions(ctx context.Context, org string) ([]*v1_pb.DataActio if err != nil { return nil, err } - queriedActions, err := s.query.SearchActions(ctx, &query.ActionSearchQueries{Queries: []query.SearchQuery{actionSearch}}) + queriedActions, err := s.query.SearchActions(ctx, &query.ActionSearchQueries{Queries: []query.SearchQuery{actionSearch}}, false) if err != nil { return nil, err } @@ -720,7 +720,7 @@ func (s *Server) getProjectsAndApps(ctx context.Context, org string) ([]*v1_pb.D if err != nil { return nil, nil, nil, nil, nil, err } - queriedProjects, err := s.query.SearchProjects(ctx, &query.ProjectSearchQueries{Queries: []query.SearchQuery{projectSearch}}) + queriedProjects, err := s.query.SearchProjects(ctx, &query.ProjectSearchQueries{Queries: []query.SearchQuery{projectSearch}}, false) if err != nil { return nil, nil, nil, nil, nil, err } @@ -747,7 +747,7 @@ func (s *Server) getProjectsAndApps(ctx context.Context, org string) ([]*v1_pb.D return nil, nil, nil, nil, nil, err } - queriedProjectRoles, err := s.query.SearchProjectRoles(ctx, false, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectRoleSearch}}) + queriedProjectRoles, err := s.query.SearchProjectRoles(ctx, false, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectRoleSearch}}, false) if err != nil { return nil, nil, nil, nil, nil, err } @@ -764,7 +764,7 @@ func (s *Server) getProjectsAndApps(ctx context.Context, org string) ([]*v1_pb.D if err != nil { return nil, nil, nil, nil, nil, err } - apps, err := s.query.SearchApps(ctx, &query.AppSearchQueries{Queries: []query.SearchQuery{appSearch}}) + apps, err := s.query.SearchApps(ctx, &query.AppSearchQueries{Queries: []query.SearchQuery{appSearch}}, false) if err != nil { return nil, nil, nil, nil, nil, err } @@ -824,7 +824,7 @@ func (s *Server) getProjectsAndApps(ctx context.Context, org string) ([]*v1_pb.D if err != nil { return nil, nil, nil, nil, nil, err } - keys, err := s.query.SearchAuthNKeysData(ctx, &query.AuthNKeySearchQueries{Queries: []query.SearchQuery{appIDQuery, projectIDQuery, orgIDQuery}}) + keys, err := s.query.SearchAuthNKeysData(ctx, &query.AuthNKeySearchQueries{Queries: []query.SearchQuery{appIDQuery, projectIDQuery, orgIDQuery}}, false) if err != nil { return nil, nil, nil, nil, nil, err } @@ -854,7 +854,7 @@ func (s *Server) getNecessaryProjectGrantMembersForOrg(ctx context.Context, org return nil, err } - queriedProjectMembers, err := s.query.ProjectGrantMembers(ctx, &query.ProjectGrantMembersQuery{ProjectID: projectID, OrgID: org, GrantID: grantID, MembersQuery: query.MembersQuery{Queries: []query.SearchQuery{search}}}) + queriedProjectMembers, err := s.query.ProjectGrantMembers(ctx, &query.ProjectGrantMembersQuery{ProjectID: projectID, OrgID: org, GrantID: grantID, MembersQuery: query.MembersQuery{Queries: []query.SearchQuery{search}}}, false) if err != nil { return nil, err } @@ -882,7 +882,7 @@ func (s *Server) getNecessaryProjectMembersForOrg(ctx context.Context, processed projectMembers := make([]*management_pb.AddProjectMemberRequest, 0) for _, projectID := range processedProjects { - queriedProjectMembers, err := s.query.ProjectMembers(ctx, &query.ProjectMembersQuery{ProjectID: projectID}) + queriedProjectMembers, err := s.query.ProjectMembers(ctx, &query.ProjectMembersQuery{ProjectID: projectID}, false) if err != nil { return nil, err } @@ -903,7 +903,7 @@ func (s *Server) getNecessaryProjectMembersForOrg(ctx context.Context, processed } func (s *Server) getNecessaryOrgMembersForOrg(ctx context.Context, org string, processedUsers []string) ([]*management_pb.AddOrgMemberRequest, error) { - queriedOrgMembers, err := s.query.OrgMembers(ctx, &query.OrgMembersQuery{OrgID: org}) + queriedOrgMembers, err := s.query.OrgMembers(ctx, &query.OrgMembersQuery{OrgID: org}, false) if err != nil { return nil, err } @@ -928,7 +928,7 @@ func (s *Server) getNecessaryProjectGrantsForOrg(ctx context.Context, org string if err != nil { return nil, err } - queriedProjectGrants, err := s.query.SearchProjectGrants(ctx, &query.ProjectGrantSearchQueries{Queries: []query.SearchQuery{projectGrantSearchOrg}}) + queriedProjectGrants, err := s.query.SearchProjectGrants(ctx, &query.ProjectGrantSearchQueries{Queries: []query.SearchQuery{projectGrantSearchOrg}}, false) if err != nil { return nil, err } @@ -966,7 +966,7 @@ func (s *Server) getNecessaryUserGrantsForOrg(ctx context.Context, org string, p return nil, err } - queriedUserGrants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantSearchOrg}}) + queriedUserGrants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantSearchOrg}}, false) if err != nil { return nil, err } @@ -1061,7 +1061,7 @@ func (s *Server) getCustomLoginTexts(ctx context.Context, org string, languages func (s *Server) getCustomInitMessageTexts(ctx context.Context, org string, languages []string) ([]*management_pb.SetCustomInitMessageTextRequest, error) { customTexts := make([]*management_pb.SetCustomInitMessageTextRequest, 0, len(languages)) for _, lang := range languages { - text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.InitCodeMessageType, lang) + text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.InitCodeMessageType, lang, false) if err != nil { return nil, err } @@ -1086,7 +1086,7 @@ func (s *Server) getCustomInitMessageTexts(ctx context.Context, org string, lang func (s *Server) getCustomPasswordResetMessageTexts(ctx context.Context, org string, languages []string) ([]*management_pb.SetCustomPasswordResetMessageTextRequest, error) { customTexts := make([]*management_pb.SetCustomPasswordResetMessageTextRequest, 0, len(languages)) for _, lang := range languages { - text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.PasswordResetMessageType, lang) + text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.PasswordResetMessageType, lang, false) if err != nil { return nil, err } @@ -1111,7 +1111,7 @@ func (s *Server) getCustomPasswordResetMessageTexts(ctx context.Context, org str func (s *Server) getCustomVerifyEmailMessageTexts(ctx context.Context, org string, languages []string) ([]*management_pb.SetCustomVerifyEmailMessageTextRequest, error) { customTexts := make([]*management_pb.SetCustomVerifyEmailMessageTextRequest, 0, len(languages)) for _, lang := range languages { - text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.VerifyEmailMessageType, lang) + text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.VerifyEmailMessageType, lang, false) if err != nil { return nil, err } @@ -1136,7 +1136,7 @@ func (s *Server) getCustomVerifyEmailMessageTexts(ctx context.Context, org strin func (s *Server) getCustomVerifyPhoneMessageTexts(ctx context.Context, org string, languages []string) ([]*management_pb.SetCustomVerifyPhoneMessageTextRequest, error) { customTexts := make([]*management_pb.SetCustomVerifyPhoneMessageTextRequest, 0, len(languages)) for _, lang := range languages { - text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.VerifyPhoneMessageType, lang) + text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.VerifyPhoneMessageType, lang, false) if err != nil { return nil, err } @@ -1161,7 +1161,7 @@ func (s *Server) getCustomVerifyPhoneMessageTexts(ctx context.Context, org strin func (s *Server) getCustomDomainClaimedMessageTexts(ctx context.Context, org string, languages []string) ([]*management_pb.SetCustomDomainClaimedMessageTextRequest, error) { customTexts := make([]*management_pb.SetCustomDomainClaimedMessageTextRequest, 0, len(languages)) for _, lang := range languages { - text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.DomainClaimedMessageType, lang) + text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.DomainClaimedMessageType, lang, false) if err != nil { return nil, err } @@ -1186,7 +1186,7 @@ func (s *Server) getCustomDomainClaimedMessageTexts(ctx context.Context, org str func (s *Server) getCustomPasswordlessRegistrationMessageTexts(ctx context.Context, org string, languages []string) ([]*management_pb.SetCustomPasswordlessRegistrationMessageTextRequest, error) { customTexts := make([]*management_pb.SetCustomPasswordlessRegistrationMessageTextRequest, 0, len(languages)) for _, lang := range languages { - text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.DomainClaimedMessageType, lang) + text, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, org, domain.DomainClaimedMessageType, lang, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/admin/iam_member.go b/internal/api/grpc/admin/iam_member.go index cd53d5adb1..45efdaba7d 100644 --- a/internal/api/grpc/admin/iam_member.go +++ b/internal/api/grpc/admin/iam_member.go @@ -22,7 +22,7 @@ func (s *Server) ListIAMMembers(ctx context.Context, req *admin_pb.ListIAMMember if err != nil { return nil, err } - res, err := s.query.IAMMembers(ctx, queries) + res, err := s.query.IAMMembers(ctx, queries, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/admin/idp.go b/internal/api/grpc/admin/idp.go index e48d5a9758..cfe202aca9 100644 --- a/internal/api/grpc/admin/idp.go +++ b/internal/api/grpc/admin/idp.go @@ -11,7 +11,7 @@ import ( ) func (s *Server) GetIDPByID(ctx context.Context, req *admin_pb.GetIDPByIDRequest) (*admin_pb.GetIDPByIDResponse, error) { - idp, err := s.query.IDPByIDAndResourceOwner(ctx, true, req.Id, authz.GetInstance(ctx).InstanceID()) + idp, err := s.query.IDPByIDAndResourceOwner(ctx, true, req.Id, authz.GetInstance(ctx).InstanceID(), false) if err != nil { return nil, err } @@ -23,7 +23,7 @@ func (s *Server) ListIDPs(ctx context.Context, req *admin_pb.ListIDPsRequest) (* if err != nil { return nil, err } - resp, err := s.query.IDPs(ctx, queries) + resp, err := s.query.IDPs(ctx, queries, false) if err != nil { return nil, err } @@ -100,7 +100,7 @@ func (s *Server) RemoveIDP(ctx context.Context, req *admin_pb.RemoveIDPRequest) } idps, err := s.query.IDPs(ctx, &query.IDPSearchQueries{ Queries: []query.SearchQuery{providerQuery}, - }) + }, true) if err != nil { return nil, err } @@ -111,7 +111,7 @@ func (s *Server) RemoveIDP(ctx context.Context, req *admin_pb.RemoveIDPRequest) } userLinks, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{ Queries: []query.SearchQuery{idpQuery}, - }) + }, true) if err != nil { return nil, err } diff --git a/internal/api/grpc/admin/login_policy.go b/internal/api/grpc/admin/login_policy.go index aa39ac7367..8d95a6979e 100644 --- a/internal/api/grpc/admin/login_policy.go +++ b/internal/api/grpc/admin/login_policy.go @@ -36,7 +36,7 @@ func (s *Server) UpdateLoginPolicy(ctx context.Context, p *admin_pb.UpdateLoginP } func (s *Server) ListLoginPolicyIDPs(ctx context.Context, req *admin_pb.ListLoginPolicyIDPsRequest) (*admin_pb.ListLoginPolicyIDPsResponse, error) { - res, err := s.query.IDPLoginPolicyLinks(ctx, authz.GetInstance(ctx).InstanceID(), ListLoginPolicyIDPsRequestToQuery(req)) + res, err := s.query.IDPLoginPolicyLinks(ctx, authz.GetInstance(ctx).InstanceID(), ListLoginPolicyIDPsRequestToQuery(req), false) if err != nil { return nil, err } @@ -67,7 +67,7 @@ func (s *Server) RemoveIDPFromLoginPolicy(ctx context.Context, req *admin_pb.Rem } idps, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{ Queries: []query.SearchQuery{idpQuery}, - }) + }, true) if err != nil { return nil, err diff --git a/internal/api/grpc/admin/org.go b/internal/api/grpc/admin/org.go index 3ac515aa7c..b3b378461f 100644 --- a/internal/api/grpc/admin/org.go +++ b/internal/api/grpc/admin/org.go @@ -83,7 +83,7 @@ func (s *Server) getClaimedUserIDsOfOrgDomain(ctx context.Context, orgDomain str if err != nil { return nil, err } - users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{loginName}}) + users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{loginName}}, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/auth/email.go b/internal/api/grpc/auth/email.go index 3e4f636c7f..7c336ca1fc 100644 --- a/internal/api/grpc/auth/email.go +++ b/internal/api/grpc/auth/email.go @@ -11,7 +11,7 @@ import ( ) func (s *Server) GetMyEmail(ctx context.Context, _ *auth_pb.GetMyEmailRequest) (*auth_pb.GetMyEmailResponse, error) { - email, err := s.query.GetHumanEmail(ctx, authz.GetCtxData(ctx).UserID) + email, err := s.query.GetHumanEmail(ctx, authz.GetCtxData(ctx).UserID, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/auth/idp.go b/internal/api/grpc/auth/idp.go index 780a2f60dc..10879a5d8a 100644 --- a/internal/api/grpc/auth/idp.go +++ b/internal/api/grpc/auth/idp.go @@ -13,7 +13,7 @@ func (s *Server) ListMyLinkedIDPs(ctx context.Context, req *auth_pb.ListMyLinked if err != nil { return nil, err } - links, err := s.query.IDPUserLinks(ctx, q) + links, err := s.query.IDPUserLinks(ctx, q, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/auth/multi_factor.go b/internal/api/grpc/auth/multi_factor.go index f29aa10392..cf95644492 100644 --- a/internal/api/grpc/auth/multi_factor.go +++ b/internal/api/grpc/auth/multi_factor.go @@ -26,7 +26,7 @@ func (s *Server) ListMyAuthFactors(ctx context.Context, _ *auth_pb.ListMyAuthFac if err != nil { return nil, err } - authMethods, err := s.query.SearchUserAuthMethods(ctx, query) + authMethods, err := s.query.SearchUserAuthMethods(ctx, query, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/auth/password_complexity.go b/internal/api/grpc/auth/password_complexity.go index 1488d54442..63c648dc89 100644 --- a/internal/api/grpc/auth/password_complexity.go +++ b/internal/api/grpc/auth/password_complexity.go @@ -9,7 +9,7 @@ import ( ) func (s *Server) GetMyPasswordComplexityPolicy(ctx context.Context, _ *auth_pb.GetMyPasswordComplexityPolicyRequest) (*auth_pb.GetMyPasswordComplexityPolicyResponse, error) { - policy, err := s.query.PasswordComplexityPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID) + policy, err := s.query.PasswordComplexityPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/auth/passwordless.go b/internal/api/grpc/auth/passwordless.go index e601da6e87..3b0aa5357d 100644 --- a/internal/api/grpc/auth/passwordless.go +++ b/internal/api/grpc/auth/passwordless.go @@ -30,7 +30,7 @@ func (s *Server) ListMyPasswordless(ctx context.Context, _ *auth_pb.ListMyPasswo if err != nil { return nil, err } - authMethods, err := s.query.SearchUserAuthMethods(ctx, query) + authMethods, err := s.query.SearchUserAuthMethods(ctx, query, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/auth/permission.go b/internal/api/grpc/auth/permission.go index 5f93b8e7c3..5f45542dae 100644 --- a/internal/api/grpc/auth/permission.go +++ b/internal/api/grpc/auth/permission.go @@ -34,7 +34,7 @@ func (s *Server) ListMyProjectPermissions(ctx context.Context, _ *auth_pb.ListMy if err != nil { return nil, err } - userGrant, err := s.query.UserGrant(ctx, true, userGrantOrgID, userGrantProjectID, userGrantUserID) + userGrant, err := s.query.UserGrant(ctx, true, false, userGrantOrgID, userGrantProjectID, userGrantUserID) if err != nil { return nil, err } @@ -48,7 +48,7 @@ func (s *Server) ListMyMemberships(ctx context.Context, req *auth_pb.ListMyMembe if err != nil { return nil, err } - response, err := s.query.Memberships(ctx, request) + response, err := s.query.Memberships(ctx, request, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/auth/phone.go b/internal/api/grpc/auth/phone.go index 3595d85106..6c474831bc 100644 --- a/internal/api/grpc/auth/phone.go +++ b/internal/api/grpc/auth/phone.go @@ -11,7 +11,7 @@ import ( ) func (s *Server) GetMyPhone(ctx context.Context, _ *auth_pb.GetMyPhoneRequest) (*auth_pb.GetMyPhoneResponse, error) { - phone, err := s.query.GetHumanPhone(ctx, authz.GetCtxData(ctx).UserID) + phone, err := s.query.GetHumanPhone(ctx, authz.GetCtxData(ctx).UserID, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/auth/policy.go b/internal/api/grpc/auth/policy.go index 78add88fa9..1736b0ce37 100644 --- a/internal/api/grpc/auth/policy.go +++ b/internal/api/grpc/auth/policy.go @@ -9,7 +9,7 @@ import ( ) func (s *Server) GetMyLabelPolicy(ctx context.Context, _ *auth_pb.GetMyLabelPolicyRequest) (*auth_pb.GetMyLabelPolicyResponse, error) { - policy, err := s.query.ActiveLabelPolicyByOrg(ctx, authz.GetCtxData(ctx).OrgID) + policy, err := s.query.ActiveLabelPolicyByOrg(ctx, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } @@ -19,7 +19,7 @@ func (s *Server) GetMyLabelPolicy(ctx context.Context, _ *auth_pb.GetMyLabelPoli } func (s *Server) GetMyPrivacyPolicy(ctx context.Context, _ *auth_pb.GetMyPrivacyPolicyRequest) (*auth_pb.GetMyPrivacyPolicyResponse, error) { - policy, err := s.query.PrivacyPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID) + policy, err := s.query.PrivacyPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/auth/profile.go b/internal/api/grpc/auth/profile.go index 50f973c616..9d5d02c2ca 100644 --- a/internal/api/grpc/auth/profile.go +++ b/internal/api/grpc/auth/profile.go @@ -10,7 +10,7 @@ import ( ) func (s *Server) GetMyProfile(ctx context.Context, req *auth_pb.GetMyProfileRequest) (*auth_pb.GetMyProfileResponse, error) { - profile, err := s.query.GetHumanProfile(ctx, authz.GetCtxData(ctx).UserID) + profile, err := s.query.GetHumanProfile(ctx, authz.GetCtxData(ctx).UserID, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/auth/user.go b/internal/api/grpc/auth/user.go index 51524d99d4..162c8b21dc 100644 --- a/internal/api/grpc/auth/user.go +++ b/internal/api/grpc/auth/user.go @@ -17,7 +17,7 @@ import ( ) func (s *Server) GetMyUser(ctx context.Context, _ *auth_pb.GetMyUserRequest) (*auth_pb.GetMyUserResponse, error) { - user, err := s.query.GetUserByID(ctx, true, authz.GetCtxData(ctx).UserID) + user, err := s.query.GetUserByID(ctx, true, authz.GetCtxData(ctx).UserID, false) if err != nil { return nil, err } @@ -31,7 +31,7 @@ func (s *Server) RemoveMyUser(ctx context.Context, _ *auth_pb.RemoveMyUserReques return nil, err } queries := &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantUserID}} - grants, err := s.query.UserGrants(ctx, queries) + grants, err := s.query.UserGrants(ctx, queries, false) if err != nil { return nil, err } @@ -42,7 +42,7 @@ func (s *Server) RemoveMyUser(ctx context.Context, _ *auth_pb.RemoveMyUserReques } memberships, err := s.query.Memberships(ctx, &query.MembershipSearchQuery{ Queries: []query.SearchQuery{userQuery}, - }) + }, false) if err != nil { return nil, err } @@ -71,7 +71,7 @@ func (s *Server) ListMyMetadata(ctx context.Context, req *auth_pb.ListMyMetadata if err != nil { return nil, err } - res, err := s.query.SearchUserMetadata(ctx, true, authz.GetCtxData(ctx).UserID, queries) + res, err := s.query.SearchUserMetadata(ctx, true, authz.GetCtxData(ctx).UserID, queries, false) if err != nil { return nil, err } @@ -82,7 +82,7 @@ func (s *Server) ListMyMetadata(ctx context.Context, req *auth_pb.ListMyMetadata } func (s *Server) GetMyMetadata(ctx context.Context, req *auth_pb.GetMyMetadataRequest) (*auth_pb.GetMyMetadataResponse, error) { - data, err := s.query.GetUserMetadataByKey(ctx, true, authz.GetCtxData(ctx).UserID, req.Key) + data, err := s.query.GetUserMetadataByKey(ctx, true, authz.GetCtxData(ctx).UserID, req.Key, false) if err != nil { return nil, err } @@ -125,7 +125,7 @@ func (s *Server) ListMyUserGrants(ctx context.Context, req *auth_pb.ListMyUserGr if err != nil { return nil, err } - res, err := s.query.UserGrants(ctx, queries) + res, err := s.query.UserGrants(ctx, queries, false) if err != nil { return nil, err } @@ -154,7 +154,7 @@ func (s *Server) ListMyProjectOrgs(ctx context.Context, req *auth_pb.ListMyProje return nil, err } - grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantProjectID, userGrantUserID}}) + grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantProjectID, userGrantUserID}}, false) if err != nil { return nil, err } @@ -210,7 +210,7 @@ func (s *Server) myOrgsQuery(ctx context.Context, ctxData authz.CtxData) (*query } return s.query.Memberships(ctx, &query.MembershipSearchQuery{ Queries: []query.SearchQuery{userQuery}, - }) + }, false) } func isIAMAdmin(memberships []*query.Membership) bool { diff --git a/internal/api/grpc/management/actions.go b/internal/api/grpc/management/actions.go index 67a25d16e4..09a0136088 100644 --- a/internal/api/grpc/management/actions.go +++ b/internal/api/grpc/management/actions.go @@ -14,7 +14,7 @@ func (s *Server) ListActions(ctx context.Context, req *mgmt_pb.ListActionsReques if err != nil { return nil, err } - actions, err := s.query.SearchActions(ctx, query) + actions, err := s.query.SearchActions(ctx, query, false) if err != nil { return nil, err } @@ -25,7 +25,7 @@ func (s *Server) ListActions(ctx context.Context, req *mgmt_pb.ListActionsReques } func (s *Server) GetAction(ctx context.Context, req *mgmt_pb.GetActionRequest) (*mgmt_pb.GetActionResponse, error) { - action, err := s.query.GetActionByID(ctx, req.Id, authz.GetCtxData(ctx).OrgID) + action, err := s.query.GetActionByID(ctx, req.Id, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } @@ -89,7 +89,7 @@ func (s *Server) ReactivateAction(ctx context.Context, req *mgmt_pb.ReactivateAc } func (s *Server) DeleteAction(ctx context.Context, req *mgmt_pb.DeleteActionRequest) (*mgmt_pb.DeleteActionResponse, error) { - flowTypes, err := s.query.GetFlowTypesOfActionID(ctx, req.Id) + flowTypes, err := s.query.GetFlowTypesOfActionID(ctx, req.Id, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/custom_text.go b/internal/api/grpc/management/custom_text.go index b7ab8cc319..6473c7813b 100644 --- a/internal/api/grpc/management/custom_text.go +++ b/internal/api/grpc/management/custom_text.go @@ -13,7 +13,7 @@ import ( ) func (s *Server) GetCustomInitMessageText(ctx context.Context, req *mgmt_pb.GetCustomInitMessageTextRequest) (*mgmt_pb.GetCustomInitMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.InitCodeMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.InitCodeMessageType, req.Language, false) if err != nil { return nil, err } @@ -61,7 +61,7 @@ func (s *Server) ResetCustomInitMessageTextToDefault(ctx context.Context, req *m } func (s *Server) GetCustomPasswordResetMessageText(ctx context.Context, req *mgmt_pb.GetCustomPasswordResetMessageTextRequest) (*mgmt_pb.GetCustomPasswordResetMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.PasswordResetMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.PasswordResetMessageType, req.Language, false) if err != nil { return nil, err } @@ -109,7 +109,7 @@ func (s *Server) ResetCustomPasswordResetMessageTextToDefault(ctx context.Contex } func (s *Server) GetCustomVerifyEmailMessageText(ctx context.Context, req *mgmt_pb.GetCustomVerifyEmailMessageTextRequest) (*mgmt_pb.GetCustomVerifyEmailMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.VerifyEmailMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.VerifyEmailMessageType, req.Language, false) if err != nil { return nil, err } @@ -157,7 +157,7 @@ func (s *Server) ResetCustomVerifyEmailMessageTextToDefault(ctx context.Context, } func (s *Server) GetCustomVerifyPhoneMessageText(ctx context.Context, req *mgmt_pb.GetCustomVerifyPhoneMessageTextRequest) (*mgmt_pb.GetCustomVerifyPhoneMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.VerifyPhoneMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.VerifyPhoneMessageType, req.Language, false) if err != nil { return nil, err } @@ -205,7 +205,7 @@ func (s *Server) ResetCustomVerifyPhoneMessageTextToDefault(ctx context.Context, } func (s *Server) GetCustomDomainClaimedMessageText(ctx context.Context, req *mgmt_pb.GetCustomDomainClaimedMessageTextRequest) (*mgmt_pb.GetCustomDomainClaimedMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.DomainClaimedMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.DomainClaimedMessageType, req.Language, false) if err != nil { return nil, err } @@ -253,7 +253,7 @@ func (s *Server) ResetCustomDomainClaimedMessageTextToDefault(ctx context.Contex } func (s *Server) GetCustomPasswordlessRegistrationMessageText(ctx context.Context, req *mgmt_pb.GetCustomPasswordlessRegistrationMessageTextRequest) (*mgmt_pb.GetCustomPasswordlessRegistrationMessageTextResponse, error) { - msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.PasswordlessRegistrationMessageType, req.Language) + msg, err := s.query.CustomMessageTextByTypeAndLanguage(ctx, authz.GetCtxData(ctx).OrgID, domain.PasswordlessRegistrationMessageType, req.Language, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/flow.go b/internal/api/grpc/management/flow.go index 3aa9a439c3..c8692bd813 100644 --- a/internal/api/grpc/management/flow.go +++ b/internal/api/grpc/management/flow.go @@ -32,7 +32,7 @@ func (s *Server) ListFlowTriggerTypes(ctx context.Context, req *mgmt_pb.ListFlow } func (s *Server) GetFlow(ctx context.Context, req *mgmt_pb.GetFlowRequest) (*mgmt_pb.GetFlowResponse, error) { - flow, err := s.query.GetFlow(ctx, action_grpc.FlowTypeToDomain(req.Type), authz.GetCtxData(ctx).OrgID) + flow, err := s.query.GetFlow(ctx, action_grpc.FlowTypeToDomain(req.Type), authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/idp.go b/internal/api/grpc/management/idp.go index 01f430c342..30ba162ac0 100644 --- a/internal/api/grpc/management/idp.go +++ b/internal/api/grpc/management/idp.go @@ -11,7 +11,7 @@ import ( ) func (s *Server) GetOrgIDPByID(ctx context.Context, req *mgmt_pb.GetOrgIDPByIDRequest) (*mgmt_pb.GetOrgIDPByIDResponse, error) { - idp, err := s.query.IDPByIDAndResourceOwner(ctx, true, req.Id, authz.GetCtxData(ctx).OrgID) + idp, err := s.query.IDPByIDAndResourceOwner(ctx, true, req.Id, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } @@ -23,7 +23,7 @@ func (s *Server) ListOrgIDPs(ctx context.Context, req *mgmt_pb.ListOrgIDPsReques if err != nil { return nil, err } - resp, err := s.query.IDPs(ctx, queries) + resp, err := s.query.IDPs(ctx, queries, false) if err != nil { return nil, err } @@ -80,7 +80,7 @@ func (s *Server) ReactivateOrgIDP(ctx context.Context, req *mgmt_pb.ReactivateOr } func (s *Server) RemoveOrgIDP(ctx context.Context, req *mgmt_pb.RemoveOrgIDPRequest) (*mgmt_pb.RemoveOrgIDPResponse, error) { - idp, err := s.query.IDPByIDAndResourceOwner(ctx, true, req.IdpId, authz.GetCtxData(ctx).OrgID) + idp, err := s.query.IDPByIDAndResourceOwner(ctx, true, req.IdpId, authz.GetCtxData(ctx).OrgID, true) if err != nil { return nil, err } @@ -90,7 +90,7 @@ func (s *Server) RemoveOrgIDP(ctx context.Context, req *mgmt_pb.RemoveOrgIDPRequ } userLinks, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{ Queries: []query.SearchQuery{idpQuery}, - }) + }, true) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/org.go b/internal/api/grpc/management/org.go index 36560ef3c5..138ee752f5 100644 --- a/internal/api/grpc/management/org.go +++ b/internal/api/grpc/management/org.go @@ -100,8 +100,17 @@ func (s *Server) ReactivateOrg(ctx context.Context, req *mgmt_pb.ReactivateOrgRe }, err } +func (s *Server) RemoveOrg(ctx context.Context, req *mgmt_pb.RemoveOrgRequest) (*mgmt_pb.RemoveOrgResponse, error) { + details, err := s.command.RemoveOrg(ctx, authz.GetCtxData(ctx).OrgID) + if err != nil { + return nil, err + } + + return &mgmt_pb.RemoveOrgResponse{Details: object.DomainToChangeDetailsPb(details)}, nil +} + func (s *Server) GetDomainPolicy(ctx context.Context, req *mgmt_pb.GetDomainPolicyRequest) (*mgmt_pb.GetDomainPolicyResponse, error) { - policy, err := s.query.DomainPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID) + policy, err := s.query.DomainPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } @@ -111,7 +120,7 @@ func (s *Server) GetDomainPolicy(ctx context.Context, req *mgmt_pb.GetDomainPoli } func (s *Server) GetOrgIAMPolicy(ctx context.Context, _ *mgmt_pb.GetOrgIAMPolicyRequest) (*mgmt_pb.GetOrgIAMPolicyResponse, error) { - policy, err := s.query.DomainPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID) + policy, err := s.query.DomainPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } @@ -131,7 +140,7 @@ func (s *Server) ListOrgDomains(ctx context.Context, req *mgmt_pb.ListOrgDomains } queries.Queries = append(queries.Queries, orgIDQuery) - domains, err := s.query.SearchOrgDomains(ctx, queries) + domains, err := s.query.SearchOrgDomains(ctx, queries, false) if err != nil { return nil, err } @@ -227,7 +236,7 @@ func (s *Server) ListOrgMembers(ctx context.Context, req *mgmt_pb.ListOrgMembers if err != nil { return nil, err } - members, err := s.query.OrgMembers(ctx, queries) + members, err := s.query.OrgMembers(ctx, queries, false) if err != nil { return nil, err } @@ -289,7 +298,7 @@ func (s *Server) getClaimedUserIDsOfOrgDomain(ctx context.Context, orgDomain, or } queries = append(queries, owner) } - users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: queries}) + users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: queries}, false) if err != nil { return nil, err } @@ -305,7 +314,7 @@ func (s *Server) ListOrgMetadata(ctx context.Context, req *mgmt_pb.ListOrgMetada if err != nil { return nil, err } - res, err := s.query.SearchOrgMetadata(ctx, true, authz.GetCtxData(ctx).OrgID, metadataQueries) + res, err := s.query.SearchOrgMetadata(ctx, true, authz.GetCtxData(ctx).OrgID, metadataQueries, false) if err != nil { return nil, err } @@ -316,7 +325,7 @@ func (s *Server) ListOrgMetadata(ctx context.Context, req *mgmt_pb.ListOrgMetada } func (s *Server) GetOrgMetadata(ctx context.Context, req *mgmt_pb.GetOrgMetadataRequest) (*mgmt_pb.GetOrgMetadataResponse, error) { - data, err := s.query.GetOrgMetadataByKey(ctx, true, authz.GetCtxData(ctx).OrgID, req.Key) + data, err := s.query.GetOrgMetadataByKey(ctx, true, authz.GetCtxData(ctx).OrgID, req.Key, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/policy_label.go b/internal/api/grpc/management/policy_label.go index e76f97fb00..fef1d83d3f 100644 --- a/internal/api/grpc/management/policy_label.go +++ b/internal/api/grpc/management/policy_label.go @@ -10,7 +10,7 @@ import ( ) func (s *Server) GetLabelPolicy(ctx context.Context, req *mgmt_pb.GetLabelPolicyRequest) (*mgmt_pb.GetLabelPolicyResponse, error) { - policy, err := s.query.ActiveLabelPolicyByOrg(ctx, authz.GetCtxData(ctx).OrgID) + policy, err := s.query.ActiveLabelPolicyByOrg(ctx, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/policy_lockout.go b/internal/api/grpc/management/policy_lockout.go index 740a34e3a2..a36ee862d8 100644 --- a/internal/api/grpc/management/policy_lockout.go +++ b/internal/api/grpc/management/policy_lockout.go @@ -10,7 +10,7 @@ import ( ) func (s *Server) GetLockoutPolicy(ctx context.Context, req *mgmt_pb.GetLockoutPolicyRequest) (*mgmt_pb.GetLockoutPolicyResponse, error) { - policy, err := s.query.LockoutPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID) + policy, err := s.query.LockoutPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/policy_login.go b/internal/api/grpc/management/policy_login.go index ecfa3073bd..59b8f74a5a 100644 --- a/internal/api/grpc/management/policy_login.go +++ b/internal/api/grpc/management/policy_login.go @@ -14,7 +14,7 @@ import ( ) func (s *Server) GetLoginPolicy(ctx context.Context, req *mgmt_pb.GetLoginPolicyRequest) (*mgmt_pb.GetLoginPolicyResponse, error) { - policy, err := s.query.LoginPolicyByID(ctx, true, authz.GetCtxData(ctx).OrgID) + policy, err := s.query.LoginPolicyByID(ctx, true, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } @@ -68,7 +68,7 @@ func (s *Server) ResetLoginPolicyToDefault(ctx context.Context, req *mgmt_pb.Res } func (s *Server) ListLoginPolicyIDPs(ctx context.Context, req *mgmt_pb.ListLoginPolicyIDPsRequest) (*mgmt_pb.ListLoginPolicyIDPsResponse, error) { - res, err := s.query.IDPLoginPolicyLinks(ctx, authz.GetCtxData(ctx).OrgID, ListLoginPolicyIDPsRequestToQuery(req)) + res, err := s.query.IDPLoginPolicyLinks(ctx, authz.GetCtxData(ctx).OrgID, ListLoginPolicyIDPsRequestToQuery(req), false) if err != nil { return nil, err } @@ -99,7 +99,7 @@ func (s *Server) RemoveIDPFromLoginPolicy(ctx context.Context, req *mgmt_pb.Remo } userLinks, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{ Queries: []query.SearchQuery{idpQuery}, - }) + }, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/policy_password_age.go b/internal/api/grpc/management/policy_password_age.go index 088aeff206..86b7726654 100644 --- a/internal/api/grpc/management/policy_password_age.go +++ b/internal/api/grpc/management/policy_password_age.go @@ -10,7 +10,7 @@ import ( ) func (s *Server) GetPasswordAgePolicy(ctx context.Context, req *mgmt_pb.GetPasswordAgePolicyRequest) (*mgmt_pb.GetPasswordAgePolicyResponse, error) { - policy, err := s.query.PasswordAgePolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID) + policy, err := s.query.PasswordAgePolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/policy_password_complexity.go b/internal/api/grpc/management/policy_password_complexity.go index efb44e415e..6b5eed096f 100644 --- a/internal/api/grpc/management/policy_password_complexity.go +++ b/internal/api/grpc/management/policy_password_complexity.go @@ -10,7 +10,7 @@ import ( ) func (s *Server) GetPasswordComplexityPolicy(ctx context.Context, req *mgmt_pb.GetPasswordComplexityPolicyRequest) (*mgmt_pb.GetPasswordComplexityPolicyResponse, error) { - policy, err := s.query.PasswordComplexityPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID) + policy, err := s.query.PasswordComplexityPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/policy_privacy.go b/internal/api/grpc/management/policy_privacy.go index 86b3f242ac..06fb09dd62 100644 --- a/internal/api/grpc/management/policy_privacy.go +++ b/internal/api/grpc/management/policy_privacy.go @@ -10,7 +10,7 @@ import ( ) func (s *Server) GetPrivacyPolicy(ctx context.Context, _ *mgmt_pb.GetPrivacyPolicyRequest) (*mgmt_pb.GetPrivacyPolicyResponse, error) { - policy, err := s.query.PrivacyPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID) + policy, err := s.query.PrivacyPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/project.go b/internal/api/grpc/management/project.go index a55a2fb576..c54c13bb86 100644 --- a/internal/api/grpc/management/project.go +++ b/internal/api/grpc/management/project.go @@ -13,7 +13,7 @@ import ( ) func (s *Server) GetProjectByID(ctx context.Context, req *mgmt_pb.GetProjectByIDRequest) (*mgmt_pb.GetProjectByIDResponse, error) { - project, err := s.query.ProjectByID(ctx, true, req.Id) + project, err := s.query.ProjectByID(ctx, true, req.Id, false) if err != nil { return nil, err } @@ -23,7 +23,7 @@ func (s *Server) GetProjectByID(ctx context.Context, req *mgmt_pb.GetProjectByID } func (s *Server) GetGrantedProjectByID(ctx context.Context, req *mgmt_pb.GetGrantedProjectByIDRequest) (*mgmt_pb.GetGrantedProjectByIDResponse, error) { - grant, err := s.query.ProjectGrantByID(ctx, true, req.GrantId) + grant, err := s.query.ProjectGrantByID(ctx, true, req.GrantId, false) if err != nil { return nil, err } @@ -45,7 +45,7 @@ func (s *Server) ListProjects(ctx context.Context, req *mgmt_pb.ListProjectsRequ if err != nil { return nil, err } - projects, err := s.query.SearchProjects(ctx, queries) + projects, err := s.query.SearchProjects(ctx, queries, false) if err != nil { return nil, err } @@ -79,7 +79,7 @@ func (s *Server) ListGrantedProjects(ctx context.Context, req *mgmt_pb.ListGrant if err != nil { return nil, err } - projects, err := s.query.SearchProjectGrants(ctx, queries) + projects, err := s.query.SearchProjectGrants(ctx, queries, false) if err != nil { return nil, err } @@ -98,7 +98,7 @@ func (s *Server) ListGrantedProjectRoles(ctx context.Context, req *mgmt_pb.ListG if err != nil { return nil, err } - roles, err := s.query.SearchGrantedProjectRoles(ctx, req.GrantId, authz.GetCtxData(ctx).OrgID, queries) + roles, err := s.query.SearchGrantedProjectRoles(ctx, req.GrantId, authz.GetCtxData(ctx).OrgID, queries, false) if err != nil { return nil, err } @@ -172,7 +172,7 @@ func (s *Server) RemoveProject(ctx context.Context, req *mgmt_pb.RemoveProjectRe } grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{ Queries: []query.SearchQuery{projectQuery}, - }) + }, false) if err != nil { return nil, err } @@ -198,7 +198,7 @@ func (s *Server) ListProjectRoles(ctx context.Context, req *mgmt_pb.ListProjectR if err != nil { return nil, err } - roles, err := s.query.SearchProjectRoles(ctx, true, queries) + roles, err := s.query.SearchProjectRoles(ctx, true, queries, false) if err != nil { return nil, err } @@ -257,12 +257,12 @@ func (s *Server) RemoveProjectRole(ctx context.Context, req *mgmt_pb.RemoveProje } userGrants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{ Queries: []query.SearchQuery{projectQuery, rolesQuery}, - }) + }, false) if err != nil { return nil, err } - projectGrants, err := s.query.SearchProjectGrantsByProjectIDAndRoleKey(ctx, req.ProjectId, req.RoleKey) + projectGrants, err := s.query.SearchProjectGrantsByProjectIDAndRoleKey(ctx, req.ProjectId, req.RoleKey, false) if err != nil { return nil, err } @@ -288,7 +288,7 @@ func (s *Server) ListProjectMembers(ctx context.Context, req *mgmt_pb.ListProjec if err != nil { return nil, err } - members, err := s.query.ProjectMembers(ctx, queries) + members, err := s.query.ProjectMembers(ctx, queries, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/project_application.go b/internal/api/grpc/management/project_application.go index 1290d96681..422f2bf4b7 100644 --- a/internal/api/grpc/management/project_application.go +++ b/internal/api/grpc/management/project_application.go @@ -14,7 +14,7 @@ import ( ) func (s *Server) GetAppByID(ctx context.Context, req *mgmt_pb.GetAppByIDRequest) (*mgmt_pb.GetAppByIDResponse, error) { - app, err := s.query.AppByProjectAndAppID(ctx, true, req.ProjectId, req.AppId) + app, err := s.query.AppByProjectAndAppID(ctx, true, req.ProjectId, req.AppId, false) if err != nil { return nil, err } @@ -28,7 +28,7 @@ func (s *Server) ListApps(ctx context.Context, req *mgmt_pb.ListAppsRequest) (*m if err != nil { return nil, err } - apps, err := s.query.SearchApps(ctx, queries) + apps, err := s.query.SearchApps(ctx, queries, false) if err != nil { return nil, err } @@ -228,7 +228,7 @@ func (s *Server) GetAppKey(ctx context.Context, req *mgmt_pb.GetAppKeyRequest) ( if err != nil { return nil, err } - key, err := s.query.GetAuthNKeyByID(ctx, true, req.KeyId, resourceOwner, aggregateID, objectID) + key, err := s.query.GetAuthNKeyByID(ctx, true, req.KeyId, false, resourceOwner, aggregateID, objectID) if err != nil { return nil, err } @@ -242,7 +242,7 @@ func (s *Server) ListAppKeys(ctx context.Context, req *mgmt_pb.ListAppKeysReques if err != nil { return nil, err } - keys, err := s.query.SearchAuthNKeys(ctx, queries) + keys, err := s.query.SearchAuthNKeys(ctx, queries, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/project_grant.go b/internal/api/grpc/management/project_grant.go index 3426520400..002daeaa0d 100644 --- a/internal/api/grpc/management/project_grant.go +++ b/internal/api/grpc/management/project_grant.go @@ -13,7 +13,7 @@ import ( ) func (s *Server) GetProjectGrantByID(ctx context.Context, req *mgmt_pb.GetProjectGrantByIDRequest) (*mgmt_pb.GetProjectGrantByIDResponse, error) { - grant, err := s.query.ProjectGrantByID(ctx, true, req.GrantId) + grant, err := s.query.ProjectGrantByID(ctx, true, req.GrantId, false) if err != nil { return nil, err } @@ -31,7 +31,7 @@ func (s *Server) ListProjectGrants(ctx context.Context, req *mgmt_pb.ListProject if err != nil { return nil, err } - grants, err := s.query.SearchProjectGrants(ctx, queries) + grants, err := s.query.SearchProjectGrants(ctx, queries, false) if err != nil { return nil, err } @@ -54,7 +54,7 @@ func (s *Server) ListAllProjectGrants(ctx context.Context, req *mgmt_pb.ListAllP if err != nil { return nil, err } - grants, err := s.query.SearchProjectGrants(ctx, queries) + grants, err := s.query.SearchProjectGrants(ctx, queries, false) if err != nil { return nil, err } @@ -90,7 +90,7 @@ func (s *Server) UpdateProjectGrant(ctx context.Context, req *mgmt_pb.UpdateProj } grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{ Queries: []query.SearchQuery{projectQuery, grantQuery}, - }) + }, false) if err != nil { return nil, err } @@ -138,7 +138,7 @@ func (s *Server) RemoveProjectGrant(ctx context.Context, req *mgmt_pb.RemoveProj } userGrants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{ Queries: []query.SearchQuery{projectQuery, grantQuery}, - }) + }, true) if err != nil { return nil, err } @@ -164,7 +164,7 @@ func (s *Server) ListProjectGrantMembers(ctx context.Context, req *mgmt_pb.ListP if err != nil { return nil, err } - response, err := s.query.ProjectGrantMembers(ctx, queries) + response, err := s.query.ProjectGrantMembers(ctx, queries, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/user.go b/internal/api/grpc/management/user.go index 191bc82bce..8e0ecbe2aa 100644 --- a/internal/api/grpc/management/user.go +++ b/internal/api/grpc/management/user.go @@ -30,7 +30,7 @@ func (s *Server) GetUserByID(ctx context.Context, req *mgmt_pb.GetUserByIDReques if err != nil { return nil, err } - user, err := s.query.GetUserByID(ctx, true, req.Id, owner) + user, err := s.query.GetUserByID(ctx, true, req.Id, false, owner) if err != nil { return nil, err } @@ -44,7 +44,7 @@ func (s *Server) GetUserByLoginNameGlobal(ctx context.Context, req *mgmt_pb.GetU if err != nil { return nil, err } - user, err := s.query.GetUser(ctx, true, loginName) + user, err := s.query.GetUser(ctx, true, false, loginName) if err != nil { return nil, err } @@ -63,7 +63,7 @@ func (s *Server) ListUsers(ctx context.Context, req *mgmt_pb.ListUsersRequest) ( if err != nil { return nil, err } - res, err := s.query.SearchUsers(ctx, queries) + res, err := s.query.SearchUsers(ctx, queries, false) if err != nil { return nil, err } @@ -86,14 +86,14 @@ func (s *Server) ListUserChanges(ctx context.Context, req *mgmt_pb.ListUserChang func (s *Server) IsUserUnique(ctx context.Context, req *mgmt_pb.IsUserUniqueRequest) (*mgmt_pb.IsUserUniqueResponse, error) { orgID := authz.GetCtxData(ctx).OrgID - policy, err := s.query.DomainPolicyByOrg(ctx, true, orgID) + policy, err := s.query.DomainPolicyByOrg(ctx, true, orgID, false) if err != nil { return nil, err } if !policy.UserLoginMustBeDomain { orgID = "" } - unique, err := s.query.IsUserUnique(ctx, req.UserName, req.Email, orgID) + unique, err := s.query.IsUserUnique(ctx, req.UserName, req.Email, orgID, false) if err != nil { return nil, err } @@ -111,7 +111,7 @@ func (s *Server) ListUserMetadata(ctx context.Context, req *mgmt_pb.ListUserMeta if err != nil { return nil, err } - res, err := s.query.SearchUserMetadata(ctx, true, req.Id, metadataQueries) + res, err := s.query.SearchUserMetadata(ctx, true, req.Id, metadataQueries, false) if err != nil { return nil, err } @@ -126,7 +126,7 @@ func (s *Server) GetUserMetadata(ctx context.Context, req *mgmt_pb.GetUserMetada if err != nil { return nil, err } - data, err := s.query.GetUserMetadataByKey(ctx, true, req.Id, req.Key, owner) + data, err := s.query.GetUserMetadataByKey(ctx, true, req.Id, req.Key, false, owner) if err != nil { return nil, err } @@ -323,27 +323,11 @@ func (s *Server) UnlockUser(ctx context.Context, req *mgmt_pb.UnlockUserRequest) } func (s *Server) RemoveUser(ctx context.Context, req *mgmt_pb.RemoveUserRequest) (*mgmt_pb.RemoveUserResponse, error) { - userGrantUserQuery, err := query.NewUserGrantUserIDSearchQuery(req.Id) + memberships, grants, err := s.removeUserDependencies(ctx, req.Id) if err != nil { return nil, err } - grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{ - Queries: []query.SearchQuery{userGrantUserQuery}, - }) - if err != nil { - return nil, err - } - membershipsUserQuery, err := query.NewMembershipUserIDQuery(req.Id) - if err != nil { - return nil, err - } - memberships, err := s.query.Memberships(ctx, &query.MembershipSearchQuery{ - Queries: []query.SearchQuery{membershipsUserQuery}, - }) - if err != nil { - return nil, err - } - objectDetails, err := s.command.RemoveUser(ctx, req.Id, authz.GetCtxData(ctx).OrgID, cascadingMemberships(memberships.Memberships), userGrantsToIDs(grants.UserGrants)...) + objectDetails, err := s.command.RemoveUser(ctx, req.Id, authz.GetCtxData(ctx).OrgID, memberships, grants...) if err != nil { return nil, err } @@ -352,6 +336,30 @@ func (s *Server) RemoveUser(ctx context.Context, req *mgmt_pb.RemoveUserRequest) }, nil } +func (s *Server) removeUserDependencies(ctx context.Context, userID string) ([]*command.CascadingMembership, []string, error) { + userGrantUserQuery, err := query.NewUserGrantUserIDSearchQuery(userID) + if err != nil { + return nil, nil, err + } + grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{ + Queries: []query.SearchQuery{userGrantUserQuery}, + }, true) + if err != nil { + return nil, nil, err + } + membershipsUserQuery, err := query.NewMembershipUserIDQuery(userID) + if err != nil { + return nil, nil, err + } + memberships, err := s.query.Memberships(ctx, &query.MembershipSearchQuery{ + Queries: []query.SearchQuery{membershipsUserQuery}, + }, true) + if err != nil { + return nil, nil, err + } + return cascadingMemberships(memberships.Memberships), userGrantsToIDs(grants.UserGrants), nil +} + func (s *Server) UpdateUserName(ctx context.Context, req *mgmt_pb.UpdateUserNameRequest) (*mgmt_pb.UpdateUserNameResponse, error) { objectDetails, err := s.command.ChangeUsername(ctx, authz.GetCtxData(ctx).OrgID, req.UserId, req.UserName) if err != nil { @@ -367,7 +375,7 @@ func (s *Server) GetHumanProfile(ctx context.Context, req *mgmt_pb.GetHumanProfi if err != nil { return nil, err } - profile, err := s.query.GetHumanProfile(ctx, req.UserId, owner) + profile, err := s.query.GetHumanProfile(ctx, req.UserId, false, owner) if err != nil { return nil, err } @@ -401,7 +409,7 @@ func (s *Server) GetHumanEmail(ctx context.Context, req *mgmt_pb.GetHumanEmailRe if err != nil { return nil, err } - email, err := s.query.GetHumanEmail(ctx, req.UserId, owner) + email, err := s.query.GetHumanEmail(ctx, req.UserId, false, owner) if err != nil { return nil, err } @@ -467,7 +475,7 @@ func (s *Server) GetHumanPhone(ctx context.Context, req *mgmt_pb.GetHumanPhoneRe if err != nil { return nil, err } - phone, err := s.query.GetHumanPhone(ctx, req.UserId, owner) + phone, err := s.query.GetHumanPhone(ctx, req.UserId, false, owner) if err != nil { return nil, err } @@ -583,7 +591,7 @@ func (s *Server) ListHumanAuthFactors(ctx context.Context, req *mgmt_pb.ListHuma if err != nil { return nil, err } - authMethods, err := s.query.SearchUserAuthMethods(ctx, query) + authMethods, err := s.query.SearchUserAuthMethods(ctx, query, false) if err != nil { return nil, err } @@ -626,7 +634,7 @@ func (s *Server) ListHumanPasswordless(ctx context.Context, req *mgmt_pb.ListHum if err != nil { return nil, err } - authMethods, err := s.query.SearchUserAuthMethods(ctx, query) + authMethods, err := s.query.SearchUserAuthMethods(ctx, query, false) if err != nil { return nil, err } @@ -698,7 +706,7 @@ func (s *Server) GetMachineKeyByIDs(ctx context.Context, req *mgmt_pb.GetMachine if err != nil { return nil, err } - key, err := s.query.GetAuthNKeyByID(ctx, true, req.KeyId, resourceOwner, aggregateID) + key, err := s.query.GetAuthNKeyByID(ctx, true, req.KeyId, false, resourceOwner, aggregateID) if err != nil { return nil, err } @@ -712,7 +720,7 @@ func (s *Server) ListMachineKeys(ctx context.Context, req *mgmt_pb.ListMachineKe if err != nil { return nil, err } - result, err := s.query.SearchAuthNKeys(ctx, query) + result, err := s.query.SearchAuthNKeys(ctx, query, false) if err != nil { return nil, err } @@ -761,7 +769,7 @@ func (s *Server) GetPersonalAccessTokenByIDs(ctx context.Context, req *mgmt_pb.G if err != nil { return nil, err } - token, err := s.query.PersonalAccessTokenByID(ctx, true, req.TokenId, resourceOwner, aggregateID) + token, err := s.query.PersonalAccessTokenByID(ctx, true, req.TokenId, false, resourceOwner, aggregateID) if err != nil { return nil, err } @@ -775,7 +783,7 @@ func (s *Server) ListPersonalAccessTokens(ctx context.Context, req *mgmt_pb.List if err != nil { return nil, err } - result, err := s.query.SearchPersonalAccessTokens(ctx, queries) + result, err := s.query.SearchPersonalAccessTokens(ctx, queries, false) if err != nil { return nil, err } @@ -821,7 +829,7 @@ func (s *Server) ListHumanLinkedIDPs(ctx context.Context, req *mgmt_pb.ListHuman if err != nil { return nil, err } - res, err := s.query.IDPUserLinks(ctx, queries) + res, err := s.query.IDPUserLinks(ctx, queries, false) if err != nil { return nil, err } @@ -845,7 +853,7 @@ func (s *Server) ListUserMemberships(ctx context.Context, req *mgmt_pb.ListUserM if err != nil { return nil, err } - response, err := s.query.Memberships(ctx, request) + response, err := s.query.Memberships(ctx, request, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/user_grant.go b/internal/api/grpc/management/user_grant.go index 457491c145..8a71689150 100644 --- a/internal/api/grpc/management/user_grant.go +++ b/internal/api/grpc/management/user_grant.go @@ -19,7 +19,7 @@ func (s *Server) GetUserGrantByID(ctx context.Context, req *mgmt_pb.GetUserGrant if err != nil { return nil, err } - grant, err := s.query.UserGrant(ctx, true, idQuery, ownerQuery) + grant, err := s.query.UserGrant(ctx, true, false, idQuery, ownerQuery) if err != nil { return nil, err } @@ -33,7 +33,7 @@ func (s *Server) ListUserGrants(ctx context.Context, req *mgmt_pb.ListUserGrantR if err != nil { return nil, err } - res, err := s.query.UserGrants(ctx, queries) + res, err := s.query.UserGrants(ctx, queries, false) if err != nil { return nil, err } diff --git a/internal/api/grpc/org/converter.go b/internal/api/grpc/org/converter.go index d107bde10c..acd1c1c054 100644 --- a/internal/api/grpc/org/converter.go +++ b/internal/api/grpc/org/converter.go @@ -99,6 +99,8 @@ func OrgStateToPb(state domain.OrgState) org_pb.OrgState { return org_pb.OrgState_ORG_STATE_ACTIVE case domain.OrgStateInactive: return org_pb.OrgState_ORG_STATE_INACTIVE + case domain.OrgStateRemoved: + return org_pb.OrgState_ORG_STATE_REMOVED default: return org_pb.OrgState_ORG_STATE_UNSPECIFIED } diff --git a/internal/api/oidc/auth_request.go b/internal/api/oidc/auth_request.go index 8d2e8201e0..ba719229da 100644 --- a/internal/api/oidc/auth_request.go +++ b/internal/api/oidc/auth_request.go @@ -209,11 +209,11 @@ func (o *OPStorage) assertProjectRoleScopes(ctx context.Context, clientID string return scopes, nil } } - projectID, err := o.query.ProjectIDFromOIDCClientID(ctx, clientID) + projectID, err := o.query.ProjectIDFromOIDCClientID(ctx, clientID, false) if err != nil { return nil, errors.ThrowPreconditionFailed(nil, "OIDC-AEG4d", "Errors.Internal") } - project, err := o.query.ProjectByID(ctx, false, projectID) + project, err := o.query.ProjectByID(ctx, false, projectID, false) if err != nil { return nil, errors.ThrowPreconditionFailed(nil, "OIDC-w4wIn", "Errors.Internal") } @@ -224,7 +224,7 @@ func (o *OPStorage) assertProjectRoleScopes(ctx context.Context, clientID string if err != nil { return nil, errors.ThrowInternal(err, "OIDC-Cyc78", "Errors.Internal") } - roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}) + roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, false) if err != nil { return nil, err } @@ -236,7 +236,7 @@ func (o *OPStorage) assertProjectRoleScopes(ctx context.Context, clientID string func (o *OPStorage) assertClientScopesForPAT(ctx context.Context, token *model.TokenView, clientID string) error { token.Audience = append(token.Audience, clientID) - projectID, err := o.query.ProjectIDFromClientID(ctx, clientID) + projectID, err := o.query.ProjectIDFromClientID(ctx, clientID, false) if err != nil { return errors.ThrowPreconditionFailed(nil, "OIDC-AEG4d", "Errors.Internal") } @@ -244,7 +244,7 @@ func (o *OPStorage) assertClientScopesForPAT(ctx context.Context, token *model.T if err != nil { return errors.ThrowInternal(err, "OIDC-Cyc78", "Errors.Internal") } - roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}) + roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, false) if err != nil { return err } diff --git a/internal/api/oidc/client.go b/internal/api/oidc/client.go index 3a74395898..cc28b87010 100644 --- a/internal/api/oidc/client.go +++ b/internal/api/oidc/client.go @@ -39,7 +39,7 @@ const ( func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (_ op.Client, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - client, err := o.query.AppByOIDCClientID(ctx, id) + client, err := o.query.AppByOIDCClientID(ctx, id, false) if err != nil { return nil, err } @@ -50,7 +50,7 @@ func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (_ op.Cl if err != nil { return nil, errors.ThrowInternal(err, "OIDC-mPxqP", "Errors.Internal") } - projectRoles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}) + projectRoles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, false) if err != nil { return nil, err } @@ -74,7 +74,7 @@ func (o *OPStorage) GetKeyByIDAndUserID(ctx context.Context, keyID, userID strin func (o *OPStorage) GetKeyByIDAndIssuer(ctx context.Context, keyID, issuer string) (_ *jose.JSONWebKey, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - publicKeyData, err := o.query.GetAuthNKeyPublicKeyByIDAndIdentifier(ctx, keyID, issuer) + publicKeyData, err := o.query.GetAuthNKeyPublicKeyByIDAndIdentifier(ctx, keyID, issuer, false) if err != nil { return nil, err } @@ -90,7 +90,7 @@ func (o *OPStorage) GetKeyByIDAndIssuer(ctx context.Context, keyID, issuer strin } func (o *OPStorage) ValidateJWTProfileScopes(ctx context.Context, subject string, scopes []string) ([]string, error) { - user, err := o.query.GetUserByID(ctx, true, subject) + user, err := o.query.GetUserByID(ctx, true, subject, false) if err != nil { return nil, err } @@ -126,7 +126,7 @@ func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secr UserID: oidcCtx, OrgID: oidcCtx, }) - app, err := o.query.AppByClientID(ctx, id) + app, err := o.query.AppByClientID(ctx, id, false) if err != nil { return err } @@ -144,7 +144,7 @@ func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo oidc.User return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired") } if token.ApplicationID != "" { - app, err := o.query.AppByOIDCClientID(ctx, token.ApplicationID) + app, err := o.query.AppByOIDCClientID(ctx, token.ApplicationID, false) if err != nil { return err } @@ -159,7 +159,7 @@ func (o *OPStorage) SetUserinfoFromScopes(ctx context.Context, userInfo oidc.Use ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() if applicationID != "" { - app, err := o.query.AppByOIDCClientID(ctx, applicationID) + app, err := o.query.AppByOIDCClientID(ctx, applicationID, false) if err != nil { return err } @@ -178,7 +178,7 @@ func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection if err != nil { return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired") } - projectID, err := o.query.ProjectIDFromClientID(ctx, clientID) + projectID, err := o.query.ProjectIDFromClientID(ctx, clientID, false) if err != nil { return errors.ThrowPermissionDenied(nil, "OIDC-Adfg5", "client not found") } @@ -212,7 +212,7 @@ func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection func (o *OPStorage) setUserinfo(ctx context.Context, userInfo oidc.UserInfoSetter, userID, applicationID string, scopes []string) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - user, err := o.query.GetUserByID(ctx, true, userID) + user, err := o.query.GetUserByID(ctx, true, userID, false) if err != nil { return err } @@ -299,7 +299,7 @@ func (o *OPStorage) setUserinfo(ctx context.Context, userInfo oidc.UserInfoSette } func (o *OPStorage) userinfoFlows(ctx context.Context, resourceOwner string, userInfo oidc.UserInfoSetter) error { - queriedActions, err := o.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeCustomiseToken, domain.TriggerTypePreUserinfoCreation, resourceOwner) + queriedActions, err := o.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeCustomiseToken, domain.TriggerTypePreUserinfoCreation, resourceOwner, false) if err != nil { return err } @@ -319,6 +319,7 @@ func (o *OPStorage) userinfoFlows(ctx context.Context, resourceOwner string, use true, userInfo.GetSubject(), &query.UserMetadataSearchQueries{Queries: []query.SearchQuery{resourceOwnerQuery}}, + false, ) if err != nil { logging.WithError(err).Info("unable to get md in action") @@ -451,11 +452,11 @@ func (o *OPStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clie } func (o *OPStorage) privateClaimsFlows(ctx context.Context, userID string, claims map[string]interface{}) (map[string]interface{}, error) { - user, err := o.query.GetUserByID(ctx, true, userID) + user, err := o.query.GetUserByID(ctx, true, userID, false) if err != nil { return nil, err } - queriedActions, err := o.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeCustomiseToken, domain.TriggerTypePreAccessTokenCreation, user.ResourceOwner) + queriedActions, err := o.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeCustomiseToken, domain.TriggerTypePreAccessTokenCreation, user.ResourceOwner, false) if err != nil { return nil, err } @@ -475,6 +476,7 @@ func (o *OPStorage) privateClaimsFlows(ctx context.Context, userID string, claim true, userID, &query.UserMetadataSearchQueries{Queries: []query.SearchQuery{resourceOwnerQuery}}, + false, ) if err != nil { logging.WithError(err).Info("unable to get md in action") @@ -554,7 +556,7 @@ func (o *OPStorage) privateClaimsFlows(ctx context.Context, userID string, claim } func (o *OPStorage) assertRoles(ctx context.Context, userID, applicationID string, requestedRoles []string) (map[string]map[string]string, error) { - projectID, err := o.query.ProjectIDFromClientID(ctx, applicationID) + projectID, err := o.query.ProjectIDFromClientID(ctx, applicationID, false) if err != nil { return nil, err } @@ -568,7 +570,7 @@ func (o *OPStorage) assertRoles(ctx context.Context, userID, applicationID strin } grants, err := o.query.UserGrants(ctx, &query.UserGrantsQueries{ Queries: []query.SearchQuery{projectQuery, userIDQuery}, - }) + }, false) if err != nil { return nil, err } @@ -582,7 +584,7 @@ func (o *OPStorage) assertRoles(ctx context.Context, userID, applicationID strin } func (o *OPStorage) assertUserMetaData(ctx context.Context, userID string) (map[string]string, error) { - metaData, err := o.query.SearchUserMetadata(ctx, true, userID, &query.UserMetadataSearchQueries{}) + metaData, err := o.query.SearchUserMetadata(ctx, true, userID, &query.UserMetadataSearchQueries{}, false) if err != nil { return nil, err } @@ -595,7 +597,7 @@ func (o *OPStorage) assertUserMetaData(ctx context.Context, userID string) (map[ } func (o *OPStorage) assertUserResourceOwner(ctx context.Context, userID string) (map[string]string, error) { - user, err := o.query.GetUserByID(ctx, true, userID) + user, err := o.query.GetUserByID(ctx, true, userID, false) if err != nil { return nil, err } diff --git a/internal/api/oidc/key.go b/internal/api/oidc/key.go index ccb5ef839b..a587a949df 100644 --- a/internal/api/oidc/key.go +++ b/internal/api/oidc/key.go @@ -92,6 +92,7 @@ func (o *OPStorage) KeySet(ctx context.Context) (keys []op.Key, err error) { func (o *OPStorage) SignatureAlgorithms(ctx context.Context) ([]jose.SignatureAlgorithm, error) { key, err := o.SigningKey(ctx) if err != nil { + logging.WithError(err).Warn("unable to fetch signing key") return nil, err } return []jose.SignatureAlgorithm{key.SignatureAlgorithm()}, nil diff --git a/internal/api/saml/storage.go b/internal/api/saml/storage.go index 4632ec9db8..1c855a6671 100644 --- a/internal/api/saml/storage.go +++ b/internal/api/saml/storage.go @@ -49,7 +49,7 @@ type Storage struct { } func (p *Storage) GetEntityByID(ctx context.Context, entityID string) (*serviceprovider.ServiceProvider, error) { - app, err := p.query.AppBySAMLEntityID(ctx, entityID) + app, err := p.query.AppBySAMLEntityID(ctx, entityID, false) if err != nil { return nil, err } @@ -63,7 +63,7 @@ func (p *Storage) GetEntityByID(ctx context.Context, entityID string) (*servicep } func (p *Storage) GetEntityIDByAppID(ctx context.Context, appID string) (string, error) { - app, err := p.query.AppByID(ctx, appID) + app, err := p.query.AppByID(ctx, appID, false) if err != nil { return "", err } @@ -121,7 +121,7 @@ func (p *Storage) AuthRequestByID(ctx context.Context, id string) (_ models.Auth func (p *Storage) SetUserinfoWithUserID(ctx context.Context, userinfo models.AttributeSetter, userID string, attributes []int) (err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - user, err := p.query.GetUserByID(ctx, true, userID) + user, err := p.query.GetUserByID(ctx, true, userID, false) if err != nil { return err } @@ -138,7 +138,7 @@ func (p *Storage) SetUserinfoWithLoginName(ctx context.Context, userinfo models. if err != nil { return err } - user, err := p.query.GetUser(ctx, true, loginNameSQ) + user, err := p.query.GetUser(ctx, true, false, loginNameSQ) if err != nil { return err } diff --git a/internal/api/ui/login/change_password_handler.go b/internal/api/ui/login/change_password_handler.go index bdbbb20682..08eb8badeb 100644 --- a/internal/api/ui/login/change_password_handler.go +++ b/internal/api/ui/login/change_password_handler.go @@ -42,7 +42,7 @@ func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, aut } translator := l.getTranslator(r.Context(), authReq) data := passwordData{ - baseData: l.getBaseData(r, authReq, "PasswordChange.Title","PasswordChange.Description", errID, errMessage), + baseData: l.getBaseData(r, authReq, "PasswordChange.Title", "PasswordChange.Description", errID, errMessage), profileData: l.getProfileData(authReq), } policy := l.getPasswordComplexityPolicy(r, authReq.UserOrgID) @@ -67,6 +67,6 @@ func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, aut func (l *Login) renderChangePasswordDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { var errType, errMessage string translator := l.getTranslator(r.Context(), authReq) - data := l.getUserData(r, authReq, "PasswordChange.Title","PasswordChange.Description", errType, errMessage) + data := l.getUserData(r, authReq, "PasswordChange.Title", "PasswordChange.Description", errType, errMessage) l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplChangePasswordDone], data, nil) } diff --git a/internal/api/ui/login/custom_action.go b/internal/api/ui/login/custom_action.go index ac2dcea71e..f63d3b8487 100644 --- a/internal/api/ui/login/custom_action.go +++ b/internal/api/ui/login/custom_action.go @@ -25,7 +25,7 @@ func (l *Login) customExternalUserMapping(ctx context.Context, user *domain.Exte if resourceOwner == instance.InstanceID() { resourceOwner = instance.DefaultOrganisationID() } - triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePostAuthentication, resourceOwner) + triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePostAuthentication, resourceOwner, false) if err != nil { return nil, err } @@ -126,7 +126,7 @@ func (l *Login) customExternalUserMapping(ctx context.Context, user *domain.Exte } func (l *Login) customExternalUserToLoginUserMapping(ctx context.Context, user *domain.Human, tokens *oidc.Tokens, req *domain.AuthRequest, config *iam_model.IDPConfigView, metadata []*domain.Metadata, resourceOwner string) (*domain.Human, []*domain.Metadata, error) { - triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePreCreation, resourceOwner) + triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePreCreation, resourceOwner, false) if err != nil { return nil, nil, err } @@ -230,7 +230,7 @@ func (l *Login) customExternalUserToLoginUserMapping(ctx context.Context, user * } func (l *Login) customGrants(ctx context.Context, userID string, tokens *oidc.Tokens, req *domain.AuthRequest, config *iam_model.IDPConfigView, resourceOwner string) ([]*domain.UserGrant, error) { - triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePostCreation, resourceOwner) + triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePostCreation, resourceOwner, false) if err != nil { return nil, err } @@ -287,7 +287,7 @@ func (l *Login) customGrants(ctx context.Context, userID string, tokens *oidc.To actions.SetFields("v1", actions.SetFields("getUser", func(c *actions.FieldConfig) interface{} { return func(call goja.FunctionCall) goja.Value { - user, err := l.query.GetUserByID(actionCtx, true, userID) + user, err := l.query.GetUserByID(actionCtx, true, userID, false) if err != nil { panic(err) } diff --git a/internal/api/ui/login/init_password_handler.go b/internal/api/ui/login/init_password_handler.go index eaf268fa37..5418f702eb 100644 --- a/internal/api/ui/login/init_password_handler.go +++ b/internal/api/ui/login/init_password_handler.go @@ -106,7 +106,7 @@ func (l *Login) resendPasswordSet(w http.ResponseWriter, r *http.Request, authRe l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) return } - user, err := l.query.GetUser(setContext(r.Context(), userOrg), false, loginName) + user, err := l.query.GetUser(setContext(r.Context(), userOrg), false, false, loginName) if err != nil { l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) return @@ -127,7 +127,7 @@ func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authR translator := l.getTranslator(r.Context(), authReq) data := initPasswordData{ - baseData: l.getBaseData(r, authReq, "InitPassword.Title","InitPassword.Description", errID, errMessage), + baseData: l.getBaseData(r, authReq, "InitPassword.Title", "InitPassword.Description", errID, errMessage), profileData: l.getProfileData(authReq), UserID: userID, Code: code, @@ -149,7 +149,7 @@ func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authR } } if authReq == nil { - user, err := l.query.GetUserByID(r.Context(), false, userID) + user, err := l.query.GetUserByID(r.Context(), false, userID, false) if err == nil { l.customTexts(r.Context(), translator, user.ResourceOwner) } diff --git a/internal/api/ui/login/init_user_handler.go b/internal/api/ui/login/init_user_handler.go index 41bba5931b..c058c62436 100644 --- a/internal/api/ui/login/init_user_handler.go +++ b/internal/api/ui/login/init_user_handler.go @@ -10,10 +10,10 @@ import ( ) const ( - queryInitUserCode = "code" - queryInitUserUserID = "userID" + queryInitUserCode = "code" + queryInitUserUserID = "userID" queryInitUserLoginName = "loginname" - queryInitUserPassword = "passwordset" + queryInitUserPassword = "passwordset" tmplInitUser = "inituser" tmplInitUserDone = "inituserdone" @@ -73,7 +73,7 @@ func (l *Login) handleInitUserCheck(w http.ResponseWriter, r *http.Request) { func (l *Login) checkUserInitCode(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *initUserFormData, err error) { if data.Password != data.PasswordConfirm { err := caos_errs.ThrowInvalidArgument(nil, "VIEW-fsdfd", "Errors.User.Password.ConfirmationWrong") - l.renderInitUser(w, r, authReq, data.UserID,data.LoginName, data.Code, data.PasswordSet, err) + l.renderInitUser(w, r, authReq, data.UserID, data.LoginName, data.Code, data.PasswordSet, err) return } userOrgID := "" @@ -82,32 +82,32 @@ func (l *Login) checkUserInitCode(w http.ResponseWriter, r *http.Request, authRe } initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.userCodeAlg) if err != nil { - l.renderInitUser(w, r, authReq, data.UserID,data.LoginName, "", data.PasswordSet, err) + l.renderInitUser(w, r, authReq, data.UserID, data.LoginName, "", data.PasswordSet, err) return } err = l.command.HumanVerifyInitCode(setContext(r.Context(), userOrgID), data.UserID, userOrgID, data.Code, data.Password, initCodeGenerator) if err != nil { - l.renderInitUser(w, r, authReq, data.UserID,data.LoginName, "", data.PasswordSet, err) + l.renderInitUser(w, r, authReq, data.UserID, data.LoginName, "", data.PasswordSet, err) return } l.renderInitUserDone(w, r, authReq, userOrgID) } -func (l *Login) resendUserInit(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID string,loginName string, showPassword bool) { +func (l *Login) resendUserInit(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID string, loginName string, showPassword bool) { userOrgID := "" if authReq != nil { userOrgID = authReq.UserOrgID } initCodeGenerator, err := l.query.InitEncryptionGenerator(r.Context(), domain.SecretGeneratorTypeInitCode, l.userCodeAlg) if err != nil { - l.renderInitUser(w, r, authReq, userID,loginName, "", showPassword, err) + l.renderInitUser(w, r, authReq, userID, loginName, "", showPassword, err) return } _, err = l.command.ResendInitialMail(setContext(r.Context(), userOrgID), userID, "", userOrgID, initCodeGenerator) l.renderInitUser(w, r, authReq, userID, loginName, "", showPassword, err) } -func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID,loginName string, code string, passwordSet bool, err error) { +func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID, loginName string, code string, passwordSet bool, err error) { var errID, errMessage string if err != nil { errID, errMessage = l.getErrorMessage(r, err) @@ -142,7 +142,7 @@ func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq * } } if authReq == nil { - user, err := l.query.GetUserByID(r.Context(), false, userID) + user, err := l.query.GetUserByID(r.Context(), false, userID, false) if err == nil { l.customTexts(r.Context(), translator, user.ResourceOwner) } @@ -151,7 +151,7 @@ func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq * } func (l *Login) renderInitUserDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgID string) { - data := l.getUserData(r, authReq,"InitUserDone.Title" ,"InitUserDone.Description", "", "") + data := l.getUserData(r, authReq, "InitUserDone.Title", "InitUserDone.Description", "", "") translator := l.getTranslator(r.Context(), authReq) if authReq == nil { l.customTexts(r.Context(), translator, orgID) diff --git a/internal/api/ui/login/login.go b/internal/api/ui/login/login.go index 79e7bdaa97..d8e02a7892 100644 --- a/internal/api/ui/login/login.go +++ b/internal/api/ui/login/login.go @@ -152,7 +152,7 @@ func (l *Login) getClaimedUserIDsOfOrgDomain(ctx context.Context, orgName string if err != nil { return nil, err } - users, err := l.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{loginName}}) + users, err := l.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: []query.SearchQuery{loginName}}, false) if err != nil { return nil, err } diff --git a/internal/api/ui/login/login_handler.go b/internal/api/ui/login/login_handler.go index b90e593c81..c141600926 100644 --- a/internal/api/ui/login/login_handler.go +++ b/internal/api/ui/login/login_handler.go @@ -99,7 +99,7 @@ func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *dom l.handleIDP(w, r, authReq, authReq.AllowedExternalIDPs[0].IDPConfigID) return } - data := l.getUserData(r, authReq, "Login.Title","Login.Description", errID, errMessage) + data := l.getUserData(r, authReq, "Login.Title", "Login.Description", errID, errMessage) funcs := map[string]interface{}{ "hasUsernamePasswordLogin": func() bool { return authReq != nil && authReq.LoginPolicy != nil && authReq.LoginPolicy.AllowUsernamePassword diff --git a/internal/api/ui/login/login_success_handler.go b/internal/api/ui/login/login_success_handler.go index 155de90a54..57b4ececd5 100644 --- a/internal/api/ui/login/login_success_handler.go +++ b/internal/api/ui/login/login_success_handler.go @@ -41,7 +41,7 @@ func (l *Login) renderSuccessAndCallback(w http.ResponseWriter, r *http.Request, errID, errMessage = l.getErrorMessage(r, err) } data := loginSuccessData{ - userData: l.getUserData(r, authReq, "LoginSuccess.Title","", errID, errMessage), + userData: l.getUserData(r, authReq, "LoginSuccess.Title", "", errID, errMessage), } if authReq != nil { //the id will be set via the html (maybe change this with the login refactoring) diff --git a/internal/api/ui/login/logout_handler.go b/internal/api/ui/login/logout_handler.go index 21a3c436bb..2146d47e49 100644 --- a/internal/api/ui/login/logout_handler.go +++ b/internal/api/ui/login/logout_handler.go @@ -13,6 +13,6 @@ func (l *Login) handleLogoutDone(w http.ResponseWriter, r *http.Request) { } func (l *Login) renderLogoutDone(w http.ResponseWriter, r *http.Request) { - data := l.getUserData(r, nil, "LogoutDone.Title","LogoutDone.Description", "", "") + data := l.getUserData(r, nil, "LogoutDone.Title", "LogoutDone.Description", "", "") l.renderer.RenderTemplate(w, r, l.getTranslator(r.Context(), nil), l.renderer.Templates[tmplLogoutDone], data, nil) } diff --git a/internal/api/ui/login/mail_verify_handler.go b/internal/api/ui/login/mail_verify_handler.go index bb61a842c8..d26c0c68ba 100644 --- a/internal/api/ui/login/mail_verify_handler.go +++ b/internal/api/ui/login/mail_verify_handler.go @@ -95,12 +95,12 @@ func (l *Login) renderMailVerification(w http.ResponseWriter, r *http.Request, a translator := l.getTranslator(r.Context(), authReq) data := mailVerificationData{ - baseData: l.getBaseData(r, authReq, "EmailVerification.Title","EmailVerification.Description", errID, errMessage), + baseData: l.getBaseData(r, authReq, "EmailVerification.Title", "EmailVerification.Description", errID, errMessage), UserID: userID, profileData: l.getProfileData(authReq), } if authReq == nil { - user, err := l.query.GetUserByID(r.Context(), false, userID) + user, err := l.query.GetUserByID(r.Context(), false, userID, false) if err == nil { l.customTexts(r.Context(), translator, user.ResourceOwner) } @@ -111,7 +111,7 @@ func (l *Login) renderMailVerification(w http.ResponseWriter, r *http.Request, a func (l *Login) renderMailVerified(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgID string) { translator := l.getTranslator(r.Context(), authReq) data := mailVerificationData{ - baseData: l.getBaseData(r, authReq, "EmailVerificationDone.Title","EmailVerificationDone.Description", "", ""), + baseData: l.getBaseData(r, authReq, "EmailVerificationDone.Title", "EmailVerificationDone.Description", "", ""), profileData: l.getProfileData(authReq), } if authReq == nil { diff --git a/internal/api/ui/login/mfa_init_done_handler.go b/internal/api/ui/login/mfa_init_done_handler.go index 0ef0c2ab84..f38927d5e7 100644 --- a/internal/api/ui/login/mfa_init_done_handler.go +++ b/internal/api/ui/login/mfa_init_done_handler.go @@ -16,7 +16,7 @@ type mfaInitDoneData struct { func (l *Login) renderMFAInitDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *mfaDoneData) { var errType, errMessage string translator := l.getTranslator(r.Context(), authReq) - data.baseData = l.getBaseData(r, authReq, "InitMFADone.Title","InitMFADone.Description", errType, errMessage) + data.baseData = l.getBaseData(r, authReq, "InitMFADone.Title", "InitMFADone.Description", errType, errMessage) data.profileData = l.getProfileData(authReq) l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplMFAInitDone], data, nil) } diff --git a/internal/api/ui/login/mfa_init_u2f.go b/internal/api/ui/login/mfa_init_u2f.go index 210f6949fc..f00b398f0e 100644 --- a/internal/api/ui/login/mfa_init_u2f.go +++ b/internal/api/ui/login/mfa_init_u2f.go @@ -31,7 +31,7 @@ func (l *Login) renderRegisterU2F(w http.ResponseWriter, r *http.Request, authRe } data := &u2fInitData{ webAuthNData: webAuthNData{ - userData: l.getUserData(r, authReq, "InitMFAU2F.Title","InitMFAU2F.Description", errID, errMessage), + userData: l.getUserData(r, authReq, "InitMFAU2F.Title", "InitMFAU2F.Description", errID, errMessage), CredentialCreationData: credentialData, }, MFAType: domain.MFATypeU2F, diff --git a/internal/api/ui/login/mfa_prompt_handler.go b/internal/api/ui/login/mfa_prompt_handler.go index 8ca0783c8a..185d61be99 100644 --- a/internal/api/ui/login/mfa_prompt_handler.go +++ b/internal/api/ui/login/mfa_prompt_handler.go @@ -56,7 +56,7 @@ func (l *Login) renderMFAPrompt(w http.ResponseWriter, r *http.Request, authReq } translator := l.getTranslator(r.Context(), authReq) data := mfaData{ - baseData: l.getBaseData(r, authReq, "InitMFAPrompt.Title","InitMFAPrompt.Description", errID, errMessage), + baseData: l.getBaseData(r, authReq, "InitMFAPrompt.Title", "InitMFAPrompt.Description", errID, errMessage), profileData: l.getProfileData(authReq), } diff --git a/internal/api/ui/login/mfa_verify_handler.go b/internal/api/ui/login/mfa_verify_handler.go index dde6341da1..7640b9cade 100644 --- a/internal/api/ui/login/mfa_verify_handler.go +++ b/internal/api/ui/login/mfa_verify_handler.go @@ -58,7 +58,7 @@ func (l *Login) renderMFAVerifySelected(w http.ResponseWriter, r *http.Request, if err != nil { errID, errMessage = l.getErrorMessage(r, err) } - data := l.getUserData(r, authReq, "","", errID, errMessage) + data := l.getUserData(r, authReq, "", "", errID, errMessage) if verificationStep == nil { l.renderError(w, r, authReq, err) return diff --git a/internal/api/ui/login/mfa_verify_u2f_handler.go b/internal/api/ui/login/mfa_verify_u2f_handler.go index 135f29971a..eb5f4a9e77 100644 --- a/internal/api/ui/login/mfa_verify_u2f_handler.go +++ b/internal/api/ui/login/mfa_verify_u2f_handler.go @@ -39,7 +39,7 @@ func (l *Login) renderU2FVerification(w http.ResponseWriter, r *http.Request, au } data := &mfaU2FData{ webAuthNData: webAuthNData{ - userData: l.getUserData(r, authReq, "VerifyMFAU2F.Title","VerifyMFAU2F.Description", errID, errMessage), + userData: l.getUserData(r, authReq, "VerifyMFAU2F.Title", "VerifyMFAU2F.Description", errID, errMessage), CredentialCreationData: credentialData, }, MFAProviders: providers, diff --git a/internal/api/ui/login/password_complexity_policy_handler.go b/internal/api/ui/login/password_complexity_policy_handler.go index 805194a077..ee0bacdaec 100644 --- a/internal/api/ui/login/password_complexity_policy_handler.go +++ b/internal/api/ui/login/password_complexity_policy_handler.go @@ -22,7 +22,7 @@ func (l *Login) getPasswordComplexityPolicy(r *http.Request, orgID string) *iam_ } func (l *Login) getPasswordComplexityPolicyByUserID(r *http.Request, userID string) *iam_model.PasswordComplexityPolicyView { - user, err := l.query.GetUserByID(r.Context(), false, userID) + user, err := l.query.GetUserByID(r.Context(), false, userID, false) if err != nil { logging.WithFields("userID", userID).OnError(err).Error("could not load user for password complexity policy") return nil diff --git a/internal/api/ui/login/password_handler.go b/internal/api/ui/login/password_handler.go index ed292d22e3..fa9a884443 100644 --- a/internal/api/ui/login/password_handler.go +++ b/internal/api/ui/login/password_handler.go @@ -19,7 +19,7 @@ func (l *Login) renderPassword(w http.ResponseWriter, r *http.Request, authReq * if err != nil { errID, errMessage = l.getErrorMessage(r, err) } - data := l.getUserData(r, authReq, "Password.Title","Password.Description", errID, errMessage) + data := l.getUserData(r, authReq, "Password.Title", "Password.Description", errID, errMessage) funcs := map[string]interface{}{ "showPasswordReset": func() bool { if authReq.LoginPolicy != nil { diff --git a/internal/api/ui/login/password_reset_handler.go b/internal/api/ui/login/password_reset_handler.go index c7dcc0a97f..90da71d263 100644 --- a/internal/api/ui/login/password_reset_handler.go +++ b/internal/api/ui/login/password_reset_handler.go @@ -23,7 +23,7 @@ func (l *Login) handlePasswordReset(w http.ResponseWriter, r *http.Request) { l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) return } - user, err := l.query.GetUser(setContext(r.Context(), authReq.UserOrgID), true, loginName) + user, err := l.query.GetUser(setContext(r.Context(), authReq.UserOrgID), true, false, loginName) if err != nil { l.renderPasswordResetDone(w, r, authReq, err) return @@ -45,6 +45,6 @@ func (l *Login) renderPasswordResetDone(w http.ResponseWriter, r *http.Request, if err != nil { errID, errMessage = l.getErrorMessage(r, err) } - data := l.getUserData(r, authReq, "PasswordResetDone.Title","PasswordResetDone.Description", errID, errMessage) + data := l.getUserData(r, authReq, "PasswordResetDone.Title", "PasswordResetDone.Description", errID, errMessage) l.renderer.RenderTemplate(w, r, l.getTranslator(r.Context(), authReq), l.renderer.Templates[tmplPasswordResetDone], data, nil) } diff --git a/internal/api/ui/login/passwordless_login_handler.go b/internal/api/ui/login/passwordless_login_handler.go index 69d2b5121f..d199faa2ab 100644 --- a/internal/api/ui/login/passwordless_login_handler.go +++ b/internal/api/ui/login/passwordless_login_handler.go @@ -38,7 +38,7 @@ func (l *Login) renderPasswordlessVerification(w http.ResponseWriter, r *http.Re } data := &passwordlessData{ webAuthNData{ - userData: l.getUserData(r, authReq, "Passwordless.Title","Passwordless.Description", errID, errMessage), + userData: l.getUserData(r, authReq, "Passwordless.Title", "Passwordless.Description", errID, errMessage), CredentialCreationData: credentialData, }, passwordSet, diff --git a/internal/api/ui/login/passwordless_prompt_handler.go b/internal/api/ui/login/passwordless_prompt_handler.go index 8020184c18..24a1eabf6c 100644 --- a/internal/api/ui/login/passwordless_prompt_handler.go +++ b/internal/api/ui/login/passwordless_prompt_handler.go @@ -32,7 +32,7 @@ func (l *Login) renderPasswordlessPrompt(w http.ResponseWriter, r *http.Request, errID, errMessage = l.getErrorMessage(r, err) } data := &passwordlessPromptData{ - userData: l.getUserData(r, authReq, "PasswordlessPrompt.Title","PasswordlessPrompt.Description", errID, errMessage), + userData: l.getUserData(r, authReq, "PasswordlessPrompt.Title", "PasswordlessPrompt.Description", errID, errMessage), } translator := l.getTranslator(r.Context(), authReq) diff --git a/internal/api/ui/login/passwordless_registration_handler.go b/internal/api/ui/login/passwordless_registration_handler.go index af9444047d..b70aac0c60 100644 --- a/internal/api/ui/login/passwordless_registration_handler.go +++ b/internal/api/ui/login/passwordless_registration_handler.go @@ -114,7 +114,7 @@ func (l *Login) renderPasswordlessRegistration(w http.ResponseWriter, r *http.Re disabled, } if authReq == nil { - policy, err := l.query.ActiveLabelPolicyByOrg(r.Context(), orgID) + policy, err := l.query.ActiveLabelPolicyByOrg(r.Context(), orgID, false) logging.Log("HANDL-XjWKE").OnError(err).Error("unable to get active label policy") data.LabelPolicy = labelPolicyToDomain(policy) @@ -195,7 +195,7 @@ func (l *Login) renderPasswordlessRegistrationDone(w http.ResponseWriter, r *htt translator := l.getTranslator(r.Context(), authReq) data := passwordlessRegistrationDoneDate{ - userData: l.getUserData(r, authReq, "PasswordlessRegistrationDone.Title","PasswordlessRegistrationDone.Description", errID, errMessage), + userData: l.getUserData(r, authReq, "PasswordlessRegistrationDone.Title", "PasswordlessRegistrationDone.Description", errID, errMessage), HideNextButton: authReq == nil, } if authReq == nil { diff --git a/internal/api/ui/login/policy_handler.go b/internal/api/ui/login/policy_handler.go index f5db76a2bc..8b8bcd6987 100644 --- a/internal/api/ui/login/policy_handler.go +++ b/internal/api/ui/login/policy_handler.go @@ -15,7 +15,7 @@ func (l *Login) getOrgDomainPolicy(r *http.Request, orgID string) (*query.Domain if orgID == "" { return l.query.DefaultDomainPolicy(r.Context()) } - return l.query.DomainPolicyByOrg(r.Context(), false, orgID) + return l.query.DomainPolicyByOrg(r.Context(), false, orgID, false) } func (l *Login) getIDPConfigByID(r *http.Request, idpConfigID string) (*iam_model.IDPConfigView, error) { @@ -26,12 +26,12 @@ func (l *Login) getLoginPolicy(r *http.Request, orgID string) (*query.LoginPolic if orgID == "" { return l.query.DefaultLoginPolicy(r.Context()) } - return l.query.LoginPolicyByID(r.Context(), false, orgID) + return l.query.LoginPolicyByID(r.Context(), false, orgID, false) } func (l *Login) getLabelPolicy(r *http.Request, orgID string) (*query.LabelPolicy, error) { if orgID == "" { return l.query.DefaultActiveLabelPolicy(r.Context()) } - return l.query.ActiveLabelPolicyByOrg(r.Context(), orgID) + return l.query.ActiveLabelPolicyByOrg(r.Context(), orgID, false) } diff --git a/internal/api/ui/login/register_handler.go b/internal/api/ui/login/register_handler.go index d0213b806e..8ae9daf738 100644 --- a/internal/api/ui/login/register_handler.go +++ b/internal/api/ui/login/register_handler.go @@ -124,7 +124,7 @@ func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authReque } data := registerData{ - baseData: l.getBaseData(r, authRequest, "RegistrationUser.Title","RegistrationUser.Description", errID, errMessage), + baseData: l.getBaseData(r, authRequest, "RegistrationUser.Title", "RegistrationUser.Description", errID, errMessage), registerFormData: *formData, } diff --git a/internal/api/ui/login/register_option_handler.go b/internal/api/ui/login/register_option_handler.go index 08f0617043..c00ee18a2d 100644 --- a/internal/api/ui/login/register_option_handler.go +++ b/internal/api/ui/login/register_option_handler.go @@ -54,7 +54,7 @@ func (l *Login) renderRegisterOption(w http.ResponseWriter, r *http.Request, aut } translator := l.getTranslator(r.Context(), authReq) data := registerOptionData{ - baseData: l.getBaseData(r, authReq, "RegisterOption.Title","RegisterOption.Description", errID, errMessage), + baseData: l.getBaseData(r, authReq, "RegisterOption.Title", "RegisterOption.Description", errID, errMessage), } funcs := map[string]interface{}{ "hasRegistration": func() bool { @@ -109,7 +109,7 @@ func (l *Login) passLoginHintToRegistration(r *http.Request, authReq *domain.Aut logging.WithFields("authRequest", authReq.ID, "org", authReq.RequestedOrgID).Error("unable to search query for registration loginHint") return data } - domains, err := l.query.SearchOrgDomains(r.Context(), &query.OrgDomainSearchQueries{Queries: []query.SearchQuery{searchQuery}}) + domains, err := l.query.SearchOrgDomains(r.Context(), &query.OrgDomainSearchQueries{Queries: []query.SearchQuery{searchQuery}}, false) if err != nil { logging.WithFields("authRequest", authReq.ID, "org", authReq.RequestedOrgID).Error("unable to load domains for registration loginHint") return data diff --git a/internal/api/ui/login/register_org_handler.go b/internal/api/ui/login/register_org_handler.go index 80c25c2b6c..f56f429a27 100644 --- a/internal/api/ui/login/register_org_handler.go +++ b/internal/api/ui/login/register_org_handler.go @@ -88,7 +88,7 @@ func (l *Login) renderRegisterOrg(w http.ResponseWriter, r *http.Request, authRe } translator := l.getTranslator(r.Context(), authRequest) data := registerOrgData{ - baseData: l.getBaseData(r, authRequest, "RegistrationOrg.Title","RegistrationOrg.Description", errID, errMessage), + baseData: l.getBaseData(r, authRequest, "RegistrationOrg.Title", "RegistrationOrg.Description", errID, errMessage), registerOrgFormData: *formData, } pwPolicy := l.getPasswordComplexityPolicy(r, "0") diff --git a/internal/api/ui/login/renderer.go b/internal/api/ui/login/renderer.go index 185b04e98b..95ea08637f 100644 --- a/internal/api/ui/login/renderer.go +++ b/internal/api/ui/login/renderer.go @@ -325,7 +325,7 @@ func (l *Login) renderInternalError(w http.ResponseWriter, r *http.Request, auth if err != nil { _, msg = l.getErrorMessage(r, err) } - data := l.getBaseData(r, authReq, "Errors.Internal","", "Internal", msg) + data := l.getBaseData(r, authReq, "Errors.Internal", "", "Internal", msg) l.renderer.RenderTemplate(w, r, l.getTranslator(r.Context(), authReq), l.renderer.Templates[tmplError], data, nil) } @@ -342,7 +342,7 @@ func (l *Login) getUserData(r *http.Request, authReq *domain.AuthRequest, titleI func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, titleI18nKey string, descriptionI18nKey string, errType, errMessage string) baseData { translator := l.getTranslator(r.Context(), authReq) - + title := "" if titleI18nKey != "" { title = translator.LocalizeWithoutArgs(titleI18nKey) @@ -350,9 +350,9 @@ func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, titleI description := "" if descriptionI18nKey != "" { - description = translator.LocalizeWithoutArgs(descriptionI18nKey) + description = translator.LocalizeWithoutArgs(descriptionI18nKey) } - + lang, _ := l.renderer.ReqLang(translator, r).Base() baseData := baseData{ errorData: errorData{ @@ -361,7 +361,7 @@ func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, titleI }, Lang: lang.String(), Title: title, - Description: description, + Description: description, Theme: l.getTheme(r), ThemeMode: l.getThemeMode(r), DarkMode: l.isDarkMode(r), @@ -384,7 +384,7 @@ func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, titleI } privacyPolicy = authReq.PrivacyPolicy } else { - labelPolicy, _ := l.query.ActiveLabelPolicyByOrg(r.Context(), baseData.PrivateLabelingOrgID) + labelPolicy, _ := l.query.ActiveLabelPolicyByOrg(r.Context(), baseData.PrivateLabelingOrgID, false) if labelPolicy != nil { baseData.LabelPolicy = labelPolicy.ToDomain() } @@ -549,7 +549,7 @@ func (l *Login) addLoginTranslations(translator *i18n.Translator, customTexts [] func (l *Login) customTexts(ctx context.Context, translator *i18n.Translator, orgID string) { instanceID := authz.GetInstance(ctx).InstanceID() - instanceTexts, err := l.query.CustomTextListByTemplate(ctx, instanceID, domain.LoginCustomText) + instanceTexts, err := l.query.CustomTextListByTemplate(ctx, instanceID, domain.LoginCustomText, false) if err != nil { logging.WithFields("instanceID", instanceID).Warn("unable to load custom texts for instance") return @@ -558,7 +558,7 @@ func (l *Login) customTexts(ctx context.Context, translator *i18n.Translator, or if orgID == "" { return } - orgTexts, err := l.query.CustomTextListByTemplate(ctx, orgID, domain.LoginCustomText) + orgTexts, err := l.query.CustomTextListByTemplate(ctx, orgID, domain.LoginCustomText, false) if err != nil { logging.WithFields("instanceID", instanceID, "org", orgID).Warn("unable to load custom texts for org") return diff --git a/internal/api/ui/login/select_user_handler.go b/internal/api/ui/login/select_user_handler.go index a4eab5ff8e..d1078cbb83 100644 --- a/internal/api/ui/login/select_user_handler.go +++ b/internal/api/ui/login/select_user_handler.go @@ -18,7 +18,7 @@ type userSelectionFormData struct { func (l *Login) renderUserSelection(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, selectionData *domain.SelectUserStep) { translator := l.getTranslator(r.Context(), authReq) - + linking := len(authReq.LinkingUsers) > 0 titleI18nKey := "SelectAccount.Title" @@ -28,7 +28,7 @@ func (l *Login) renderUserSelection(w http.ResponseWriter, r *http.Request, auth descriptionI18nKey = "SelectAccount.DescriptionLinking" } data := userSelectionData{ - baseData: l.getBaseData(r, authReq, titleI18nKey,descriptionI18nKey, "", ""), + baseData: l.getBaseData(r, authReq, titleI18nKey, descriptionI18nKey, "", ""), Users: selectionData.Users, Linking: linking, } diff --git a/internal/api/ui/login/username_change_handler.go b/internal/api/ui/login/username_change_handler.go index 97ca25a597..79affe9705 100644 --- a/internal/api/ui/login/username_change_handler.go +++ b/internal/api/ui/login/username_change_handler.go @@ -21,7 +21,7 @@ func (l *Login) renderChangeUsername(w http.ResponseWriter, r *http.Request, aut errID, errMessage = l.getErrorMessage(r, err) } translator := l.getTranslator(r.Context(), authReq) - data := l.getUserData(r, authReq, "UsernameChange.Title","UsernameChange.Description", errID, errMessage) + data := l.getUserData(r, authReq, "UsernameChange.Title", "UsernameChange.Description", errID, errMessage) l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplChangeUsername], data, nil) } @@ -43,6 +43,6 @@ func (l *Login) handleChangeUsername(w http.ResponseWriter, r *http.Request) { func (l *Login) renderChangeUsernameDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { var errType, errMessage string translator := l.getTranslator(r.Context(), authReq) - data := l.getUserData(r, authReq, "UsernameChangeDone.Title","UsernameChangeDone.Description", errType, errMessage) + data := l.getUserData(r, authReq, "UsernameChangeDone.Title", "UsernameChangeDone.Description", errType, errMessage) l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplChangeUsernameDone], data, nil) } diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index b9ac3da531..e32d150f56 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -57,11 +57,11 @@ type AuthRequestRepo struct { } type labelPolicyProvider interface { - ActiveLabelPolicyByOrg(context.Context, string) (*query.LabelPolicy, error) + ActiveLabelPolicyByOrg(context.Context, string, bool) (*query.LabelPolicy, error) } type privacyPolicyProvider interface { - PrivacyPolicyByOrg(context.Context, bool, string) (*query.PrivacyPolicy, error) + PrivacyPolicyByOrg(context.Context, bool, string, bool) (*query.PrivacyPolicy, error) } type userSessionViewProvider interface { @@ -73,11 +73,11 @@ type userViewProvider interface { } type loginPolicyViewProvider interface { - LoginPolicyByID(context.Context, bool, string) (*query.LoginPolicy, error) + LoginPolicyByID(context.Context, bool, string, bool) (*query.LoginPolicy, error) } type lockoutPolicyViewProvider interface { - LockoutPolicyByOrg(context.Context, bool, string) (*query.LockoutPolicy, error) + LockoutPolicyByOrg(context.Context, bool, string, bool) (*query.LockoutPolicy, error) } type idpProviderViewProvider interface { @@ -85,7 +85,7 @@ type idpProviderViewProvider interface { } type idpUserLinksProvider interface { - IDPUserLinks(ctx context.Context, queries *query.IDPUserLinksSearchQuery) (*query.IDPUserLinks, error) + IDPUserLinks(ctx context.Context, queries *query.IDPUserLinksSearchQuery, withOwnerRemoved bool) (*query.IDPUserLinks, error) } type userEventProvider interface { @@ -102,17 +102,17 @@ type orgViewProvider interface { } type userGrantProvider interface { - ProjectByClientID(context.Context, string) (*query.Project, error) + ProjectByClientID(context.Context, string, bool) (*query.Project, error) UserGrantsByProjectAndUserID(context.Context, string, string) ([]*query.UserGrant, error) } type projectProvider interface { - ProjectByClientID(context.Context, string) (*query.Project, error) + ProjectByClientID(context.Context, string, bool) (*query.Project, error) OrgProjectMappingByIDs(orgID, projectID, instanceID string) (*project_view_model.OrgProjectMapping, error) } type applicationProvider interface { - AppByOIDCClientID(context.Context, string) (*query.App, error) + AppByOIDCClientID(context.Context, string, bool) (*query.App, error) } func (repo *AuthRequestRepo) Health(ctx context.Context) error { @@ -127,7 +127,7 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *dom return nil, err } request.ID = reqID - project, err := repo.ProjectProvider.ProjectByClientID(ctx, request.ApplicationID) + project, err := repo.ProjectProvider.ProjectByClientID(ctx, request.ApplicationID, false) if err != nil { return nil, err } @@ -135,7 +135,7 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *dom if err != nil { return nil, err } - appIDs, err := repo.Query.SearchClientIDs(ctx, &query.AppSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}) + appIDs, err := repo.Query.SearchClientIDs(ctx, &query.AppSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, false) if err != nil { return nil, err } @@ -547,7 +547,7 @@ func (repo *AuthRequestRepo) getAuthRequest(ctx context.Context, id, userAgentID } func (repo *AuthRequestRepo) getLoginPolicyAndIDPProviders(ctx context.Context, orgID string) (*query.LoginPolicy, []*domain.IDPProvider, error) { - policy, err := repo.LoginPolicyViewProvider.LoginPolicyByID(ctx, false, orgID) + policy, err := repo.LoginPolicyViewProvider.LoginPolicyByID(ctx, false, orgID, false) if err != nil { return nil, nil, err } @@ -710,7 +710,7 @@ func (repo *AuthRequestRepo) checkDomainDiscovery(ctx context.Context, request * return false } // and if the login policy allows domain discovery - policy, err := repo.Query.LoginPolicyByID(ctx, true, org.ID) + policy, err := repo.Query.LoginPolicyByID(ctx, true, org.ID, false) if err != nil || !policy.AllowDomainDiscovery { return false } @@ -997,7 +997,7 @@ func checkExternalIDPsOfUser(ctx context.Context, idpUserLinksProvider idpUserLi if err != nil { return nil, err } - return idpUserLinksProvider.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: []query.SearchQuery{userIDQuery}}) + return idpUserLinksProvider.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: []query.SearchQuery{userIDQuery}}, false) } func (repo *AuthRequestRepo) usersForUserSelection(request *domain.AuthRequest) ([]domain.UserSelection, error) { @@ -1113,7 +1113,7 @@ func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView, reques } func (repo *AuthRequestRepo) GetPrivacyPolicy(ctx context.Context, orgID string) (*domain.PrivacyPolicy, error) { - policy, err := repo.PrivacyPolicyProvider.PrivacyPolicyByOrg(ctx, false, orgID) + policy, err := repo.PrivacyPolicyProvider.PrivacyPolicyByOrg(ctx, false, orgID, false) if errors.IsNotFound(err) { return new(domain.PrivacyPolicy), nil } @@ -1141,7 +1141,7 @@ func privacyPolicyToDomain(p *query.PrivacyPolicy) *domain.PrivacyPolicy { } func (repo *AuthRequestRepo) getLockoutPolicy(ctx context.Context, orgID string) (*query.LockoutPolicy, error) { - policy, err := repo.LockoutPolicyViewProvider.LockoutPolicyByOrg(ctx, false, orgID) + policy, err := repo.LockoutPolicyViewProvider.LockoutPolicyByOrg(ctx, false, orgID, false) if err != nil { return nil, err } @@ -1149,7 +1149,7 @@ func (repo *AuthRequestRepo) getLockoutPolicy(ctx context.Context, orgID string) } func (repo *AuthRequestRepo) getLabelPolicy(ctx context.Context, orgID string) (*domain.LabelPolicy, error) { - policy, err := repo.LabelPolicyProvider.ActiveLabelPolicyByOrg(ctx, orgID) + policy, err := repo.LabelPolicyProvider.ActiveLabelPolicyByOrg(ctx, orgID, false) if err != nil { return nil, err } @@ -1187,7 +1187,7 @@ func labelPolicyToDomain(p *query.LabelPolicy) *domain.LabelPolicy { } func (repo *AuthRequestRepo) getLoginTexts(ctx context.Context, aggregateID string) ([]*domain.CustomText, error) { - loginTexts, err := repo.Query.CustomTextListByTemplate(ctx, aggregateID, domain.LoginCustomText) + loginTexts, err := repo.Query.CustomTextListByTemplate(ctx, aggregateID, domain.LoginCustomText, false) if err != nil { return nil, err } @@ -1198,7 +1198,7 @@ func (repo *AuthRequestRepo) hasSucceededPage(ctx context.Context, request *doma if _, ok := request.Request.(*domain.AuthRequestOIDC); !ok { return false, nil } - app, err := provider.AppByOIDCClientID(ctx, request.ApplicationID) + app, err := provider.AppByOIDCClientID(ctx, request.ApplicationID, false) if err != nil { return false, err } @@ -1206,7 +1206,7 @@ func (repo *AuthRequestRepo) hasSucceededPage(ctx context.Context, request *doma } func (repo *AuthRequestRepo) getDomainPolicy(ctx context.Context, orgID string) (*query.DomainPolicy, error) { - return repo.Query.DomainPolicyByOrg(ctx, false, orgID) + return repo.Query.DomainPolicyByOrg(ctx, false, orgID, false) } func setOrgID(ctx context.Context, orgViewProvider orgViewProvider, request *domain.AuthRequest) error { @@ -1420,7 +1420,7 @@ func userGrantRequired(ctx context.Context, request *domain.AuthRequest, user *u var project *query.Project switch request.Request.Type() { case domain.AuthRequestTypeOIDC, domain.AuthRequestTypeSAML: - project, err = userGrantProvider.ProjectByClientID(ctx, request.ApplicationID) + project, err = userGrantProvider.ProjectByClientID(ctx, request.ApplicationID, false) if err != nil { return false, err } @@ -1441,7 +1441,7 @@ func projectRequired(ctx context.Context, request *domain.AuthRequest, projectPr var project *query.Project switch request.Request.Type() { case domain.AuthRequestTypeOIDC, domain.AuthRequestTypeSAML: - project, err = projectProvider.ProjectByClientID(ctx, request.ApplicationID) + project, err = projectProvider.ProjectByClientID(ctx, request.ApplicationID, false) if err != nil { return false, err } diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go index e7b8c51b78..bc6983bfba 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go @@ -132,7 +132,7 @@ type mockLoginPolicy struct { policy *query.LoginPolicy } -func (m *mockLoginPolicy) LoginPolicyByID(ctx context.Context, _ bool, id string) (*query.LoginPolicy, error) { +func (m *mockLoginPolicy) LoginPolicyByID(ctx context.Context, _ bool, id string, _ bool) (*query.LoginPolicy, error) { return m.policy, nil } @@ -140,7 +140,7 @@ type mockLockoutPolicy struct { policy *query.LockoutPolicy } -func (m *mockLockoutPolicy) LockoutPolicyByOrg(context.Context, bool, string) (*query.LockoutPolicy, error) { +func (m *mockLockoutPolicy) LockoutPolicyByOrg(context.Context, bool, string, bool) (*query.LockoutPolicy, error) { return m.policy, nil } @@ -195,7 +195,7 @@ type mockUserGrants struct { userGrants int } -func (m *mockUserGrants) ProjectByClientID(ctx context.Context, s string) (*query.Project, error) { +func (m *mockUserGrants) ProjectByClientID(ctx context.Context, s string, _ bool) (*query.Project, error) { return &query.Project{ProjectRoleCheck: m.roleCheck}, nil } @@ -212,7 +212,7 @@ type mockProject struct { projectCheck bool } -func (m *mockProject) ProjectByClientID(ctx context.Context, s string) (*query.Project, error) { +func (m *mockProject) ProjectByClientID(ctx context.Context, s string, _ bool) (*query.Project, error) { return &query.Project{HasProjectCheck: m.projectCheck}, nil } @@ -227,7 +227,7 @@ type mockApp struct { app *query.App } -func (m *mockApp) AppByOIDCClientID(ctx context.Context, id string) (*query.App, error) { +func (m *mockApp) AppByOIDCClientID(ctx context.Context, id string, _ bool) (*query.App, error) { if m.app != nil { return m.app, nil } @@ -238,7 +238,7 @@ type mockIDPUserLinks struct { idps []*query.IDPUserLink } -func (m *mockIDPUserLinks) IDPUserLinks(ctx context.Context, queries *query.IDPUserLinksSearchQuery) (*query.IDPUserLinks, error) { +func (m *mockIDPUserLinks) IDPUserLinks(ctx context.Context, queries *query.IDPUserLinksSearchQuery, withOwnerRemoved bool) (*query.IDPUserLinks, error) { return &query.IDPUserLinks{Links: m.idps}, nil } diff --git a/internal/auth/repository/eventsourcing/eventstore/org.go b/internal/auth/repository/eventsourcing/eventstore/org.go index b5ed7ee572..d8d19e9ef9 100644 --- a/internal/auth/repository/eventsourcing/eventstore/org.go +++ b/internal/auth/repository/eventsourcing/eventstore/org.go @@ -31,7 +31,7 @@ func (repo *OrgRepository) GetIDPConfigByID(ctx context.Context, idpConfigID str } func (repo *OrgRepository) GetMyPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error) { - policy, err := repo.Query.PasswordComplexityPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID) + policy, err := repo.Query.PasswordComplexityPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID, false) if err != nil { return nil, err } @@ -39,11 +39,11 @@ func (repo *OrgRepository) GetMyPasswordComplexityPolicy(ctx context.Context) (* } func (repo *OrgRepository) GetLoginText(ctx context.Context, orgID string) ([]*domain.CustomText, error) { - loginTexts, err := repo.Query.CustomTextListByTemplate(ctx, authz.GetInstance(ctx).InstanceID(), domain.LoginCustomText) + loginTexts, err := repo.Query.CustomTextListByTemplate(ctx, authz.GetInstance(ctx).InstanceID(), domain.LoginCustomText, false) if err != nil { return nil, err } - orgLoginTexts, err := repo.Query.CustomTextListByTemplate(ctx, orgID, domain.LoginCustomText) + orgLoginTexts, err := repo.Query.CustomTextListByTemplate(ctx, orgID, domain.LoginCustomText, false) 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 c2157f1df2..342daa5e9a 100644 --- a/internal/auth/repository/eventsourcing/handler/idp_config.go +++ b/internal/auth/repository/eventsourcing/handler/idp_config.go @@ -17,7 +17,7 @@ import ( ) const ( - idpConfigTable = "auth.idp_configs" + idpConfigTable = "auth.idp_configs2" ) type IDPConfig struct { @@ -121,6 +121,8 @@ func (i *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve return i.view.DeleteIDPConfig(idp.IDPConfigID, event) case instance.InstanceRemovedEventType: return i.view.DeleteInstanceIDPs(event) + case org.OrgRemovedEventType: + return i.view.UpdateOrgOwnerRemovedIDPs(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 35bec063d4..72b3d06514 100644 --- a/internal/auth/repository/eventsourcing/handler/idp_providers.go +++ b/internal/auth/repository/eventsourcing/handler/idp_providers.go @@ -21,7 +21,7 @@ import ( ) const ( - idpProviderTable = "auth.idp_providers" + idpProviderTable = "auth.idp_providers2" ) type IDPProvider struct { @@ -140,7 +140,9 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) { case org.LoginPolicyRemovedEventType: return i.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event.InstanceID, event) case instance.InstanceRemovedEventType: - return i.view.DeleteInstanceIDPs(event) + return i.view.DeleteInstanceIDPProviders(event) + case org.OrgRemovedEventType: + return i.view.UpdateOrgOwnerRemovedIDPProviders(event) default: return i.view.ProcessedIDPProviderSequence(event) } @@ -194,9 +196,9 @@ func (i *IDPProvider) OnSuccess(instanceIDs []string) error { } func (i *IDPProvider) getOrgIDPConfig(instanceID, aggregateID, idpConfigID string) (*query2.IDP, error) { - return i.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), false, idpConfigID, aggregateID) + return i.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), false, idpConfigID, aggregateID, false) } func (i *IDPProvider) getDefaultIDPConfig(instanceID, idpConfigID string) (*query2.IDP, error) { - return i.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), false, idpConfigID, instanceID) + return i.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), false, idpConfigID, instanceID, false) } diff --git a/internal/auth/repository/eventsourcing/handler/org_project_mapping.go b/internal/auth/repository/eventsourcing/handler/org_project_mapping.go index 7236c8a115..ffa7688866 100644 --- a/internal/auth/repository/eventsourcing/handler/org_project_mapping.go +++ b/internal/auth/repository/eventsourcing/handler/org_project_mapping.go @@ -12,11 +12,12 @@ import ( "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/org" "github.com/zitadel/zitadel/internal/repository/project" ) const ( - orgProjectMappingTable = "auth.org_project_mapping" + orgProjectMappingTable = "auth.org_project_mapping2" ) type OrgProjectMapping struct { @@ -108,6 +109,8 @@ func (p *OrgProjectMapping) Reduce(event *es_models.Event) (err error) { } case instance.InstanceRemovedEventType: return p.view.DeleteInstanceOrgProjectMappings(event) + case org.OrgRemovedEventType: + return p.view.UpdateOwnerRemovedOrgProjectMappings(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 99499f73b6..29e228caea 100644 --- a/internal/auth/repository/eventsourcing/handler/refresh_token.go +++ b/internal/auth/repository/eventsourcing/handler/refresh_token.go @@ -13,6 +13,7 @@ import ( "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/org" "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" @@ -114,6 +115,8 @@ func (t *RefreshToken) Reduce(event *es_models.Event) (err error) { return t.view.DeleteUserRefreshTokens(event.AggregateID, event.InstanceID, event) case instance.InstanceRemovedEventType: return t.view.DeleteInstanceRefreshTokens(event) + case org.OrgRemovedEventType: + return t.view.DeleteOrgRefreshTokens(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 22c531ccb4..280c85b6b4 100644 --- a/internal/auth/repository/eventsourcing/handler/token.go +++ b/internal/auth/repository/eventsourcing/handler/token.go @@ -17,6 +17,7 @@ import ( 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/org" "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/user" user_repo "github.com/zitadel/zitadel/internal/repository/user" @@ -151,6 +152,11 @@ func (t *Token) Reduce(event *es_models.Event) (err error) { return t.view.DeleteApplicationTokens(event, applicationsIDs...) case instance.InstanceRemovedEventType: return t.view.DeleteInstanceTokens(event) + case org.OrgRemovedEventType: + // deletes all tokens including PATs, which is expected for now + // if there is an undo of the org deletion in the future, + // we will need to have a look on how to handle the deleted PATs + return t.view.DeleteOrgTokens(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 34130219be..f61e24da6e 100644 --- a/internal/auth/repository/eventsourcing/handler/user.go +++ b/internal/auth/repository/eventsourcing/handler/user.go @@ -24,7 +24,7 @@ import ( ) const ( - userTable = "auth.users" + userTable = "auth.users2" ) type User struct { @@ -228,6 +228,8 @@ func (u *User) ProcessOrg(event *es_models.Event) (err error) { return u.fillLoginNamesOnOrgUsers(event) case org.OrgDomainPrimarySetEventType: return u.fillPreferredLoginNamesOnOrgUsers(event) + case org.OrgRemovedEventType: + return u.view.UpdateOrgOwnerRemovedUsers(event) default: return u.view.ProcessedUserSequence(event) } diff --git a/internal/auth/repository/eventsourcing/handler/user_external_idps.go b/internal/auth/repository/eventsourcing/handler/user_external_idps.go index 08e5a5ccef..4733cca4a8 100644 --- a/internal/auth/repository/eventsourcing/handler/user_external_idps.go +++ b/internal/auth/repository/eventsourcing/handler/user_external_idps.go @@ -22,7 +22,7 @@ import ( ) const ( - externalIDPTable = "auth.user_external_idps" + externalIDPTable = "auth.user_external_idps2" ) type ExternalIDP struct { @@ -153,6 +153,8 @@ func (i *ExternalIDP) processIdpConfig(event *es_models.Event) (err error) { return i.view.PutExternalIDPs(event, exterinalIDPs...) case instance.InstanceRemovedEventType: return i.view.DeleteInstanceExternalIDPs(event) + case org.OrgRemovedEventType: + return i.view.UpdateOrgOwnerRemovedExternalIDPs(event) default: return i.view.ProcessedExternalIDPSequence(event) } @@ -184,9 +186,9 @@ func (i *ExternalIDP) OnSuccess(instanceIDs []string) error { } func (i *ExternalIDP) getOrgIDPConfig(instanceID, aggregateID, idpConfigID string) (*query2.IDP, error) { - return i.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), false, idpConfigID, aggregateID) + return i.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), false, idpConfigID, aggregateID, false) } func (i *ExternalIDP) getDefaultIDPConfig(instanceID, idpConfigID string) (*query2.IDP, error) { - return i.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), false, idpConfigID, instanceID) + return i.queries.IDPByIDAndResourceOwner(withInstanceID(context.Background(), instanceID), false, idpConfigID, instanceID, false) } diff --git a/internal/auth/repository/eventsourcing/handler/user_session.go b/internal/auth/repository/eventsourcing/handler/user_session.go index f04105cbc0..a4bda6a59a 100644 --- a/internal/auth/repository/eventsourcing/handler/user_session.go +++ b/internal/auth/repository/eventsourcing/handler/user_session.go @@ -156,6 +156,8 @@ func (u *UserSession) Reduce(event *models.Event) (err error) { return u.view.DeleteUserSessions(event.AggregateID, event.InstanceID, event) case instance.InstanceRemovedEventType: return u.view.DeleteInstanceUserSessions(event) + case org.OrgRemovedEventType: + return u.view.DeleteOrgUserSessions(event) default: return u.view.ProcessedUserSessionSequence(event) } diff --git a/internal/auth/repository/eventsourcing/repository.go b/internal/auth/repository/eventsourcing/repository.go index a523108622..531c03248d 100644 --- a/internal/auth/repository/eventsourcing/repository.go +++ b/internal/auth/repository/eventsourcing/repository.go @@ -127,7 +127,7 @@ func (q queryViewWrapper) UserGrantsByProjectAndUserID(ctx context.Context, proj return nil, err } queries := &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantUserID, userGrantProjectID}} - grants, err := q.Queries.UserGrants(ctx, queries) + grants, err := q.Queries.UserGrants(ctx, queries, false) if err != nil { return nil, err } diff --git a/internal/auth/repository/eventsourcing/view/external_idps.go b/internal/auth/repository/eventsourcing/view/external_idps.go index 103666e69d..3379b70ae4 100644 --- a/internal/auth/repository/eventsourcing/view/external_idps.go +++ b/internal/auth/repository/eventsourcing/view/external_idps.go @@ -9,7 +9,7 @@ import ( ) const ( - externalIDPTable = "auth.user_external_idps" + externalIDPTable = "auth.user_external_idps2" ) func (v *View) ExternalIDPByExternalUserIDAndIDPConfigID(externalUserID, idpConfigID, instanceID string) (*model.ExternalIDPView, error) { @@ -64,6 +64,14 @@ func (v *View) DeleteInstanceExternalIDPs(event *models.Event) error { return v.ProcessedExternalIDPSequence(event) } +func (v *View) UpdateOrgOwnerRemovedExternalIDPs(event *models.Event) error { + err := view.UpdateOrgOwnerRemovedExternalIDPs(v.Db, externalIDPTable, event.InstanceID, event.ResourceOwner) + 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 8b55d0b040..439b637112 100644 --- a/internal/auth/repository/eventsourcing/view/idp_configs.go +++ b/internal/auth/repository/eventsourcing/view/idp_configs.go @@ -10,7 +10,7 @@ import ( ) const ( - idpConfigTable = "auth.idp_configs" + idpConfigTable = "auth.idp_configs2" ) func (v *View) IDPConfigByID(idpID, instanceID string) (*iam_es_model.IDPConfigView, error) { @@ -49,6 +49,14 @@ func (v *View) DeleteInstanceIDPs(event *models.Event) error { return v.ProcessedIDPConfigSequence(event) } +func (v *View) UpdateOrgOwnerRemovedIDPs(event *models.Event) error { + err := view.UpdateOrgOwnerRemovedIDPs(v.Db, idpConfigTable, event.InstanceID, event.AggregateID) + 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 7b3fbe83ae..ead8f7c0a0 100644 --- a/internal/auth/repository/eventsourcing/view/idp_providers.go +++ b/internal/auth/repository/eventsourcing/view/idp_providers.go @@ -10,7 +10,7 @@ import ( ) const ( - idpProviderTable = "auth.idp_providers" + idpProviderTable = "auth.idp_providers2" ) func (v *View) IDPProviderByAggregateAndIDPConfigID(aggregateID, idpConfigID, instanceID string) (*model.IDPProviderView, error) { @@ -69,6 +69,14 @@ func (v *View) DeleteInstanceIDPProviders(event *models.Event) error { return v.ProcessedIDPProviderSequence(event) } +func (v *View) UpdateOrgOwnerRemovedIDPProviders(event *models.Event) error { + err := view.UpdateOrgOwnerRemovedIDPProviders(v.Db, idpProviderTable, event.InstanceID, event.AggregateID) + 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 4ccac5dccd..9cd3f20899 100644 --- a/internal/auth/repository/eventsourcing/view/org_project_mapping.go +++ b/internal/auth/repository/eventsourcing/view/org_project_mapping.go @@ -9,15 +9,15 @@ import ( ) const ( - orgPrgojectMappingTable = "auth.org_project_mapping" + orgProjectMappingTable = "auth.org_project_mapping2" ) func (v *View) OrgProjectMappingByIDs(orgID, projectID, instanceID string) (*model.OrgProjectMapping, error) { - return view.OrgProjectMappingByIDs(v.Db, orgPrgojectMappingTable, orgID, projectID, instanceID) + return view.OrgProjectMappingByIDs(v.Db, orgProjectMappingTable, orgID, projectID, instanceID) } func (v *View) PutOrgProjectMapping(mapping *model.OrgProjectMapping, event *models.Event) error { - err := view.PutOrgProjectMapping(v.Db, orgPrgojectMappingTable, mapping) + err := view.PutOrgProjectMapping(v.Db, orgProjectMappingTable, mapping) if err != nil { return err } @@ -25,7 +25,7 @@ func (v *View) PutOrgProjectMapping(mapping *model.OrgProjectMapping, event *mod } func (v *View) DeleteOrgProjectMapping(orgID, projectID, instanceID string, event *models.Event) error { - err := view.DeleteOrgProjectMapping(v.Db, orgPrgojectMappingTable, orgID, projectID, instanceID) + err := view.DeleteOrgProjectMapping(v.Db, orgProjectMappingTable, orgID, projectID, instanceID) if err != nil && !errors.IsNotFound(err) { return err } @@ -33,7 +33,15 @@ func (v *View) DeleteOrgProjectMapping(orgID, projectID, instanceID string, even } func (v *View) DeleteInstanceOrgProjectMappings(event *models.Event) error { - err := view.DeleteInstanceOrgProjectMappings(v.Db, orgPrgojectMappingTable, event.InstanceID) + err := view.DeleteInstanceOrgProjectMappings(v.Db, orgProjectMappingTable, event.InstanceID) + if err != nil && !errors.IsNotFound(err) { + return err + } + return v.ProcessedOrgProjectMappingSequence(event) +} + +func (v *View) UpdateOwnerRemovedOrgProjectMappings(event *models.Event) error { + err := view.UpdateOwnerRemovedOrgProjectMappings(v.Db, orgProjectMappingTable, event.InstanceID, event.AggregateID) if err != nil && !errors.IsNotFound(err) { return err } @@ -41,31 +49,31 @@ func (v *View) DeleteInstanceOrgProjectMappings(event *models.Event) error { } func (v *View) DeleteOrgProjectMappingsByProjectID(projectID, instanceID string) error { - return view.DeleteOrgProjectMappingsByProjectID(v.Db, orgPrgojectMappingTable, projectID, instanceID) + return view.DeleteOrgProjectMappingsByProjectID(v.Db, orgProjectMappingTable, projectID, instanceID) } func (v *View) DeleteOrgProjectMappingsByProjectGrantID(projectGrantID, instanceID string) error { - return view.DeleteOrgProjectMappingsByProjectGrantID(v.Db, orgPrgojectMappingTable, projectGrantID, instanceID) + return view.DeleteOrgProjectMappingsByProjectGrantID(v.Db, orgProjectMappingTable, projectGrantID, instanceID) } func (v *View) GetLatestOrgProjectMappingSequence(instanceID string) (*repository.CurrentSequence, error) { - return v.latestSequence(orgPrgojectMappingTable, instanceID) + return v.latestSequence(orgProjectMappingTable, instanceID) } func (v *View) GetLatestOrgProjectMappingSequences(instanceIDs []string) ([]*repository.CurrentSequence, error) { - return v.latestSequences(orgPrgojectMappingTable, instanceIDs) + return v.latestSequences(orgProjectMappingTable, instanceIDs) } func (v *View) ProcessedOrgProjectMappingSequence(event *models.Event) error { - return v.saveCurrentSequence(orgPrgojectMappingTable, event) + return v.saveCurrentSequence(orgProjectMappingTable, event) } func (v *View) UpdateOrgProjectMappingSpoolerRunTimestamp(instanceIDs []string) error { - return v.updateSpoolerRunSequence(orgPrgojectMappingTable, instanceIDs) + return v.updateSpoolerRunSequence(orgProjectMappingTable, instanceIDs) } func (v *View) GetLatestOrgProjectMappingFailedEvent(sequence uint64, instanceID string) (*repository.FailedEvent, error) { - return v.latestFailedEvent(orgPrgojectMappingTable, instanceID, sequence) + return v.latestFailedEvent(orgProjectMappingTable, instanceID, sequence) } func (v *View) ProcessedOrgProjectMappingFailedEvent(failedEvent *repository.FailedEvent) error { diff --git a/internal/auth/repository/eventsourcing/view/refresh_token.go b/internal/auth/repository/eventsourcing/view/refresh_token.go index 5f7bd50401..e63fa0ec0e 100644 --- a/internal/auth/repository/eventsourcing/view/refresh_token.go +++ b/internal/auth/repository/eventsourcing/view/refresh_token.go @@ -73,6 +73,14 @@ func (v *View) DeleteInstanceRefreshTokens(event *models.Event) error { return v.ProcessedRefreshTokenSequence(event) } +func (v *View) DeleteOrgRefreshTokens(event *models.Event) error { + err := usr_view.DeleteOrgRefreshTokens(v.Db, refreshTokenTable, event.InstanceID, event.ResourceOwner) + 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 dfc05a51a1..132c3ecd94 100644 --- a/internal/auth/repository/eventsourcing/view/token.go +++ b/internal/auth/repository/eventsourcing/view/token.go @@ -84,6 +84,14 @@ func (v *View) DeleteInstanceTokens(event *models.Event) error { return v.ProcessedTokenSequence(event) } +func (v *View) DeleteOrgTokens(event *models.Event) error { + err := usr_view.DeleteOrgTokens(v.Db, tokenTable, event.InstanceID, event.ResourceOwner) + 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 8ff62f5579..a38ec94532 100644 --- a/internal/auth/repository/eventsourcing/view/user.go +++ b/internal/auth/repository/eventsourcing/view/user.go @@ -14,7 +14,7 @@ import ( ) const ( - userTable = "auth.users" + userTable = "auth.users2" ) func (v *View) UserByID(userID, instanceID string) (*model.UserView, error) { @@ -97,7 +97,7 @@ func (v *View) UserByPhoneAndResourceOwner(phone, resourceOwner, instanceID stri func (v *View) userByID(instanceID string, queries ...query.SearchQuery) (*model.UserView, error) { ctx := authz.WithInstanceID(context.Background(), instanceID) - queriedUser, err := v.query.GetNotifyUser(ctx, true, queries...) + queriedUser, err := v.query.GetNotifyUser(ctx, true, false, queries...) if err != nil { return nil, err } @@ -189,6 +189,14 @@ func (v *View) DeleteInstanceUsers(event *models.Event) error { return v.ProcessedUserSequence(event) } +func (v *View) UpdateOrgOwnerRemovedUsers(event *models.Event) error { + err := view.UpdateOrgOwnerRemovedUsers(v.Db, userTable, event.InstanceID, event.AggregateID) + 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 8a8d71bf03..52ac559384 100644 --- a/internal/auth/repository/eventsourcing/view/user_session.go +++ b/internal/auth/repository/eventsourcing/view/user_session.go @@ -64,6 +64,14 @@ func (v *View) DeleteInstanceUserSessions(event *models.Event) error { return v.ProcessedUserSessionSequence(event) } +func (v *View) DeleteOrgUserSessions(event *models.Event) error { + err := view.DeleteOrgUserSessions(v.Db, userSessionTable, event.InstanceID, event.ResourceOwner) + 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/authz/repository/eventsourcing/eventstore/user_membership.go b/internal/authz/repository/eventsourcing/eventstore/user_membership.go index 6239730e74..b7e95b603a 100644 --- a/internal/authz/repository/eventsourcing/eventstore/user_membership.go +++ b/internal/authz/repository/eventsourcing/eventstore/user_membership.go @@ -40,7 +40,7 @@ func (repo *UserMembershipRepo) searchUserMemberships(ctx context.Context) (_ [] } memberships, err := repo.Queries.Memberships(ctx, &query.MembershipSearchQuery{ Queries: []query.SearchQuery{userIDQuery, query.Or(orgIDsQuery, grantedIDQuery)}, - }) + }, false) if err != nil { return nil, err } diff --git a/internal/authz/repository/eventsourcing/view/application.go b/internal/authz/repository/eventsourcing/view/application.go index 424b108841..22170d8ba8 100644 --- a/internal/authz/repository/eventsourcing/view/application.go +++ b/internal/authz/repository/eventsourcing/view/application.go @@ -9,7 +9,7 @@ import ( ) func (v *View) ApplicationByOIDCClientID(ctx context.Context, clientID string) (*query.App, error) { - return v.Query.AppByOIDCClientID(ctx, clientID) + return v.Query.AppByOIDCClientID(ctx, clientID, false) } func (v *View) ApplicationByProjecIDAndAppName(ctx context.Context, projectID, appName string) (_ *query.App, err error) { @@ -32,7 +32,7 @@ func (v *View) ApplicationByProjecIDAndAppName(ctx context.Context, projectID, a }, } - apps, err := v.Query.SearchApps(ctx, queries) + apps, err := v.Query.SearchApps(ctx, queries, false) if err != nil { return nil, err } diff --git a/internal/command/custom_login_text_model.go b/internal/command/custom_login_text_model.go index 9f4f0b9ed3..75d2224c45 100644 --- a/internal/command/custom_login_text_model.go +++ b/internal/command/custom_login_text_model.go @@ -21,9 +21,7 @@ func (wm *CustomLoginTextsReadModel) Reduce() error { case *policy.CustomTextSetEvent: wm.CustomLoginTexts[e.Template+e.Language.String()] = &CustomText{Language: e.Language, Template: e.Template} case *policy.CustomTextTemplateRemovedEvent: - if _, ok := wm.CustomLoginTexts[e.Template+e.Language.String()]; ok { - delete(wm.CustomLoginTexts, e.Template+e.Language.String()) - } + delete(wm.CustomLoginTexts, e.Template+e.Language.String()) } } return wm.WriteModel.Reduce() diff --git a/internal/command/custom_message_text_model.go b/internal/command/custom_message_text_model.go index 50695de52d..e3a3211faf 100644 --- a/internal/command/custom_message_text_model.go +++ b/internal/command/custom_message_text_model.go @@ -168,9 +168,7 @@ func (wm *CustomMessageTemplatesReadModel) Reduce() error { wm.CustomMessageTemplate[e.Template+e.Language.String()].FooterText = "" } case *policy.CustomTextTemplateRemovedEvent: - if _, ok := wm.CustomMessageTemplate[e.Template+e.Language.String()]; ok { - delete(wm.CustomMessageTemplate, e.Template+e.Language.String()) - } + delete(wm.CustomMessageTemplate, e.Template+e.Language.String()) } } return wm.WriteModel.Reduce() diff --git a/internal/command/instance.go b/internal/command/instance.go index 75a51fc075..b856fd3495 100644 --- a/internal/command/instance.go +++ b/internal/command/instance.go @@ -397,11 +397,7 @@ func (c *Commands) UpdateInstance(ctx context.Context, name string) (*domain.Obj if err != nil { return nil, err } - return &domain.ObjectDetails{ - Sequence: events[len(events)-1].Sequence(), - EventDate: events[len(events)-1].CreationDate(), - ResourceOwner: events[len(events)-1].Aggregate().ResourceOwner, - }, nil + return pushedEventsToObjectDetails(events), nil } func (c *Commands) SetDefaultLanguage(ctx context.Context, defaultLanguage language.Tag) (*domain.ObjectDetails, error) { @@ -415,11 +411,7 @@ func (c *Commands) SetDefaultLanguage(ctx context.Context, defaultLanguage langu if err != nil { return nil, err } - return &domain.ObjectDetails{ - Sequence: events[len(events)-1].Sequence(), - EventDate: events[len(events)-1].CreationDate(), - ResourceOwner: events[len(events)-1].Aggregate().ResourceOwner, - }, nil + return pushedEventsToObjectDetails(events), nil } func (c *Commands) SetDefaultOrg(ctx context.Context, orgID string) (*domain.ObjectDetails, error) { @@ -433,11 +425,7 @@ func (c *Commands) SetDefaultOrg(ctx context.Context, orgID string) (*domain.Obj if err != nil { return nil, err } - return &domain.ObjectDetails{ - Sequence: events[len(events)-1].Sequence(), - EventDate: events[len(events)-1].CreationDate(), - ResourceOwner: events[len(events)-1].Aggregate().ResourceOwner, - }, nil + return pushedEventsToObjectDetails(events), nil } func (c *Commands) ChangeSystemConfig(ctx context.Context, externalDomain string, externalPort uint16, externalSecure bool) error { diff --git a/internal/command/instance_custom_login_text.go b/internal/command/instance_custom_login_text.go index 44764b0638..9c99963b4b 100644 --- a/internal/command/instance_custom_login_text.go +++ b/internal/command/instance_custom_login_text.go @@ -42,6 +42,9 @@ func (c *Commands) RemoveCustomInstanceLoginTexts(ctx context.Context, lang lang } iamAgg := InstanceAggregateFromWriteModel(&customText.WriteModel) pushedEvents, err := c.eventstore.Push(ctx, instance.NewCustomTextTemplateRemovedEvent(ctx, iamAgg, domain.LoginCustomText, lang)) + if err != nil { + return nil, err + } err = AppendAndReduce(customText, pushedEvents...) if err != nil { return nil, err diff --git a/internal/command/instance_member.go b/internal/command/instance_member.go index 700315d72c..e7d70f8dce 100644 --- a/internal/command/instance_member.go +++ b/internal/command/instance_member.go @@ -8,7 +8,6 @@ import ( "github.com/zitadel/zitadel/internal/command/preparation" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" - caos_errs "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/telemetry/tracing" @@ -20,7 +19,7 @@ func (c *Commands) AddInstanceMemberCommand(a *instance.Aggregate, userID string return nil, errors.ThrowInvalidArgument(nil, "INSTA-SDSfs", "Errors.Invalid.Argument") } if len(domain.CheckForInvalidRoles(roles, domain.IAMRolePrefix, c.zitadelRoles)) > 0 { - return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-4m0fS", "Errors.IAM.MemberInvalid") + return nil, errors.ThrowInvalidArgument(nil, "INSTANCE-4m0fS", "Errors.IAM.MemberInvalid") } return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { if exists, err := ExistsUser(ctx, filter, userID, ""); err != nil || !exists { @@ -88,13 +87,13 @@ func (c *Commands) AddInstanceMember(ctx context.Context, userID string, roles . return memberWriteModelToMember(&addedMember.MemberWriteModel), nil } -//ChangeInstanceMember updates an existing member +// ChangeInstanceMember updates an existing member func (c *Commands) ChangeInstanceMember(ctx context.Context, member *domain.Member) (*domain.Member, error) { if !member.IsIAMValid() { - return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-LiaZi", "Errors.IAM.MemberInvalid") + return nil, errors.ThrowInvalidArgument(nil, "INSTANCE-LiaZi", "Errors.IAM.MemberInvalid") } if len(domain.CheckForInvalidRoles(member.Roles, domain.IAMRolePrefix, c.zitadelRoles)) > 0 { - return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-3m9fs", "Errors.IAM.MemberInvalid") + return nil, errors.ThrowInvalidArgument(nil, "INSTANCE-3m9fs", "Errors.IAM.MemberInvalid") } existingMember, err := c.instanceMemberWriteModelByID(ctx, member.UserID) @@ -103,7 +102,7 @@ func (c *Commands) ChangeInstanceMember(ctx context.Context, member *domain.Memb } if reflect.DeepEqual(existingMember.Roles, member.Roles) { - return nil, caos_errs.ThrowPreconditionFailed(nil, "INSTANCE-LiaZi", "Errors.IAM.Member.RolesNotChanged") + return nil, errors.ThrowPreconditionFailed(nil, "INSTANCE-LiaZi", "Errors.IAM.Member.RolesNotChanged") } instanceAgg := InstanceAggregateFromWriteModel(&existingMember.MemberWriteModel.WriteModel) pushedEvents, err := c.eventstore.Push(ctx, instance.NewMemberChangedEvent(ctx, instanceAgg, member.UserID, member.Roles...)) @@ -120,7 +119,7 @@ func (c *Commands) ChangeInstanceMember(ctx context.Context, member *domain.Memb func (c *Commands) RemoveInstanceMember(ctx context.Context, userID string) (*domain.ObjectDetails, error) { if userID == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-LiaZi", "Errors.IDMissing") + return nil, errors.ThrowInvalidArgument(nil, "INSTANCE-LiaZi", "Errors.IDMissing") } memberWriteModel, err := c.instanceMemberWriteModelByID(ctx, userID) if err != nil && !errors.IsNotFound(err) { diff --git a/internal/command/instance_settings.go b/internal/command/instance_settings.go index 3f95f91a0f..3105f58dcc 100644 --- a/internal/command/instance_settings.go +++ b/internal/command/instance_settings.go @@ -8,7 +8,6 @@ import ( "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" - caos_errs "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/instance" ) @@ -73,7 +72,7 @@ func prepareAddSecretGeneratorConfig(a *instance.Aggregate, typ domain.SecretGen func (c *Commands) ChangeSecretGeneratorConfig(ctx context.Context, generatorType domain.SecretGeneratorType, config *crypto.GeneratorConfig) (*domain.ObjectDetails, error) { if generatorType == domain.SecretGeneratorTypeUnspecified { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-33k9f", "Errors.SecretGenerator.TypeMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-33k9f", "Errors.SecretGenerator.TypeMissing") } generatorWriteModel, err := c.getSecretConfig(ctx, generatorType) @@ -81,7 +80,7 @@ func (c *Commands) ChangeSecretGeneratorConfig(ctx context.Context, generatorTyp return nil, err } if generatorWriteModel.State == domain.SecretGeneratorStateUnspecified || generatorWriteModel.State == domain.SecretGeneratorStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3n9ls", "Errors.SecretGenerator.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-3n9ls", "Errors.SecretGenerator.NotFound") } instanceAgg := InstanceAggregateFromWriteModel(&generatorWriteModel.WriteModel) @@ -99,7 +98,7 @@ func (c *Commands) ChangeSecretGeneratorConfig(ctx context.Context, generatorTyp return nil, err } if !hasChanged { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-m0o3f", "Errors.NoChangesFound") + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-m0o3f", "Errors.NoChangesFound") } pushedEvents, err := c.eventstore.Push(ctx, changedEvent) if err != nil { @@ -114,7 +113,7 @@ func (c *Commands) ChangeSecretGeneratorConfig(ctx context.Context, generatorTyp func (c *Commands) RemoveSecretGeneratorConfig(ctx context.Context, generatorType domain.SecretGeneratorType) (*domain.ObjectDetails, error) { if generatorType == domain.SecretGeneratorTypeUnspecified { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-2j9lw", "Errors.SecretGenerator.TypeMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-2j9lw", "Errors.SecretGenerator.TypeMissing") } generatorWriteModel, err := c.getSecretConfig(ctx, generatorType) @@ -122,7 +121,7 @@ func (c *Commands) RemoveSecretGeneratorConfig(ctx context.Context, generatorTyp return nil, err } if generatorWriteModel.State == domain.SecretGeneratorStateUnspecified || generatorWriteModel.State == domain.SecretGeneratorStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-b8les", "Errors.SecretGenerator.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-b8les", "Errors.SecretGenerator.NotFound") } instanceAgg := InstanceAggregateFromWriteModel(&generatorWriteModel.WriteModel) pushedEvents, err := c.eventstore.Push(ctx, instance.NewSecretGeneratorRemovedEvent(ctx, instanceAgg, generatorType)) diff --git a/internal/command/org.go b/internal/command/org.go index d0bdc49352..3f8f99a807 100644 --- a/internal/command/org.go +++ b/internal/command/org.go @@ -8,9 +8,9 @@ import ( "github.com/zitadel/zitadel/internal/command/preparation" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" - caos_errs "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/org" + "github.com/zitadel/zitadel/internal/repository/project" user_repo "github.com/zitadel/zitadel/internal/repository/user" ) @@ -105,8 +105,8 @@ func (c *Commands) getOrg(ctx context.Context, orgID string) (*domain.Org, error if err != nil { return nil, err } - if writeModel.State == domain.OrgStateUnspecified || writeModel.State == domain.OrgStateRemoved { - return nil, caos_errs.ThrowInternal(err, "COMMAND-4M9sf", "Errors.Org.NotFound") + if !isOrgStateExists(writeModel.State) { + return nil, errors.ThrowInternal(err, "COMMAND-4M9sf", "Errors.Org.NotFound") } return orgWriteModelToOrg(writeModel), nil } @@ -116,8 +116,8 @@ func (c *Commands) checkOrgExists(ctx context.Context, orgID string) error { if err != nil { return err } - if orgWriteModel.State == domain.OrgStateUnspecified || orgWriteModel.State == domain.OrgStateRemoved { - return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-QXPGs", "Errors.Org.NotFound") + if !isOrgStateExists(orgWriteModel.State) { + return errors.ThrowPreconditionFailed(nil, "COMMAND-QXPGs", "Errors.Org.NotFound") } return nil } @@ -128,7 +128,7 @@ func (c *Commands) AddOrgWithID(ctx context.Context, name, userID, resourceOwner return nil, err } if existingOrg.State != domain.OrgStateUnspecified { - return nil, caos_errs.ThrowNotFound(nil, "ORG-lapo2m", "Errors.Org.AlreadyExisting") + return nil, errors.ThrowNotFound(nil, "ORG-lapo2m", "Errors.Org.AlreadyExisting") } return c.addOrgWithIDAndMember(ctx, name, userID, resourceOwner, orgID, claimedUserIDs) @@ -136,12 +136,12 @@ func (c *Commands) AddOrgWithID(ctx context.Context, name, userID, resourceOwner func (c *Commands) AddOrg(ctx context.Context, name, userID, resourceOwner string, claimedUserIDs []string) (*domain.Org, error) { if name = strings.TrimSpace(name); name == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "EVENT-Mf9sd", "Errors.Org.Invalid") + return nil, errors.ThrowInvalidArgument(nil, "EVENT-Mf9sd", "Errors.Org.Invalid") } orgID, err := c.idGenerator.Next() if err != nil { - return nil, caos_errs.ThrowInternal(err, "COMMA-OwciI", "Errors.Internal") + return nil, errors.ThrowInternal(err, "COMMA-OwciI", "Errors.Internal") } return c.addOrgWithIDAndMember(ctx, name, userID, resourceOwner, orgID, claimedUserIDs) @@ -176,18 +176,18 @@ func (c *Commands) addOrgWithIDAndMember(ctx context.Context, name, userID, reso func (c *Commands) ChangeOrg(ctx context.Context, orgID, name string) (*domain.ObjectDetails, error) { name = strings.TrimSpace(name) if orgID == "" || name == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "EVENT-Mf9sd", "Errors.Org.Invalid") + return nil, errors.ThrowInvalidArgument(nil, "EVENT-Mf9sd", "Errors.Org.Invalid") } orgWriteModel, err := c.getOrgWriteModelByID(ctx, orgID) if err != nil { return nil, err } - if orgWriteModel.State == domain.OrgStateUnspecified || orgWriteModel.State == domain.OrgStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "ORG-1MRds", "Errors.Org.NotFound") + if !isOrgStateExists(orgWriteModel.State) { + return nil, errors.ThrowNotFound(nil, "ORG-1MRds", "Errors.Org.NotFound") } if orgWriteModel.Name == name { - return nil, caos_errs.ThrowPreconditionFailed(nil, "ORG-4VSdf", "Errors.Org.NotChanged") + return nil, errors.ThrowPreconditionFailed(nil, "ORG-4VSdf", "Errors.Org.NotChanged") } orgAgg := OrgAggregateFromWriteModel(&orgWriteModel.WriteModel) events := make([]eventstore.Command, 0) @@ -215,11 +215,11 @@ func (c *Commands) DeactivateOrg(ctx context.Context, orgID string) (*domain.Obj if err != nil { return nil, err } - if orgWriteModel.State == domain.OrgStateUnspecified || orgWriteModel.State == domain.OrgStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "ORG-oL9nT", "Errors.Org.NotFound") + if !isOrgStateExists(orgWriteModel.State) { + return nil, errors.ThrowNotFound(nil, "ORG-oL9nT", "Errors.Org.NotFound") } if orgWriteModel.State == domain.OrgStateInactive { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Dbs2g", "Errors.Org.AlreadyDeactivated") + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Dbs2g", "Errors.Org.AlreadyDeactivated") } orgAgg := OrgAggregateFromWriteModel(&orgWriteModel.WriteModel) pushedEvents, err := c.eventstore.Push(ctx, org.NewOrgDeactivatedEvent(ctx, orgAgg)) @@ -238,11 +238,11 @@ func (c *Commands) ReactivateOrg(ctx context.Context, orgID string) (*domain.Obj if err != nil { return nil, err } - if orgWriteModel.State == domain.OrgStateUnspecified || orgWriteModel.State == domain.OrgStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "ORG-Dgf3g", "Errors.Org.NotFound") + if !isOrgStateExists(orgWriteModel.State) { + return nil, errors.ThrowNotFound(nil, "ORG-Dgf3g", "Errors.Org.NotFound") } if orgWriteModel.State == domain.OrgStateActive { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-bfnrh", "Errors.Org.AlreadyActive") + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-bfnrh", "Errors.Org.AlreadyActive") } orgAgg := OrgAggregateFromWriteModel(&orgWriteModel.WriteModel) pushedEvents, err := c.eventstore.Push(ctx, org.NewOrgReactivatedEvent(ctx, orgAgg)) @@ -256,8 +256,251 @@ func (c *Commands) ReactivateOrg(ctx context.Context, orgID string) (*domain.Obj return writeModelToObjectDetails(&orgWriteModel.WriteModel), nil } +func (c *Commands) RemoveOrg(ctx context.Context, id string) (*domain.ObjectDetails, error) { + orgAgg := org.NewAggregate(id) + + cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareRemoveOrg(orgAgg)) + if err != nil { + return nil, err + } + + events, err := c.eventstore.Push(ctx, cmds...) + if err != nil { + return nil, err + } + + return &domain.ObjectDetails{ + Sequence: events[len(events)-1].Sequence(), + EventDate: events[len(events)-1].CreationDate(), + ResourceOwner: events[len(events)-1].Aggregate().InstanceID, + }, nil +} + +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) { + writeModel, err := c.getOrgWriteModelByID(ctx, a.ID) + if err != nil { + return nil, errors.ThrowPreconditionFailed(err, "COMMA-wG9p1", "Errors.Org.NotFound") + } + if !isOrgStateExists(writeModel.State) { + return nil, errors.ThrowNotFound(nil, "COMMA-aps2n", "Errors.Org.NotFound") + } + + domainPolicy, err := c.getOrgDomainPolicy(ctx, a.ID) + if err != nil { + return nil, err + } + usernames, err := OrgUsers(ctx, filter, a.ID) + if err != nil { + return nil, err + } + domains, err := OrgDomains(ctx, filter, a.ID) + if err != nil { + return nil, err + } + links, err := OrgUserIDPLinks(ctx, filter, a.ID) + if err != nil { + return nil, err + } + entityIds, err := OrgSamlEntityIDs(ctx, filter, a.ID) + if err != nil { + return nil, err + } + return []eventstore.Command{org.NewOrgRemovedEvent(ctx, &a.Aggregate, writeModel.Name, usernames, domainPolicy.UserLoginMustBeDomain, domains, links, entityIds)}, nil + }, nil + } +} + +func OrgUserIDPLinks(ctx context.Context, filter preparation.FilterToQueryReducer, orgID string) ([]*domain.UserIDPLink, error) { + events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + ResourceOwner(orgID). + OrderAsc(). + AddQuery(). + AggregateTypes(user_repo.AggregateType). + EventTypes( + user_repo.UserIDPLinkAddedType, user_repo.UserIDPLinkRemovedType, user_repo.UserIDPLinkCascadeRemovedType, + ).Builder()) + if err != nil { + return nil, err + } + links := make([]*domain.UserIDPLink, 0) + for _, event := range events { + switch eventTyped := event.(type) { + case *user_repo.UserIDPLinkAddedEvent: + links = append(links, &domain.UserIDPLink{ + IDPConfigID: eventTyped.IDPConfigID, + ExternalUserID: eventTyped.ExternalUserID, + DisplayName: eventTyped.DisplayName, + }) + case *user_repo.UserIDPLinkRemovedEvent: + for i := range links { + if links[i].ExternalUserID == eventTyped.ExternalUserID && + links[i].IDPConfigID == eventTyped.IDPConfigID { + links[i] = links[len(links)-1] + links[len(links)-1] = nil + links = links[:len(links)-1] + break + } + } + + case *user_repo.UserIDPLinkCascadeRemovedEvent: + for i := range links { + if links[i].ExternalUserID == eventTyped.ExternalUserID && + links[i].IDPConfigID == eventTyped.IDPConfigID { + links[i] = links[len(links)-1] + links[len(links)-1] = nil + links = links[:len(links)-1] + break + } + } + } + } + return links, nil +} + +type samlEntityID struct { + appID string + entityID string +} + +func OrgSamlEntityIDs(ctx context.Context, filter preparation.FilterToQueryReducer, orgID string) ([]string, error) { + events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + ResourceOwner(orgID). + OrderAsc(). + AddQuery(). + AggregateTypes(project.AggregateType). + EventTypes( + project.SAMLConfigAddedType, project.SAMLConfigChangedType, project.ApplicationRemovedType, + ).Builder()) + if err != nil { + return nil, err + } + entityIDs := make([]samlEntityID, 0) + for _, event := range events { + switch eventTyped := event.(type) { + case *project.SAMLConfigAddedEvent: + entityIDs = append(entityIDs, samlEntityID{appID: eventTyped.AppID, entityID: eventTyped.EntityID}) + case *project.SAMLConfigChangedEvent: + for i := range entityIDs { + if entityIDs[i].appID == eventTyped.AppID { + entityIDs[i].entityID = eventTyped.EntityID + break + } + } + case *project.ApplicationRemovedEvent: + for i := range entityIDs { + if entityIDs[i].appID == eventTyped.AppID { + entityIDs[i] = entityIDs[len(entityIDs)-1] + entityIDs = entityIDs[:len(entityIDs)-1] + break + } + } + } + } + ids := make([]string, len(entityIDs)) + for i := range entityIDs { + ids[i] = entityIDs[i].entityID + } + return ids, nil +} + +func OrgDomains(ctx context.Context, filter preparation.FilterToQueryReducer, orgID string) ([]string, error) { + events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + ResourceOwner(orgID). + OrderAsc(). + AddQuery(). + AggregateTypes(org.AggregateType). + EventTypes( + org.OrgDomainVerifiedEventType, + org.OrgDomainRemovedEventType, + ).Builder()) + if err != nil { + return nil, err + } + names := make([]string, 0) + for _, event := range events { + switch eventTyped := event.(type) { + case *org.DomainVerifiedEvent: + names = append(names, eventTyped.Domain) + case *org.DomainRemovedEvent: + for i := range names { + if names[i] == eventTyped.Domain { + names[i] = names[len(names)-1] + names = names[:len(names)-1] + break + } + } + } + } + return names, nil +} + +type userIDName struct { + name string + id string +} + +func OrgUsers(ctx context.Context, filter preparation.FilterToQueryReducer, orgID string) ([]string, error) { + events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + InstanceID(authz.GetInstance(ctx).InstanceID()). + ResourceOwner(orgID). + OrderAsc(). + AddQuery(). + AggregateTypes(user_repo.AggregateType). + EventTypes( + user_repo.HumanAddedType, + user_repo.MachineAddedEventType, + user_repo.HumanRegisteredType, + user_repo.UserDomainClaimedType, + user_repo.UserUserNameChangedType, + user_repo.UserRemovedType, + ).Builder()) + if err != nil { + return nil, err + } + + users := make([]userIDName, 0) + for _, event := range events { + switch eventTyped := event.(type) { + case *user_repo.HumanAddedEvent: + users = append(users, userIDName{eventTyped.UserName, eventTyped.Aggregate().ID}) + case *user_repo.MachineAddedEvent: + users = append(users, userIDName{eventTyped.UserName, eventTyped.Aggregate().ID}) + case *user_repo.HumanRegisteredEvent: + users = append(users, userIDName{eventTyped.UserName, eventTyped.Aggregate().ID}) + case *user_repo.DomainClaimedEvent: + for i := range users { + if users[i].id == eventTyped.Aggregate().ID { + users[i].name = eventTyped.UserName + } + } + case *user_repo.UsernameChangedEvent: + for i := range users { + if users[i].id == eventTyped.Aggregate().ID { + users[i].name = eventTyped.UserName + } + } + case *user_repo.UserRemovedEvent: + for i := range users { + if users[i].id == eventTyped.Aggregate().ID { + users[i] = users[len(users)-1] + users = users[:len(users)-1] + break + } + } + } + } + names := make([]string, len(users)) + for i := range users { + names[i] = users[i].name + } + return names, nil +} + func ExistsOrg(ctx context.Context, filter preparation.FilterToQueryReducer, id string) (exists bool, err error) { events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + InstanceID(authz.GetInstance(ctx).InstanceID()). ResourceOwner(id). OrderAsc(). AddQuery(). @@ -287,7 +530,7 @@ func ExistsOrg(ctx context.Context, filter preparation.FilterToQueryReducer, id func (c *Commands) addOrgWithID(ctx context.Context, organisation *domain.Org, orgID string, claimedUserIDs []string) (_ *eventstore.Aggregate, _ *OrgWriteModel, _ []eventstore.Command, err error) { if !organisation.IsValid() { - return nil, nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMM-deLSk", "Errors.Org.Invalid") + return nil, nil, nil, errors.ThrowInvalidArgument(nil, "COMM-deLSk", "Errors.Org.Invalid") } organisation.AggregateID = orgID @@ -316,3 +559,16 @@ func (c *Commands) getOrgWriteModelByID(ctx context.Context, orgID string) (*Org } return orgWriteModel, nil } + +func isOrgStateExists(state domain.OrgState) bool { + return !hasOrgState(state, domain.OrgStateRemoved, domain.OrgStateUnspecified) +} + +func hasOrgState(check domain.OrgState, states ...domain.OrgState) bool { + for _, state := range states { + if check == state { + return true + } + } + return false +} diff --git a/internal/command/org_custom_login_text.go b/internal/command/org_custom_login_text.go index 9e3dbbce9f..83a846d247 100644 --- a/internal/command/org_custom_login_text.go +++ b/internal/command/org_custom_login_text.go @@ -60,6 +60,9 @@ func (c *Commands) RemoveOrgLoginTexts(ctx context.Context, resourceOwner string } orgAgg := OrgAggregateFromWriteModel(&customText.WriteModel) pushedEvents, err := c.eventstore.Push(ctx, org.NewCustomTextTemplateRemovedEvent(ctx, orgAgg, domain.LoginCustomText, lang)) + if err != nil { + return nil, err + } err = AppendAndReduce(customText, pushedEvents...) if err != nil { return nil, err diff --git a/internal/command/org_member.go b/internal/command/org_member.go index fd29c84059..68e3e5cace 100644 --- a/internal/command/org_member.go +++ b/internal/command/org_member.go @@ -109,7 +109,7 @@ func (c *Commands) addOrgMember(ctx context.Context, orgAgg *eventstore.Aggregat return org.NewMemberAddedEvent(ctx, orgAgg, member.UserID, member.Roles...), nil } -//ChangeOrgMember updates an existing member +// ChangeOrgMember updates an existing member func (c *Commands) ChangeOrgMember(ctx context.Context, member *domain.Member) (*domain.Member, error) { if !member.IsValid() { return nil, errors.ThrowInvalidArgument(nil, "Org-LiaZi", "Errors.Org.MemberInvalid") @@ -128,6 +128,9 @@ func (c *Commands) ChangeOrgMember(ctx context.Context, member *domain.Member) ( } orgAgg := OrgAggregateFromWriteModel(&existingMember.MemberWriteModel.WriteModel) pushedEvents, err := c.eventstore.Push(ctx, org.NewMemberChangedEvent(ctx, orgAgg, member.UserID, member.Roles...)) + if err != nil { + return nil, err + } err = AppendAndReduce(existingMember, pushedEvents...) if err != nil { return nil, err diff --git a/internal/command/org_model.go b/internal/command/org_model.go index d2f2ad3c77..2661af9bd9 100644 --- a/internal/command/org_model.go +++ b/internal/command/org_model.go @@ -41,7 +41,7 @@ func (wm *OrgWriteModel) Reduce() error { wm.PrimaryDomain = e.Domain } } - return nil + return wm.WriteModel.Reduce() } func (wm *OrgWriteModel) Query() *eventstore.SearchQueryBuilder { diff --git a/internal/command/org_policy_login_factors_model.go b/internal/command/org_policy_login_factors_model.go index f1f039b147..0047aec7eb 100644 --- a/internal/command/org_policy_login_factors_model.go +++ b/internal/command/org_policy_login_factors_model.go @@ -161,10 +161,10 @@ func (wm *OrgAuthFactorsAllowedWriteModel) Reduce() error { wm.ensureMultiFactor(e.MFAType) wm.MultiFactors[e.MFAType].Org = domain.FactorStateRemoved case *org.LoginPolicyRemovedEvent: - for factorType, _ := range wm.SecondFactors { + for factorType := range wm.SecondFactors { wm.SecondFactors[factorType].Org = domain.FactorStateRemoved } - for factorType, _ := range wm.MultiFactors { + for factorType := range wm.MultiFactors { wm.MultiFactors[factorType].Org = domain.FactorStateRemoved } } diff --git a/internal/command/org_test.go b/internal/command/org_test.go index 1f7e04f4b3..5ef15301fe 100644 --- a/internal/command/org_test.go +++ b/internal/command/org_test.go @@ -17,6 +17,7 @@ import ( id_mock "github.com/zitadel/zitadel/internal/id/mock" "github.com/zitadel/zitadel/internal/repository/member" "github.com/zitadel/zitadel/internal/repository/org" + "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/user" ) @@ -1006,3 +1007,274 @@ func TestCommandSide_ReactivateOrg(t *testing.T) { }) } } + +func TestCommandSide_RemoveOrg(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + idGenerator id.Generator + } + type args struct { + ctx context.Context + orgID string + } + type res struct { + err func(error) bool + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "org not found, error", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter(), + ), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + }, + res: res{ + err: errors.IsNotFound, + }, + }, + { + name: "org already removed, error", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + org.NewOrgAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + "org"), + ), + eventFromEventPusher( + org.NewOrgRemovedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + "org", []string{}, false, []string{}, []*domain.UserIDPLink{}, []string{}), + ), + ), + ), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + }, + res: res{ + err: errors.IsNotFound, + }, + }, + { + name: "push failed, error", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + org.NewOrgAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + "org"), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + true, + true, + true, + ), + ), + ), + expectFilter(), + expectFilter(), + expectFilter(), + expectFilter(), + expectPushFailed( + errors.ThrowInternal(nil, "id", "message"), + []*repository.Event{ + eventFromEventPusher( + org.NewOrgRemovedEvent( + context.Background(), &org.NewAggregate("org1").Aggregate, "org", []string{}, false, []string{}, []*domain.UserIDPLink{}, []string{}, + ), + ), + }, + uniqueConstraintsFromEventConstraint(org.NewRemoveOrgNameUniqueConstraint("org")), + ), + ), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + }, + res: res{ + err: errors.IsInternal, + }, + }, + { + name: "remove org", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + org.NewOrgAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + "org"), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + true, + true, + true, + ), + ), + ), + expectFilter(), + expectFilter(), + expectFilter(), + expectFilter(), + expectPush( + []*repository.Event{ + eventFromEventPusher( + org.NewOrgRemovedEvent( + context.Background(), &org.NewAggregate("org1").Aggregate, "org", []string{}, false, []string{}, []*domain.UserIDPLink{}, []string{}, + ), + ), + }, + uniqueConstraintsFromEventConstraint(org.NewRemoveOrgNameUniqueConstraint("org")), + ), + ), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + }, + res: res{}, + }, + { + name: "remove org with usernames and domains", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + org.NewOrgAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + "org"), + ), + ), + + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &org.NewAggregate("org1").Aggregate, + true, + true, + true, + ), + ), + ), + expectFilter( + eventFromEventPusher( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user1", "org1").Aggregate, + "user1", + "firstname1", + "lastname1", + "nickname1", + "displayname1", + language.German, + domain.GenderMale, + "email1", + true, + ), + ), eventFromEventPusher( + user.NewMachineAddedEvent(context.Background(), + &user.NewAggregate("user2", "org1").Aggregate, + "user2", + "name", + "description", + true, + ), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewDomainVerifiedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "domain1"), + ), + eventFromEventPusher( + org.NewDomainVerifiedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "domain2"), + ), + ), + expectFilter( + eventFromEventPusher( + user.NewUserIDPLinkAddedEvent(context.Background(), &user.NewAggregate("user1", "org1").Aggregate, "config1", "display1", "id1"), + ), + eventFromEventPusher( + user.NewUserIDPLinkAddedEvent(context.Background(), &user.NewAggregate("user2", "org1").Aggregate, "config2", "display2", "id2"), + ), + ), + expectFilter( + eventFromEventPusher( + project.NewSAMLConfigAddedEvent(context.Background(), &project.NewAggregate("project1", "org1").Aggregate, "app1", "entity1", []byte{}, ""), + ), + eventFromEventPusher( + project.NewSAMLConfigAddedEvent(context.Background(), &project.NewAggregate("project2", "org1").Aggregate, "app2", "entity2", []byte{}, ""), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusher( + org.NewOrgRemovedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, "org", + []string{"user1", "user2"}, + false, + []string{"domain1", "domain2"}, + []*domain.UserIDPLink{{IDPConfigID: "config1", ExternalUserID: "id1", DisplayName: "display1"}, {IDPConfigID: "config2", ExternalUserID: "id2", DisplayName: "display2"}}, + []string{"entity1", "entity2"}, + ), + ), + }, + uniqueConstraintsFromEventConstraint(org.NewRemoveOrgNameUniqueConstraint("org")), + uniqueConstraintsFromEventConstraint(user.NewRemoveUsernameUniqueConstraint("user1", "org1", true)), + uniqueConstraintsFromEventConstraint(user.NewRemoveUsernameUniqueConstraint("user2", "org1", true)), + uniqueConstraintsFromEventConstraint(org.NewRemoveOrgDomainUniqueConstraint("domain1")), + uniqueConstraintsFromEventConstraint(org.NewRemoveOrgDomainUniqueConstraint("domain2")), + uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("config1", "id1")), + uniqueConstraintsFromEventConstraint(user.NewRemoveUserIDPLinkUniqueConstraint("config2", "id2")), + uniqueConstraintsFromEventConstraint(project.NewRemoveSAMLConfigEntityIDUniqueConstraint("entity1")), + uniqueConstraintsFromEventConstraint(project.NewRemoveSAMLConfigEntityIDUniqueConstraint("entity2")), + ), + ), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + }, + res: res{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore, + idGenerator: tt.fields.idGenerator, + } + _, err := r.RemoveOrg(tt.args.ctx, tt.args.orgID) + 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) + } + }) + } +} diff --git a/internal/command/project.go b/internal/command/project.go index ab2d4f2d98..751d54535f 100644 --- a/internal/command/project.go +++ b/internal/command/project.go @@ -9,7 +9,6 @@ import ( "github.com/zitadel/zitadel/internal/command/preparation" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" - caos_errs "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/project" ) @@ -20,14 +19,14 @@ func (c *Commands) AddProjectWithID(ctx context.Context, project *domain.Project return nil, err } if existingProject.State != domain.ProjectStateUnspecified { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-opamwu", "Errors.Project.AlreadyExisting") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-opamwu", "Errors.Project.AlreadyExisting") } return c.addProjectWithID(ctx, project, resourceOwner, projectID) } func (c *Commands) AddProject(ctx context.Context, project *domain.Project, resourceOwner, ownerUserID string) (_ *domain.Project, err error) { if !project.IsValid() { - return nil, caos_errs.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid") + return nil, errors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid") } projectID, err := c.idGenerator.Next() @@ -67,7 +66,7 @@ func (c *Commands) addProjectWithID(ctx context.Context, projectAdd *domain.Proj func (c *Commands) addProjectWithIDWithOwner(ctx context.Context, projectAdd *domain.Project, resourceOwner, ownerUserID, projectID string) (_ *domain.Project, err error) { if !projectAdd.IsValid() { - return nil, caos_errs.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid") + return nil, errors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid") } projectAdd.AggregateID = projectID addedProject := NewProjectWriteModel(projectAdd.AggregateID, resourceOwner) @@ -154,7 +153,7 @@ func (c *Commands) getProjectByID(ctx context.Context, projectID, resourceOwner return nil, err } if projectWriteModel.State == domain.ProjectStateUnspecified || projectWriteModel.State == domain.ProjectStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "PROJECT-Gd2hh", "Errors.Project.NotFound") + return nil, errors.ThrowNotFound(nil, "PROJECT-Gd2hh", "Errors.Project.NotFound") } return projectWriteModelToProject(projectWriteModel), nil } @@ -165,14 +164,14 @@ func (c *Commands) checkProjectExists(ctx context.Context, projectID, resourceOw return err } if projectWriteModel.State == domain.ProjectStateUnspecified || projectWriteModel.State == domain.ProjectStateRemoved { - return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-EbFMN", "Errors.Project.NotFound") + return errors.ThrowPreconditionFailed(nil, "COMMAND-EbFMN", "Errors.Project.NotFound") } return nil } func (c *Commands) ChangeProject(ctx context.Context, projectChange *domain.Project, resourceOwner string) (*domain.Project, error) { if !projectChange.IsValid() || projectChange.AggregateID == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Invalid") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Invalid") } existingProject, err := c.getProjectWriteModelByID(ctx, projectChange.AggregateID, resourceOwner) @@ -180,7 +179,7 @@ func (c *Commands) ChangeProject(ctx context.Context, projectChange *domain.Proj return nil, err } if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound") } projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel) @@ -196,7 +195,7 @@ func (c *Commands) ChangeProject(ctx context.Context, projectChange *domain.Proj return nil, err } if !hasChanged { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M0fs", "Errors.NoChangesFound") + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-2M0fs", "Errors.NoChangesFound") } pushedEvents, err := c.eventstore.Push(ctx, changedEvent) if err != nil { @@ -211,7 +210,7 @@ func (c *Commands) ChangeProject(ctx context.Context, projectChange *domain.Proj func (c *Commands) DeactivateProject(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) { if projectID == "" || resourceOwner == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-88iF0", "Errors.Project.ProjectIDMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-88iF0", "Errors.Project.ProjectIDMissing") } existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner) @@ -219,10 +218,10 @@ func (c *Commands) DeactivateProject(ctx context.Context, projectID string, reso return nil, err } if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-112M9", "Errors.Project.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-112M9", "Errors.Project.NotFound") } if existingProject.State != domain.ProjectStateActive { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-mki55", "Errors.Project.NotActive") + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-mki55", "Errors.Project.NotActive") } projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel) @@ -239,7 +238,7 @@ func (c *Commands) DeactivateProject(ctx context.Context, projectID string, reso func (c *Commands) ReactivateProject(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) { if projectID == "" || resourceOwner == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-3ihsF", "Errors.Project.ProjectIDMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-3ihsF", "Errors.Project.ProjectIDMissing") } existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner) @@ -247,10 +246,10 @@ func (c *Commands) ReactivateProject(ctx context.Context, projectID string, reso return nil, err } if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound") } if existingProject.State != domain.ProjectStateInactive { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5M9bs", "Errors.Project.NotInactive") + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-5M9bs", "Errors.Project.NotInactive") } projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel) @@ -267,7 +266,7 @@ func (c *Commands) ReactivateProject(ctx context.Context, projectID string, reso func (c *Commands) RemoveProject(ctx context.Context, projectID, resourceOwner string, cascadingUserGrantIDs ...string) (*domain.ObjectDetails, error) { if projectID == "" || resourceOwner == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-66hM9", "Errors.Project.ProjectIDMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-66hM9", "Errors.Project.ProjectIDMissing") } existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner) @@ -275,7 +274,7 @@ func (c *Commands) RemoveProject(ctx context.Context, projectID, resourceOwner s return nil, err } if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound") } samlEntityIDsAgg, err := c.getSAMLEntityIdsWriteModelByProjectID(ctx, projectID, resourceOwner) diff --git a/internal/command/project_application_oidc.go b/internal/command/project_application_oidc.go index b29b38cf50..99eec03d41 100644 --- a/internal/command/project_application_oidc.go +++ b/internal/command/project_application_oidc.go @@ -12,7 +12,6 @@ import ( "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" - caos_errs "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" project_repo "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/telemetry/tracing" @@ -122,12 +121,12 @@ func (c *Commands) AddOIDCApplicationWithID(ctx context.Context, oidcApp *domain return nil, err } if existingApp.State != domain.AppStateUnspecified { - return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-lxowmp", "Errors.Project.App.AlreadyExisting") + return nil, errors.ThrowPreconditionFailed(nil, "PROJECT-lxowmp", "Errors.Project.App.AlreadyExisting") } project, err := c.getProjectByID(ctx, oidcApp.AggregateID, resourceOwner) if err != nil { - return nil, caos_errs.ThrowPreconditionFailed(err, "PROJECT-3m9s2", "Errors.Project.NotFound") + return nil, errors.ThrowPreconditionFailed(err, "PROJECT-3m9s2", "Errors.Project.NotFound") } return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, project, appID, appSecretGenerator) @@ -135,15 +134,15 @@ func (c *Commands) AddOIDCApplicationWithID(ctx context.Context, oidcApp *domain func (c *Commands) AddOIDCApplication(ctx context.Context, oidcApp *domain.OIDCApp, resourceOwner string, appSecretGenerator crypto.Generator) (_ *domain.OIDCApp, err error) { if oidcApp == nil || oidcApp.AggregateID == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "PROJECT-34Fm0", "Errors.Project.App.Invalid") + return nil, errors.ThrowInvalidArgument(nil, "PROJECT-34Fm0", "Errors.Project.App.Invalid") } project, err := c.getProjectByID(ctx, oidcApp.AggregateID, resourceOwner) if err != nil { - return nil, caos_errs.ThrowPreconditionFailed(err, "PROJECT-3m9ss", "Errors.Project.NotFound") + return nil, errors.ThrowPreconditionFailed(err, "PROJECT-3m9ss", "Errors.Project.NotFound") } if oidcApp.AppName == "" || !oidcApp.IsValid() { - return nil, caos_errs.ThrowInvalidArgument(nil, "PROJECT-1n8df", "Errors.Project.App.Invalid") + return nil, errors.ThrowInvalidArgument(nil, "PROJECT-1n8df", "Errors.Project.App.Invalid") } appID, err := c.idGenerator.Next() @@ -211,7 +210,7 @@ func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain func (c *Commands) ChangeOIDCApplication(ctx context.Context, oidc *domain.OIDCApp, resourceOwner string) (*domain.OIDCApp, error) { if !oidc.IsValid() || oidc.AppID == "" || oidc.AggregateID == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-5m9fs", "Errors.Project.App.OIDCConfigInvalid") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-5m9fs", "Errors.Project.App.OIDCConfigInvalid") } existingOIDC, err := c.getOIDCAppWriteModel(ctx, oidc.AggregateID, oidc.AppID, resourceOwner) @@ -219,10 +218,10 @@ func (c *Commands) ChangeOIDCApplication(ctx context.Context, oidc *domain.OIDCA return nil, err } if existingOIDC.State == domain.AppStateUnspecified || existingOIDC.State == domain.AppStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-2n8uU", "Errors.Project.App.NotExisting") + return nil, errors.ThrowNotFound(nil, "COMMAND-2n8uU", "Errors.Project.App.NotExisting") } if !existingOIDC.IsOIDC() { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-GBr34", "Errors.Project.App.IsNotOIDC") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-GBr34", "Errors.Project.App.IsNotOIDC") } projectAgg := ProjectAggregateFromWriteModel(&existingOIDC.WriteModel) changedEvent, hasChanged, err := existingOIDC.NewChangedEvent( @@ -247,7 +246,7 @@ func (c *Commands) ChangeOIDCApplication(ctx context.Context, oidc *domain.OIDCA return nil, err } if !hasChanged { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-1m88i", "Errors.NoChangesFound") + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-1m88i", "Errors.NoChangesFound") } pushedEvents, err := c.eventstore.Push(ctx, changedEvent) @@ -266,7 +265,7 @@ func (c *Commands) ChangeOIDCApplication(ctx context.Context, oidc *domain.OIDCA func (c *Commands) ChangeOIDCApplicationSecret(ctx context.Context, projectID, appID, resourceOwner string, appSecretGenerator crypto.Generator) (*domain.OIDCApp, error) { if projectID == "" || appID == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-99i83", "Errors.IDMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-99i83", "Errors.IDMissing") } existingOIDC, err := c.getOIDCAppWriteModel(ctx, projectID, appID, resourceOwner) @@ -274,10 +273,10 @@ func (c *Commands) ChangeOIDCApplicationSecret(ctx context.Context, projectID, a return nil, err } if existingOIDC.State == domain.AppStateUnspecified || existingOIDC.State == domain.AppStateRemoved { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-2g66f", "Errors.Project.App.NotExisting") + return nil, errors.ThrowNotFound(nil, "COMMAND-2g66f", "Errors.Project.App.NotExisting") } if !existingOIDC.IsOIDC() { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Ghrh3", "Errors.Project.App.IsNotOIDC") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-Ghrh3", "Errors.Project.App.IsNotOIDC") } cryptoSecret, stringPW, err := domain.NewClientSecret(appSecretGenerator) if err != nil { @@ -309,13 +308,13 @@ func (c *Commands) VerifyOIDCClientSecret(ctx context.Context, projectID, appID, return err } if !app.State.Exists() { - return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.NotExisting") + return errors.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.NotExisting") } if !app.IsOIDC() { - return caos_errs.ThrowInvalidArgument(nil, "COMMAND-BHgn2", "Errors.Project.App.IsNotOIDC") + return errors.ThrowInvalidArgument(nil, "COMMAND-BHgn2", "Errors.Project.App.IsNotOIDC") } if app.ClientSecret == nil { - return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.OIDCConfigInvalid") + return errors.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.OIDCConfigInvalid") } projectAgg := ProjectAggregateFromWriteModel(&app.WriteModel) @@ -327,8 +326,8 @@ func (c *Commands) VerifyOIDCClientSecret(ctx context.Context, projectID, appID, return err } _, err = c.eventstore.Push(ctx, project_repo.NewOIDCConfigSecretCheckFailedEvent(ctx, projectAgg, app.AppID)) - logging.New().OnError(err).Error("could not push event OIDCClientSecretCheckFailed") - return caos_errs.ThrowInvalidArgument(nil, "COMMAND-Bz542", "Errors.Project.App.ClientSecretInvalid") + logging.OnError(err).Error("could not push event OIDCClientSecretCheckFailed") + return errors.ThrowInvalidArgument(nil, "COMMAND-Bz542", "Errors.Project.App.ClientSecretInvalid") } func (c *Commands) getOIDCAppWriteModel(ctx context.Context, projectID, appID, resourceOwner string) (*OIDCApplicationWriteModel, error) { diff --git a/internal/command/project_grant.go b/internal/command/project_grant.go index 9e83044e3d..21b9e61cea 100644 --- a/internal/command/project_grant.go +++ b/internal/command/project_grant.go @@ -5,6 +5,7 @@ import ( "reflect" "github.com/zitadel/logging" + "github.com/zitadel/zitadel/internal/domain" caos_errs "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" diff --git a/internal/command/project_test.go b/internal/command/project_test.go index 4dfe3054c7..60b77f9e25 100644 --- a/internal/command/project_test.go +++ b/internal/command/project_test.go @@ -6,16 +6,14 @@ import ( "github.com/stretchr/testify/assert" - id_mock "github.com/zitadel/zitadel/internal/id/mock" - "github.com/zitadel/zitadel/internal/repository/member" - "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" - caos_errs "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/repository" "github.com/zitadel/zitadel/internal/eventstore/v1/models" "github.com/zitadel/zitadel/internal/id" + id_mock "github.com/zitadel/zitadel/internal/id/mock" + "github.com/zitadel/zitadel/internal/repository/member" "github.com/zitadel/zitadel/internal/repository/project" ) @@ -53,7 +51,7 @@ func TestCommandSide_AddProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -61,7 +59,7 @@ func TestCommandSide_AddProject(t *testing.T) { fields: fields{ eventstore: eventstoreExpect( t, - expectPushFailed(caos_errs.ThrowAlreadyExists(nil, "ERROR", "internl"), + expectPushFailed(errors.ThrowAlreadyExists(nil, "ERROR", "internl"), []*repository.Event{ eventFromEventPusher(project.NewProjectAddedEvent( context.Background(), @@ -97,7 +95,7 @@ func TestCommandSide_AddProject(t *testing.T) { ownerID: "user1", }, res: res{ - err: caos_errs.IsErrorAlreadyExists, + err: errors.IsErrorAlreadyExists, }, }, { @@ -211,7 +209,7 @@ func TestCommandSide_ChangeProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -229,7 +227,7 @@ func TestCommandSide_ChangeProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -251,7 +249,7 @@ func TestCommandSide_ChangeProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -286,7 +284,7 @@ func TestCommandSide_ChangeProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -319,7 +317,7 @@ func TestCommandSide_ChangeProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -492,7 +490,7 @@ func TestCommandSide_DeactivateProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -508,7 +506,7 @@ func TestCommandSide_DeactivateProject(t *testing.T) { resourceOwner: "", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -525,7 +523,7 @@ func TestCommandSide_DeactivateProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -555,7 +553,7 @@ func TestCommandSide_DeactivateProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -583,7 +581,7 @@ func TestCommandSide_DeactivateProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -672,7 +670,7 @@ func TestCommandSide_ReactivateProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -688,7 +686,7 @@ func TestCommandSide_ReactivateProject(t *testing.T) { resourceOwner: "", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -705,7 +703,7 @@ func TestCommandSide_ReactivateProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -735,7 +733,7 @@ func TestCommandSide_ReactivateProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -759,7 +757,7 @@ func TestCommandSide_ReactivateProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -852,7 +850,7 @@ func TestCommandSide_RemoveProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -868,7 +866,7 @@ func TestCommandSide_RemoveProject(t *testing.T) { resourceOwner: "", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -885,7 +883,7 @@ func TestCommandSide_RemoveProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -915,7 +913,7 @@ func TestCommandSide_RemoveProject(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { diff --git a/internal/command/user.go b/internal/command/user.go index 27f008403f..4d04a18e76 100644 --- a/internal/command/user.go +++ b/internal/command/user.go @@ -12,7 +12,7 @@ import ( "github.com/zitadel/zitadel/internal/command/preparation" "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" - caos_errs "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/v1/models" "github.com/zitadel/zitadel/internal/repository/user" @@ -22,7 +22,7 @@ import ( func (c *Commands) ChangeUsername(ctx context.Context, orgID, userID, userName string) (*domain.ObjectDetails, error) { userName = strings.TrimSpace(userName) if orgID == "" || userID == "" || userName == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-2N9fs", "Errors.IDMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-2N9fs", "Errors.IDMissing") } existingUser, err := c.userWriteModelByID(ctx, userID, orgID) @@ -31,16 +31,16 @@ func (c *Commands) ChangeUsername(ctx context.Context, orgID, userID, userName s } if !isUserStateExists(existingUser.UserState) { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-5N9ds", "Errors.User.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-5N9ds", "Errors.User.NotFound") } if existingUser.UserName == userName { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6m9gs", "Errors.User.UsernameNotChanged") + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-6m9gs", "Errors.User.UsernameNotChanged") } domainPolicy, err := c.getOrgDomainPolicy(ctx, orgID) if err != nil { - return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-38fnu", "Errors.Org.DomainPolicy.NotExisting") + return nil, errors.ThrowPreconditionFailed(err, "COMMAND-38fnu", "Errors.Org.DomainPolicy.NotExisting") } if err := CheckDomainPolicyForUserName(userName, domainPolicy); err != nil { @@ -62,7 +62,7 @@ func (c *Commands) ChangeUsername(ctx context.Context, orgID, userID, userName s func (c *Commands) DeactivateUser(ctx context.Context, userID, resourceOwner string) (*domain.ObjectDetails, error) { if userID == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-m0gDf", "Errors.User.UserIDMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-m0gDf", "Errors.User.UserIDMissing") } existingUser, err := c.userWriteModelByID(ctx, userID, resourceOwner) @@ -70,13 +70,13 @@ func (c *Commands) DeactivateUser(ctx context.Context, userID, resourceOwner str return nil, err } if !isUserStateExists(existingUser.UserState) { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3M9ds", "Errors.User.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-3M9ds", "Errors.User.NotFound") } if isUserStateInitial(existingUser.UserState) { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-ke0fw", "Errors.User.CantDeactivateInitial") + return nil, errors.ThrowNotFound(nil, "COMMAND-ke0fw", "Errors.User.CantDeactivateInitial") } if isUserStateInactive(existingUser.UserState) { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5M0sf", "Errors.User.AlreadyInactive") + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-5M0sf", "Errors.User.AlreadyInactive") } pushedEvents, err := c.eventstore.Push(ctx, @@ -93,7 +93,7 @@ func (c *Commands) DeactivateUser(ctx context.Context, userID, resourceOwner str func (c *Commands) ReactivateUser(ctx context.Context, userID, resourceOwner string) (*domain.ObjectDetails, error) { if userID == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4M9ds", "Errors.User.UserIDMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-4M9ds", "Errors.User.UserIDMissing") } existingUser, err := c.userWriteModelByID(ctx, userID, resourceOwner) @@ -101,10 +101,10 @@ func (c *Commands) ReactivateUser(ctx context.Context, userID, resourceOwner str return nil, err } if !isUserStateExists(existingUser.UserState) { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-4M0sd", "Errors.User.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-4M0sd", "Errors.User.NotFound") } if !isUserStateInactive(existingUser.UserState) { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6M0sf", "Errors.User.NotInactive") + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-6M0sf", "Errors.User.NotInactive") } pushedEvents, err := c.eventstore.Push(ctx, @@ -121,7 +121,7 @@ func (c *Commands) ReactivateUser(ctx context.Context, userID, resourceOwner str func (c *Commands) LockUser(ctx context.Context, userID, resourceOwner string) (*domain.ObjectDetails, error) { if userID == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-2M0sd", "Errors.User.UserIDMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-2M0sd", "Errors.User.UserIDMissing") } existingUser, err := c.userWriteModelByID(ctx, userID, resourceOwner) @@ -129,10 +129,10 @@ func (c *Commands) LockUser(ctx context.Context, userID, resourceOwner string) ( return nil, err } if !isUserStateExists(existingUser.UserState) { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-5M9fs", "Errors.User.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-5M9fs", "Errors.User.NotFound") } if !hasUserState(existingUser.UserState, domain.UserStateActive, domain.UserStateInitial) { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-3NN8v", "Errors.User.ShouldBeActiveOrInitial") + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-3NN8v", "Errors.User.ShouldBeActiveOrInitial") } pushedEvents, err := c.eventstore.Push(ctx, @@ -149,7 +149,7 @@ func (c *Commands) LockUser(ctx context.Context, userID, resourceOwner string) ( func (c *Commands) UnlockUser(ctx context.Context, userID, resourceOwner string) (*domain.ObjectDetails, error) { if userID == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-M0dse", "Errors.User.UserIDMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-M0dse", "Errors.User.UserIDMissing") } existingUser, err := c.userWriteModelByID(ctx, userID, resourceOwner) @@ -157,10 +157,10 @@ func (c *Commands) UnlockUser(ctx context.Context, userID, resourceOwner string) return nil, err } if !isUserStateExists(existingUser.UserState) { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-M0dos", "Errors.User.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-M0dos", "Errors.User.NotFound") } if !hasUserState(existingUser.UserState, domain.UserStateLocked) { - return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M0ds", "Errors.User.NotLocked") + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-4M0ds", "Errors.User.NotLocked") } pushedEvents, err := c.eventstore.Push(ctx, @@ -177,7 +177,7 @@ func (c *Commands) UnlockUser(ctx context.Context, userID, resourceOwner string) func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string, cascadingUserMemberships []*CascadingMembership, cascadingGrantIDs ...string) (*domain.ObjectDetails, error) { if userID == "" { - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-2M0ds", "Errors.User.UserIDMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-2M0ds", "Errors.User.UserIDMissing") } existingUser, err := c.userWriteModelByID(ctx, userID, resourceOwner) @@ -185,12 +185,12 @@ func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string, return nil, err } if !isUserStateExists(existingUser.UserState) { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-m9od", "Errors.User.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-m9od", "Errors.User.NotFound") } domainPolicy, err := c.getOrgDomainPolicy(ctx, existingUser.ResourceOwner) if err != nil { - return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-3M9fs", "Errors.Org.DomainPolicy.NotExisting") + return nil, errors.ThrowPreconditionFailed(err, "COMMAND-3M9fs", "Errors.Org.DomainPolicy.NotExisting") } var events []eventstore.Command userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel) @@ -226,7 +226,7 @@ func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string, func (c *Commands) AddUserToken(ctx context.Context, orgID, agentID, clientID, userID string, audience, scopes []string, lifetime time.Duration) (*domain.Token, error) { if userID == "" { //do not check for empty orgID (JWT Profile requests won't provide it, so service user requests fail) - return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Dbge4", "Errors.IDMissing") + return nil, errors.ThrowInvalidArgument(nil, "COMMAND-Dbge4", "Errors.IDMissing") } userWriteModel := NewUserWriteModel(userID, orgID) event, accessToken, err := c.addUserToken(ctx, userWriteModel, agentID, clientID, "", audience, scopes, lifetime) @@ -262,7 +262,7 @@ func (c *Commands) addUserToken(ctx context.Context, userWriteModel *UserWriteMo return nil, nil, err } if !isUserStateExists(userWriteModel.UserState) { - return nil, nil, caos_errs.ThrowNotFound(nil, "COMMAND-1d6Gg", "Errors.User.NotFound") + return nil, nil, errors.ThrowNotFound(nil, "COMMAND-1d6Gg", "Errors.User.NotFound") } audience = domain.AddAudScopeToAudience(ctx, audience, scopes) @@ -297,7 +297,7 @@ func (c *Commands) addUserToken(ctx context.Context, userWriteModel *UserWriteMo func (c *Commands) removeAccessToken(ctx context.Context, userID, orgID, tokenID string) (*user.UserTokenRemovedEvent, *UserAccessTokenWriteModel, error) { if userID == "" || orgID == "" || tokenID == "" { - return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Dng42", "Errors.IDMissing") + return nil, nil, errors.ThrowInvalidArgument(nil, "COMMAND-Dng42", "Errors.IDMissing") } refreshTokenWriteModel := NewUserAccessTokenWriteModel(userID, orgID, tokenID) err := c.eventstore.FilterToQueryReducer(ctx, refreshTokenWriteModel) @@ -305,7 +305,7 @@ func (c *Commands) removeAccessToken(ctx context.Context, userID, orgID, tokenID return nil, nil, err } if refreshTokenWriteModel.UserState != domain.UserStateActive { - return nil, nil, caos_errs.ThrowNotFound(nil, "COMMAND-BF4hd", "Errors.User.AccessToken.NotFound") + return nil, nil, errors.ThrowNotFound(nil, "COMMAND-BF4hd", "Errors.User.AccessToken.NotFound") } userAgg := UserAggregateFromWriteModel(&refreshTokenWriteModel.WriteModel) return user.NewUserTokenRemovedEvent(ctx, userAgg, tokenID), refreshTokenWriteModel, nil @@ -317,7 +317,7 @@ func (c *Commands) userDomainClaimed(ctx context.Context, userID string) (events return nil, nil, err } if existingUser.UserState == domain.UserStateUnspecified || existingUser.UserState == domain.UserStateDeleted { - return nil, nil, caos_errs.ThrowNotFound(nil, "COMMAND-ii9K0", "Errors.User.NotFound") + return nil, nil, errors.ThrowNotFound(nil, "COMMAND-ii9K0", "Errors.User.NotFound") } changedUserGrant := NewUserWriteModel(userID, existingUser.ResourceOwner) userAgg := UserAggregateFromWriteModel(&changedUserGrant.WriteModel) @@ -347,7 +347,7 @@ func (c *Commands) prepareUserDomainClaimed(ctx context.Context, filter preparat return nil, err } if !userWriteModel.UserState.Exists() { - return nil, caos_errs.ThrowNotFound(nil, "COMMAND-ii9K0", "Errors.User.NotFound") + return nil, errors.ThrowNotFound(nil, "COMMAND-ii9K0", "Errors.User.NotFound") } domainPolicy, err := domainPolicyWriteModel(ctx, filter) if err != nil { @@ -370,14 +370,14 @@ func (c *Commands) prepareUserDomainClaimed(ctx context.Context, filter preparat func (c *Commands) UserDomainClaimedSent(ctx context.Context, orgID, userID string) (err error) { if userID == "" { - return caos_errs.ThrowInvalidArgument(nil, "COMMAND-5m0fs", "Errors.IDMissing") + return errors.ThrowInvalidArgument(nil, "COMMAND-5m0fs", "Errors.IDMissing") } existingUser, err := c.userWriteModelByID(ctx, userID, orgID) if err != nil { return err } if !isUserStateExists(existingUser.UserState) { - return caos_errs.ThrowNotFound(nil, "COMMAND-5m9gK", "Errors.User.NotFound") + return errors.ThrowNotFound(nil, "COMMAND-5m9gK", "Errors.User.NotFound") } _, err = c.eventstore.Push(ctx, @@ -391,7 +391,7 @@ func (c *Commands) checkUserExists(ctx context.Context, userID, resourceOwner st return err } if !isUserStateExists(existingUser.UserState) { - return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-uXHNj", "Errors.User.NotFound") + return errors.ThrowPreconditionFailed(nil, "COMMAND-uXHNj", "Errors.User.NotFound") } return nil } diff --git a/internal/command/user_metadata_model.go b/internal/command/user_metadata_model.go index 5e3b1b5e9f..3ab68242ee 100644 --- a/internal/command/user_metadata_model.go +++ b/internal/command/user_metadata_model.go @@ -137,9 +137,7 @@ func (wm *UserMetadataByOrgListWriteModel) Reduce() error { delete(val, e.Key) } case *metadata.RemovedAllEvent: - if _, ok := wm.UserMetadata[e.Aggregate().ID]; ok { - delete(wm.UserMetadata, e.Aggregate().ID) - } + delete(wm.UserMetadata, e.Aggregate().ID) } } return wm.WriteModel.Reduce() diff --git a/internal/command/user_test.go b/internal/command/user_test.go index aa43a5a0c6..74e8f70ba4 100644 --- a/internal/command/user_test.go +++ b/internal/command/user_test.go @@ -8,18 +8,16 @@ import ( "github.com/stretchr/testify/assert" "golang.org/x/text/language" - "github.com/zitadel/zitadel/internal/repository/member" - "github.com/zitadel/zitadel/internal/repository/org" - "github.com/zitadel/zitadel/internal/repository/project" - "github.com/zitadel/zitadel/internal/command/preparation" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" - caos_errs "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/repository" "github.com/zitadel/zitadel/internal/id" "github.com/zitadel/zitadel/internal/repository/instance" + "github.com/zitadel/zitadel/internal/repository/member" + "github.com/zitadel/zitadel/internal/repository/org" + "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/user" ) @@ -59,7 +57,7 @@ func TestCommandSide_UsernameChange(t *testing.T) { username: "username", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -76,7 +74,7 @@ func TestCommandSide_UsernameChange(t *testing.T) { username: "username", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -93,7 +91,7 @@ func TestCommandSide_UsernameChange(t *testing.T) { username: "", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -110,7 +108,7 @@ func TestCommandSide_UsernameChange(t *testing.T) { username: " ", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -128,7 +126,7 @@ func TestCommandSide_UsernameChange(t *testing.T) { username: "username", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -161,7 +159,7 @@ func TestCommandSide_UsernameChange(t *testing.T) { username: "username", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -194,7 +192,7 @@ func TestCommandSide_UsernameChange(t *testing.T) { username: "username ", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -227,7 +225,7 @@ func TestCommandSide_UsernameChange(t *testing.T) { username: "username", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -271,7 +269,7 @@ func TestCommandSide_UsernameChange(t *testing.T) { username: "test@test.ch", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -448,7 +446,7 @@ func TestCommandSide_DeactivateUser(t *testing.T) { userID: "", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -465,7 +463,7 @@ func TestCommandSide_DeactivateUser(t *testing.T) { userID: "user1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -502,7 +500,7 @@ func TestCommandSide_DeactivateUser(t *testing.T) { userID: "user1", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -602,7 +600,7 @@ func TestCommandSide_ReactivateUser(t *testing.T) { userID: "", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -619,7 +617,7 @@ func TestCommandSide_ReactivateUser(t *testing.T) { userID: "user1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -651,7 +649,7 @@ func TestCommandSide_ReactivateUser(t *testing.T) { userID: "user1", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -755,7 +753,7 @@ func TestCommandSide_LockUser(t *testing.T) { userID: "", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -772,7 +770,7 @@ func TestCommandSide_LockUser(t *testing.T) { userID: "user1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -809,7 +807,7 @@ func TestCommandSide_LockUser(t *testing.T) { userID: "user1", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -909,7 +907,7 @@ func TestCommandSide_UnlockUser(t *testing.T) { userID: "", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -926,7 +924,7 @@ func TestCommandSide_UnlockUser(t *testing.T) { userID: "user1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -958,7 +956,7 @@ func TestCommandSide_UnlockUser(t *testing.T) { userID: "user1", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -1065,7 +1063,7 @@ func TestCommandSide_RemoveUser(t *testing.T) { userID: "", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -1082,7 +1080,7 @@ func TestCommandSide_RemoveUser(t *testing.T) { userID: "user1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { @@ -1116,7 +1114,7 @@ func TestCommandSide_RemoveUser(t *testing.T) { userID: "user1", }, res: res{ - err: caos_errs.IsPreconditionFailed, + err: errors.IsPreconditionFailed, }, }, { @@ -1423,7 +1421,7 @@ func TestCommandSide_AddUserToken(t *testing.T) { userID: "", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -1440,7 +1438,7 @@ func TestCommandSide_AddUserToken(t *testing.T) { userID: "user1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, } @@ -1497,7 +1495,7 @@ func TestCommands_RevokeAccessToken(t *testing.T) { }, res{ nil, - caos_errs.IsErrorInvalidArgument, + errors.IsErrorInvalidArgument, }, }, { @@ -1529,7 +1527,7 @@ func TestCommands_RevokeAccessToken(t *testing.T) { }, res{ nil, - caos_errs.IsNotFound, + errors.IsNotFound, }, }, { @@ -1624,7 +1622,7 @@ func TestCommandSide_UserDomainClaimedSent(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsErrorInvalidArgument, + err: errors.IsErrorInvalidArgument, }, }, { @@ -1641,7 +1639,7 @@ func TestCommandSide_UserDomainClaimedSent(t *testing.T) { resourceOwner: "org1", }, res: res{ - err: caos_errs.IsNotFound, + err: errors.IsNotFound, }, }, { diff --git a/internal/eventstore/handler/crdb/init.go b/internal/eventstore/handler/crdb/init.go index d8edb7cd08..2039fcd97d 100644 --- a/internal/eventstore/handler/crdb/init.go +++ b/internal/eventstore/handler/crdb/init.go @@ -173,9 +173,9 @@ func NewForeignKey(name string, columns []string, refColumns []string) *ForeignK return i } -func NewForeignKeyOfPublicKeys(name string) *ForeignKey { +func NewForeignKeyOfPublicKeys() *ForeignKey { return &ForeignKey{ - Name: name, + Name: "", } } @@ -218,7 +218,7 @@ func NewTableCheck(table *Table, opts ...execOption) *handler.Check { executes := make([]func(handler.Executer, string) (bool, error), len(table.indices)+1) executes[0] = execNextIfExists(config, create, opts, true) for i, index := range table.indices { - executes[i+1] = execNextIfExists(config, createIndexStatement(index), opts, true) + executes[i+1] = execNextIfExists(config, createIndexCheck(index), opts, true) } return &handler.Check{ Executes: executes, @@ -296,16 +296,16 @@ func createTableStatement(table *Table, tableName string, suffix string) string if len(key.Columns) == 0 { key.Columns = table.primaryKey } - stmt += fmt.Sprintf(", CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s ON DELETE CASCADE", key.Name, strings.Join(key.Columns, ","), ref) + stmt += fmt.Sprintf(", CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s ON DELETE CASCADE", foreignKeyName(key.Name, tableName, suffix), strings.Join(key.Columns, ","), ref) } for _, constraint := range table.constraints { - stmt += fmt.Sprintf(", CONSTRAINT %s UNIQUE (%s)", constraint.Name, strings.Join(constraint.Columns, ",")) + stmt += fmt.Sprintf(", CONSTRAINT %s UNIQUE (%s)", constraintName(constraint.Name, tableName, suffix), strings.Join(constraint.Columns, ",")) } stmt += ");" for _, index := range table.indices { - stmt += fmt.Sprintf("CREATE INDEX IF NOT EXISTS %s ON %s (%s);", index.Name, tableName+suffix, strings.Join(index.Columns, ",")) + stmt += createIndexStatement(index, tableName+suffix) } return stmt } @@ -317,21 +317,43 @@ func createViewStatement(viewName string, selectStmt string) string { ) } -func createIndexStatement(index *Index) func(config execConfig) string { +func createIndexCheck(index *Index) func(config execConfig) string { return func(config execConfig) string { - stmt := fmt.Sprintf("CREATE INDEX IF NOT EXISTS %s ON %s (%s)", - index.Name, - config.tableName, - strings.Join(index.Columns, ","), - ) - if index.bucketCount == 0 { - return stmt + ";" - } - return fmt.Sprintf("SET experimental_enable_hash_sharded_indexes=on; %s USING HASH WITH BUCKET_COUNT = %d;", - stmt, index.bucketCount) + return createIndexStatement(index, config.tableName) } } +func createIndexStatement(index *Index, tableName string) string { + stmt := fmt.Sprintf("CREATE INDEX IF NOT EXISTS %s ON %s (%s)", + indexName(index.Name, tableName), + tableName, + strings.Join(index.Columns, ","), + ) + if index.bucketCount == 0 { + return stmt + ";" + } + return fmt.Sprintf("SET experimental_enable_hash_sharded_indexes=on; %s USING HASH WITH BUCKET_COUNT = %d;", + stmt, index.bucketCount) +} + +func foreignKeyName(name, tableName, suffix string) string { + if name == "" { + key := "fk" + suffix + "_ref_" + tableNameWithoutSchema(tableName) + return key + } + return "fk_" + tableNameWithoutSchema(tableName+suffix) + "_" + name +} +func constraintName(name, tableName, suffix string) string { + return tableNameWithoutSchema(tableName+suffix) + "_" + name + "_unique" +} +func indexName(name, tableName string) string { + return tableNameWithoutSchema(tableName) + "_" + name + "_idx" +} + +func tableNameWithoutSchema(name string) string { + return name[strings.LastIndex(name, ".")+1:] +} + func createColumnsStatement(cols []*Column, tableName string) string { columns := make([]string, len(cols)) for i, col := range cols { diff --git a/internal/iam/model/idp_config_view.go b/internal/iam/model/idp_config_view.go index b67e5d8a29..3d3bddc461 100644 --- a/internal/iam/model/idp_config_view.go +++ b/internal/iam/model/idp_config_view.go @@ -52,6 +52,7 @@ const ( IDPConfigSearchKeyIdpConfigID IDPConfigSearchKeyIdpProviderType IDPConfigSearchKeyInstanceID + IDPConfigSearchKeyOwnerRemoved ) type IDPConfigSearchQuery struct { diff --git a/internal/iam/model/idp_provider_view.go b/internal/iam/model/idp_provider_view.go index 0653d20fcf..c6e1b4aeab 100644 --- a/internal/iam/model/idp_provider_view.go +++ b/internal/iam/model/idp_provider_view.go @@ -37,6 +37,7 @@ const ( IDPProviderSearchKeyIdpConfigID IDPProviderSearchKeyState IDPProviderSearchKeyInstanceID + IDPProviderSearchKeyOwnerRemoved ) type IDPProviderSearchQuery struct { diff --git a/internal/iam/model/label_policy_view.go b/internal/iam/model/label_policy_view.go index 71304ea597..cdab0b44b9 100644 --- a/internal/iam/model/label_policy_view.go +++ b/internal/iam/model/label_policy_view.go @@ -49,6 +49,7 @@ const ( LabelPolicySearchKeyAggregateID LabelPolicySearchKeyState LabelPolicySearchKeyInstanceID + LabelPolicySearchKeyOwnerRemoved ) type LabelPolicySearchQuery struct { diff --git a/internal/iam/repository/view/idp_provider_view.go b/internal/iam/repository/view/idp_provider_view.go index 913038adfb..06662cb219 100644 --- a/internal/iam/repository/view/idp_provider_view.go +++ b/internal/iam/repository/view/idp_provider_view.go @@ -15,7 +15,8 @@ func GetIDPProviderByAggregateIDAndConfigID(db *gorm.DB, table, aggregateID, idp aggIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals} idpConfigIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyIdpConfigID, Value: idpConfigID, Method: domain.SearchMethodEquals} instanceIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals} - query := repository.PrepareGetByQuery(table, aggIDQuery, idpConfigIDQuery, instanceIDQuery) + ownerRemovedQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyOwnerRemoved, Value: false, Method: domain.SearchMethodEquals} + query := repository.PrepareGetByQuery(table, aggIDQuery, idpConfigIDQuery, instanceIDQuery, ownerRemovedQuery) err := query(db, policy) if caos_errs.IsNotFound(err) { return nil, caos_errs.ThrowNotFound(nil, "VIEW-Skvi8", "Errors.IAM.LoginPolicy.IDP.NotExisting") @@ -36,6 +37,11 @@ func IDPProvidersByIdpConfigID(db *gorm.DB, table, idpConfigID, instanceID strin Value: instanceID, Method: domain.SearchMethodEquals, }, + { + Key: iam_model.IDPProviderSearchKeyOwnerRemoved, + Value: false, + Method: domain.SearchMethodEquals, + }, } query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Queries: queries}) _, err := query(db, &providers) @@ -63,6 +69,11 @@ func IDPProvidersByAggregateIDAndState(db *gorm.DB, table string, aggregateID, i Value: instanceID, Method: domain.SearchMethodEquals, }, + { + Key: iam_model.IDPProviderSearchKeyOwnerRemoved, + Value: false, + Method: domain.SearchMethodEquals, + }, } query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Queries: queries}) _, err := query(db, &providers) @@ -114,6 +125,19 @@ func DeleteIDPProvidersByAggregateID(db *gorm.DB, table, aggregateID, instanceID } func DeleteInstanceIDPProviders(db *gorm.DB, table, instanceID string) error { - delete := repository.PrepareDeleteByKey(table, model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), instanceID) + delete := repository.PrepareDeleteByKey(table, + model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), + instanceID, + ) return delete(db) } + +func UpdateOrgOwnerRemovedIDPProviders(db *gorm.DB, table, instanceID, aggID string) error { + update := repository.PrepareUpdateByKeys(table, + model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyOwnerRemoved), + true, + repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), Value: instanceID}, + repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyAggregateID), Value: aggID}, + ) + return update(db) +} diff --git a/internal/iam/repository/view/idp_view.go b/internal/iam/repository/view/idp_view.go index d88a03b95a..da77a97cad 100644 --- a/internal/iam/repository/view/idp_view.go +++ b/internal/iam/repository/view/idp_view.go @@ -14,7 +14,8 @@ func IDPByID(db *gorm.DB, table, idpID, instanceID string) (*model.IDPConfigView idp := new(model.IDPConfigView) idpIDQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyIdpConfigID, Value: idpID, Method: domain.SearchMethodEquals} instanceIDQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals} - query := repository.PrepareGetByQuery(table, idpIDQuery, instanceIDQuery) + ownerRemovedQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyOwnerRemoved, Value: false, Method: domain.SearchMethodEquals} + query := repository.PrepareGetByQuery(table, idpIDQuery, instanceIDQuery, ownerRemovedQuery) err := query(db, idp) if caos_errs.IsNotFound(err) { return nil, caos_errs.ThrowNotFound(nil, "VIEW-Ahq2s", "Errors.IDP.NotExisting") @@ -34,6 +35,11 @@ func GetIDPConfigsByAggregateID(db *gorm.DB, table string, aggregateID, instance Value: instanceID, Method: domain.SearchMethodEquals, }, + { + Key: iam_model.IDPConfigSearchKeyOwnerRemoved, + Value: false, + Method: domain.SearchMethodEquals, + }, } query := repository.PrepareSearchQuery(table, model.IDPConfigSearchRequest{Queries: queries}) _, err := query(db, &idps) @@ -66,6 +72,16 @@ func DeleteIDP(db *gorm.DB, table, idpID, instanceID string) error { return delete(db) } +func UpdateOrgOwnerRemovedIDPs(db *gorm.DB, table, instanceID, aggID string) error { + update := repository.PrepareUpdateByKeys(table, + model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyOwnerRemoved), + true, + repository.Key{Key: model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), Value: instanceID}, + repository.Key{Key: model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyAggregateID), Value: aggID}, + ) + return update(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/model/idp_config.go b/internal/iam/repository/view/model/idp_config.go index cdb420de3e..a127458836 100644 --- a/internal/iam/repository/view/model/idp_config.go +++ b/internal/iam/repository/view/model/idp_config.go @@ -23,6 +23,7 @@ const ( IDPConfigKeyName = "name" IDPConfigKeyProviderType = "idp_provider_type" IDPConfigKeyInstanceID = "instance_id" + IDPConfigKeyOwnerRemoved = "owner_removed" ) type IDPConfigView struct { diff --git a/internal/iam/repository/view/model/idp_config_query.go b/internal/iam/repository/view/model/idp_config_query.go index 5a2958a0d2..5f07ecfcee 100644 --- a/internal/iam/repository/view/model/idp_config_query.go +++ b/internal/iam/repository/view/model/idp_config_query.go @@ -61,6 +61,8 @@ func (key IDPConfigSearchKey) ToColumnName() string { return IDPConfigKeyProviderType case iam_model.IDPConfigSearchKeyInstanceID: return IDPConfigKeyInstanceID + case iam_model.IDPConfigSearchKeyOwnerRemoved: + return IDPConfigKeyOwnerRemoved default: return "" } diff --git a/internal/iam/repository/view/model/idp_provider.go b/internal/iam/repository/view/model/idp_provider.go index 82d73b96ca..9bb0481f71 100644 --- a/internal/iam/repository/view/model/idp_provider.go +++ b/internal/iam/repository/view/model/idp_provider.go @@ -15,10 +15,11 @@ import ( ) const ( - IDPProviderKeyAggregateID = "aggregate_id" - IDPProviderKeyIdpConfigID = "idp_config_id" - IDPProviderKeyState = "idp_state" - IDPProviderKeyInstanceID = "instance_id" + IDPProviderKeyAggregateID = "aggregate_id" + IDPProviderKeyIdpConfigID = "idp_config_id" + IDPProviderKeyState = "idp_state" + IDPProviderKeyInstanceID = "instance_id" + IDPProviderKeyOwnerRemoved = "owner_removed" ) type IDPProviderView struct { diff --git a/internal/iam/repository/view/model/idp_provider_query.go b/internal/iam/repository/view/model/idp_provider_query.go index 031b53d08a..9685507c1b 100644 --- a/internal/iam/repository/view/model/idp_provider_query.go +++ b/internal/iam/repository/view/model/idp_provider_query.go @@ -59,6 +59,8 @@ func (key IDPProviderSearchKey) ToColumnName() string { return IDPProviderKeyState case iam_model.IDPProviderSearchKeyInstanceID: return IDPProviderKeyInstanceID + case iam_model.IDPProviderSearchKeyOwnerRemoved: + return IDPProviderKeyOwnerRemoved default: return "" } diff --git a/internal/iam/repository/view/model/label_policy.go b/internal/iam/repository/view/model/label_policy.go index 207ccf10b1..e257e3399e 100644 --- a/internal/iam/repository/view/model/label_policy.go +++ b/internal/iam/repository/view/model/label_policy.go @@ -15,9 +15,10 @@ import ( ) const ( - LabelPolicyKeyAggregateID = "aggregate_id" - LabelPolicyKeyState = "label_policy_state" - LabelPolicyKeyInstanceID = "instance_id" + LabelPolicyKeyAggregateID = "aggregate_id" + LabelPolicyKeyState = "label_policy_state" + LabelPolicyKeyInstanceID = "instance_id" + LabelPolicyKeyOwnerRemoved = "owner_removed" ) type LabelPolicyView struct { diff --git a/internal/iam/repository/view/model/label_policy_query.go b/internal/iam/repository/view/model/label_policy_query.go index 555ff198ad..1c21d39be1 100644 --- a/internal/iam/repository/view/model/label_policy_query.go +++ b/internal/iam/repository/view/model/label_policy_query.go @@ -57,6 +57,8 @@ func (key LabelPolicySearchKey) ToColumnName() string { return LabelPolicyKeyState case iam_model.LabelPolicySearchKeyInstanceID: return LabelPolicyKeyInstanceID + case iam_model.LabelPolicySearchKeyOwnerRemoved: + return LabelPolicyKeyOwnerRemoved default: return "" diff --git a/internal/iam/repository/view/styling.go b/internal/iam/repository/view/styling.go index 2d337717b0..fe1426893a 100644 --- a/internal/iam/repository/view/styling.go +++ b/internal/iam/repository/view/styling.go @@ -15,7 +15,8 @@ func GetStylingByAggregateIDAndState(db *gorm.DB, table, aggregateID, instanceID aggregateIDQuery := &model.LabelPolicySearchQuery{Key: iam_model.LabelPolicySearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals} stateQuery := &model.LabelPolicySearchQuery{Key: iam_model.LabelPolicySearchKeyState, Value: state, Method: domain.SearchMethodEquals} instanceIDQuery := &model.LabelPolicySearchQuery{Key: iam_model.LabelPolicySearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals} - query := repository.PrepareGetByQuery(table, aggregateIDQuery, stateQuery, instanceIDQuery) + ownerRemovedQuery := &model.LabelPolicySearchQuery{Key: iam_model.LabelPolicySearchKeyOwnerRemoved, Value: false, Method: domain.SearchMethodEquals} + query := repository.PrepareGetByQuery(table, aggregateIDQuery, stateQuery, instanceIDQuery, ownerRemovedQuery) err := query(db, policy) if caos_errs.IsNotFound(err) { return nil, caos_errs.ThrowNotFound(nil, "VIEW-68G11", "Errors.IAM.LabelPolicy.NotExisting") @@ -28,6 +29,16 @@ func PutStyling(db *gorm.DB, table string, policy *model.LabelPolicyView) error return save(db, policy) } +func UpdateOrgOwnerRemovedStyling(db *gorm.DB, table, instanceID, aggID string) error { + update := repository.PrepareUpdateByKeys(table, + model.LabelPolicySearchKey(iam_model.LabelPolicySearchKeyOwnerRemoved), + true, + repository.Key{Key: model.LabelPolicySearchKey(iam_model.LabelPolicySearchKeyInstanceID), Value: instanceID}, + repository.Key{Key: model.LabelPolicySearchKey(iam_model.LabelPolicySearchKeyAggregateID), Value: aggID}, + ) + return update(db) +} + 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/notification/projection.go b/internal/notification/projection.go index cbdd9de682..5080e5aa9f 100644 --- a/internal/notification/projection.go +++ b/internal/notification/projection.go @@ -161,17 +161,17 @@ func (p *notificationsProjection) reduceInitCodeAdded(event eventstore.Event) (* if err != nil { return nil, err } - colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner) + colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner, false) if err != nil { return nil, err } - template, err := p.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner) + template, err := p.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner, false) if err != nil { return nil, err } - notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID) + notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID, false) if err != nil { return nil, err } @@ -224,17 +224,17 @@ func (p *notificationsProjection) reduceEmailCodeAdded(event eventstore.Event) ( if err != nil { return nil, err } - colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner) + colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner, false) if err != nil { return nil, err } - template, err := p.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner) + template, err := p.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner, false) if err != nil { return nil, err } - notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID) + notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID, false) if err != nil { return nil, err } @@ -287,17 +287,17 @@ func (p *notificationsProjection) reducePasswordCodeAdded(event eventstore.Event if err != nil { return nil, err } - colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner) + colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner, false) if err != nil { return nil, err } - template, err := p.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner) + template, err := p.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner, false) if err != nil { return nil, err } - notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID) + notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID, false) if err != nil { return nil, err } @@ -358,17 +358,17 @@ func (p *notificationsProjection) reduceDomainClaimed(event eventstore.Event) (* if alreadyHandled { return crdb.NewNoOpStatement(e), nil } - colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner) + colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner, false) if err != nil { return nil, err } - template, err := p.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner) + template, err := p.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner, false) if err != nil { return nil, err } - notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID) + notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID, false) if err != nil { return nil, err } @@ -419,17 +419,17 @@ func (p *notificationsProjection) reducePasswordlessCodeRequested(event eventsto if err != nil { return nil, err } - colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner) + colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner, false) if err != nil { return nil, err } - template, err := p.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner) + template, err := p.queries.MailTemplateByOrg(ctx, e.Aggregate().ResourceOwner, false) if err != nil { return nil, err } - notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID) + notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID, false) if err != nil { return nil, err } @@ -482,12 +482,12 @@ func (p *notificationsProjection) reducePhoneCodeAdded(event eventstore.Event) ( if err != nil { return nil, err } - colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner) + colors, err := p.queries.ActiveLabelPolicyByOrg(ctx, e.Aggregate().ResourceOwner, false) if err != nil { return nil, err } - notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID) + notifyUser, err := p.queries.GetNotifyUserByID(ctx, true, e.Aggregate().ID, false) if err != nil { return nil, err } @@ -619,11 +619,11 @@ func (p *notificationsProjection) getTranslatorWithOrgTexts(ctx context.Context, return nil, err } - allCustomTexts, err := p.queries.CustomTextListByTemplate(ctx, authz.GetInstance(ctx).InstanceID(), textType) + allCustomTexts, err := p.queries.CustomTextListByTemplate(ctx, authz.GetInstance(ctx).InstanceID(), textType, false) if err != nil { return translator, nil } - customTexts, err := p.queries.CustomTextListByTemplate(ctx, orgID, textType) + customTexts, err := p.queries.CustomTextListByTemplate(ctx, orgID, textType, false) if err != nil { return translator, nil } diff --git a/internal/project/model/org_project_mapping_view.go b/internal/project/model/org_project_mapping_view.go index 07a4d851c9..e744285533 100644 --- a/internal/project/model/org_project_mapping_view.go +++ b/internal/project/model/org_project_mapping_view.go @@ -27,6 +27,7 @@ const ( OrgProjectMappingSearchKeyOrgID OrgProjectMappingSearchKeyProjectGrantID OrgProjectMappingSearchKeyInstanceID + OrgProjectMappingSearchKeyOwnerRemoved ) type OrgProjectMappingViewSearchQuery struct { diff --git a/internal/project/repository/view/model/org_project_mapping.go b/internal/project/repository/view/model/org_project_mapping.go index e4de47725e..929725cce5 100644 --- a/internal/project/repository/view/model/org_project_mapping.go +++ b/internal/project/repository/view/model/org_project_mapping.go @@ -5,6 +5,7 @@ const ( OrgProjectMappingKeyOrgID = "org_id" OrgProjectMappingKeyProjectGrantID = "project_grant_id" OrgProjectMappingKeyInstanceID = "instance_id" + OrgProjectMappingOwnerRemoved = "owner_removed" ) type OrgProjectMapping struct { diff --git a/internal/project/repository/view/model/org_project_mapping_query.go b/internal/project/repository/view/model/org_project_mapping_query.go index 90807b9692..9587579336 100644 --- a/internal/project/repository/view/model/org_project_mapping_query.go +++ b/internal/project/repository/view/model/org_project_mapping_query.go @@ -59,6 +59,8 @@ func (key OrgProjectMappingSearchKey) ToColumnName() string { return OrgProjectMappingKeyProjectGrantID case proj_model.OrgProjectMappingSearchKeyInstanceID: return OrgProjectMappingKeyInstanceID + case proj_model.OrgProjectMappingSearchKeyOwnerRemoved: + return OrgProjectMappingOwnerRemoved default: return "" } diff --git a/internal/project/repository/view/org_project_mapping_view.go b/internal/project/repository/view/org_project_mapping_view.go index ac4299461f..b75a7f13dd 100644 --- a/internal/project/repository/view/org_project_mapping_view.go +++ b/internal/project/repository/view/org_project_mapping_view.go @@ -16,7 +16,8 @@ func OrgProjectMappingByIDs(db *gorm.DB, table, orgID, projectID, instanceID str projectIDQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyProjectID, Value: projectID, Method: domain.SearchMethodEquals} orgIDQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyOrgID, Value: orgID, Method: domain.SearchMethodEquals} instanceIDQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals} - query := repository.PrepareGetByQuery(table, projectIDQuery, orgIDQuery, instanceIDQuery) + ownerRemovedQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyOwnerRemoved, Value: false, Method: domain.SearchMethodEquals} + query := repository.PrepareGetByQuery(table, projectIDQuery, orgIDQuery, instanceIDQuery, ownerRemovedQuery) err := query(db, orgProjectMapping) if caos_errs.IsNotFound(err) { return nil, caos_errs.ThrowNotFound(nil, "VIEW-fn9fs", "Errors.OrgProjectMapping.NotExisting") @@ -42,6 +43,16 @@ func DeleteInstanceOrgProjectMappings(db *gorm.DB, table, instanceID string) err return delete(db) } +func UpdateOwnerRemovedOrgProjectMappings(db *gorm.DB, table, instanceID, orgID string) error { + update := repository.PrepareUpdateByKeys(table, + model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyOwnerRemoved), + true, + repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyInstanceID), Value: instanceID}, + repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyOrgID), Value: orgID}, + ) + return update(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/action.go b/internal/query/action.go index d0d7ad9ac8..0aba5b6898 100644 --- a/internal/query/action.go +++ b/internal/query/action.go @@ -67,6 +67,10 @@ var ( name: projection.ActionAllowedToFailCol, table: actionTable, } + ActionColumnOwnerRemoved = Column{ + name: projection.ActionOwnerRemovedCol, + table: actionTable, + } ) type Actions struct { @@ -108,13 +112,15 @@ func (q *ActionSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder { return query } -func (q *Queries) SearchActions(ctx context.Context, queries *ActionSearchQueries) (actions *Actions, err error) { +func (q *Queries) SearchActions(ctx context.Context, queries *ActionSearchQueries, withOwnerRemoved bool) (actions *Actions, err error) { query, scan := prepareActionsQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - ActionColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }). - ToSql() + eq := sq.Eq{ + ActionColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[ActionColumnOwnerRemoved.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-SDgwg", "Errors.Query.InvalidRequest") } @@ -131,14 +137,17 @@ func (q *Queries) SearchActions(ctx context.Context, queries *ActionSearchQuerie return actions, err } -func (q *Queries) GetActionByID(ctx context.Context, id string, orgID string) (*Action, error) { +func (q *Queries) GetActionByID(ctx context.Context, id string, orgID string, withOwnerRemoved bool) (*Action, error) { stmt, scan := prepareActionQuery() - query, args, err := stmt.Where( - sq.Eq{ - ActionColumnID.identifier(): id, - ActionColumnResourceOwner.identifier(): orgID, - ActionColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{ + ActionColumnID.identifier(): id, + ActionColumnResourceOwner.identifier(): orgID, + ActionColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[ActionColumnOwnerRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dgff3", "Errors.Query.SQLStatement") } diff --git a/internal/query/action_flow.go b/internal/query/action_flow.go index b2b7109f9a..3313750e81 100644 --- a/internal/query/action_flow.go +++ b/internal/query/action_flow.go @@ -50,6 +50,10 @@ var ( name: projection.FlowActionIDCol, table: flowsTriggersTable, } + FlowsTriggersOwnerRemovedCol = Column{ + name: projection.FlowOwnerRemovedCol, + table: flowsTriggersTable, + } ) type Flow struct { @@ -61,14 +65,17 @@ type Flow struct { TriggerActions map[domain.TriggerType][]*Action } -func (q *Queries) GetFlow(ctx context.Context, flowType domain.FlowType, orgID string) (*Flow, error) { +func (q *Queries) GetFlow(ctx context.Context, flowType domain.FlowType, orgID string, withOwnerRemoved bool) (*Flow, error) { query, scan := prepareFlowQuery(flowType) - stmt, args, err := query.Where( - sq.Eq{ - FlowsTriggersColumnFlowType.identifier(): flowType, - FlowsTriggersColumnResourceOwner.identifier(): orgID, - FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{ + FlowsTriggersColumnFlowType.identifier(): flowType, + FlowsTriggersColumnResourceOwner.identifier(): orgID, + FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[FlowsTriggersOwnerRemovedCol.identifier()] = false + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-HBRh3", "Errors.Query.InvalidRequest") } @@ -80,17 +87,19 @@ func (q *Queries) GetFlow(ctx context.Context, flowType domain.FlowType, orgID s return scan(rows) } -func (q *Queries) GetActiveActionsByFlowAndTriggerType(ctx context.Context, flowType domain.FlowType, triggerType domain.TriggerType, orgID string) ([]*Action, error) { +func (q *Queries) GetActiveActionsByFlowAndTriggerType(ctx context.Context, flowType domain.FlowType, triggerType domain.TriggerType, orgID string, withOwnerRemoved bool) ([]*Action, error) { stmt, scan := prepareTriggerActionsQuery() - query, args, err := stmt.Where( - sq.Eq{ - FlowsTriggersColumnFlowType.identifier(): flowType, - FlowsTriggersColumnTriggerType.identifier(): triggerType, - FlowsTriggersColumnResourceOwner.identifier(): orgID, - FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - ActionColumnState.identifier(): domain.ActionStateActive, - }, - ).ToSql() + eq := sq.Eq{ + FlowsTriggersColumnFlowType.identifier(): flowType, + FlowsTriggersColumnTriggerType.identifier(): triggerType, + FlowsTriggersColumnResourceOwner.identifier(): orgID, + FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + ActionColumnState.identifier(): domain.ActionStateActive, + } + if !withOwnerRemoved { + eq[FlowsTriggersOwnerRemovedCol.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dgff3", "Errors.Query.SQLStatement") } @@ -102,14 +111,16 @@ func (q *Queries) GetActiveActionsByFlowAndTriggerType(ctx context.Context, flow return scan(rows) } -func (q *Queries) GetFlowTypesOfActionID(ctx context.Context, actionID string) ([]domain.FlowType, error) { +func (q *Queries) GetFlowTypesOfActionID(ctx context.Context, actionID string, withOwnerRemoved bool) ([]domain.FlowType, error) { stmt, scan := prepareFlowTypesQuery() - query, args, err := stmt.Where( - sq.Eq{ - FlowsTriggersColumnActionID.identifier(): actionID, - FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ).ToSql() + eq := sq.Eq{ + FlowsTriggersColumnActionID.identifier(): actionID, + FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[FlowsTriggersOwnerRemovedCol.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-Dh311", "Errors.Query.InvalidRequest") } diff --git a/internal/query/action_flow_test.go b/internal/query/action_flow_test.go index 132351339e..4f1caf8b9e 100644 --- a/internal/query/action_flow_test.go +++ b/internal/query/action_flow_test.go @@ -32,24 +32,24 @@ func Test_FlowPrepares(t *testing.T) { }, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.allowed_to_fail,`+ - ` projections.actions2.timeout,`+ - ` projections.flows_triggers.trigger_type,`+ - ` projections.flows_triggers.trigger_sequence,`+ - ` projections.flows_triggers.flow_type,`+ - ` projections.flows_triggers.change_date,`+ - ` projections.flows_triggers.sequence,`+ - ` projections.flows_triggers.resource_owner`+ - ` FROM projections.flows_triggers`+ - ` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.allowed_to_fail,`+ + ` projections.actions3.timeout,`+ + ` projections.flow_triggers2.trigger_type,`+ + ` projections.flow_triggers2.trigger_sequence,`+ + ` projections.flow_triggers2.flow_type,`+ + ` projections.flow_triggers2.change_date,`+ + ` projections.flow_triggers2.sequence,`+ + ` projections.flow_triggers2.resource_owner`+ + ` FROM projections.flow_triggers2`+ + ` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`), nil, nil, ), @@ -66,24 +66,24 @@ func Test_FlowPrepares(t *testing.T) { }, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.allowed_to_fail,`+ - ` projections.actions2.timeout,`+ - ` projections.flows_triggers.trigger_type,`+ - ` projections.flows_triggers.trigger_sequence,`+ - ` projections.flows_triggers.flow_type,`+ - ` projections.flows_triggers.change_date,`+ - ` projections.flows_triggers.sequence,`+ - ` projections.flows_triggers.resource_owner`+ - ` FROM projections.flows_triggers`+ - ` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.allowed_to_fail,`+ + ` projections.actions3.timeout,`+ + ` projections.flow_triggers2.trigger_type,`+ + ` projections.flow_triggers2.trigger_sequence,`+ + ` projections.flow_triggers2.flow_type,`+ + ` projections.flow_triggers2.change_date,`+ + ` projections.flow_triggers2.sequence,`+ + ` projections.flow_triggers2.resource_owner`+ + ` FROM projections.flow_triggers2`+ + ` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`), []string{ "id", "creation_date", @@ -155,24 +155,24 @@ func Test_FlowPrepares(t *testing.T) { }, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.allowed_to_fail,`+ - ` projections.actions2.timeout,`+ - ` projections.flows_triggers.trigger_type,`+ - ` projections.flows_triggers.trigger_sequence,`+ - ` projections.flows_triggers.flow_type,`+ - ` projections.flows_triggers.change_date,`+ - ` projections.flows_triggers.sequence,`+ - ` projections.flows_triggers.resource_owner`+ - ` FROM projections.flows_triggers`+ - ` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.allowed_to_fail,`+ + ` projections.actions3.timeout,`+ + ` projections.flow_triggers2.trigger_type,`+ + ` projections.flow_triggers2.trigger_sequence,`+ + ` projections.flow_triggers2.flow_type,`+ + ` projections.flow_triggers2.change_date,`+ + ` projections.flow_triggers2.sequence,`+ + ` projections.flow_triggers2.resource_owner`+ + ` FROM projections.flow_triggers2`+ + ` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`), []string{ "id", "creation_date", @@ -276,24 +276,24 @@ func Test_FlowPrepares(t *testing.T) { }, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.allowed_to_fail,`+ - ` projections.actions2.timeout,`+ - ` projections.flows_triggers.trigger_type,`+ - ` projections.flows_triggers.trigger_sequence,`+ - ` projections.flows_triggers.flow_type,`+ - ` projections.flows_triggers.change_date,`+ - ` projections.flows_triggers.sequence,`+ - ` projections.flows_triggers.resource_owner`+ - ` FROM projections.flows_triggers`+ - ` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.allowed_to_fail,`+ + ` projections.actions3.timeout,`+ + ` projections.flow_triggers2.trigger_type,`+ + ` projections.flow_triggers2.trigger_sequence,`+ + ` projections.flow_triggers2.flow_type,`+ + ` projections.flow_triggers2.change_date,`+ + ` projections.flow_triggers2.sequence,`+ + ` projections.flow_triggers2.resource_owner`+ + ` FROM projections.flow_triggers2`+ + ` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`), []string{ "id", "creation_date", @@ -350,24 +350,24 @@ func Test_FlowPrepares(t *testing.T) { }, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.allowed_to_fail,`+ - ` projections.actions2.timeout,`+ - ` projections.flows_triggers.trigger_type,`+ - ` projections.flows_triggers.trigger_sequence,`+ - ` projections.flows_triggers.flow_type,`+ - ` projections.flows_triggers.change_date,`+ - ` projections.flows_triggers.sequence,`+ - ` projections.flows_triggers.resource_owner`+ - ` FROM projections.flows_triggers`+ - ` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.allowed_to_fail,`+ + ` projections.actions3.timeout,`+ + ` projections.flow_triggers2.trigger_type,`+ + ` projections.flow_triggers2.trigger_sequence,`+ + ` projections.flow_triggers2.flow_type,`+ + ` projections.flow_triggers2.change_date,`+ + ` projections.flow_triggers2.sequence,`+ + ` projections.flow_triggers2.resource_owner`+ + ` FROM projections.flow_triggers2`+ + ` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`), sql.ErrConnDone, ), err: func(err error) (error, bool) { @@ -384,18 +384,18 @@ func Test_FlowPrepares(t *testing.T) { prepare: prepareTriggerActionsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.allowed_to_fail,`+ - ` projections.actions2.timeout`+ - ` FROM projections.flows_triggers`+ - ` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.allowed_to_fail,`+ + ` projections.actions3.timeout`+ + ` FROM projections.flow_triggers2`+ + ` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`), nil, nil, ), @@ -407,18 +407,18 @@ func Test_FlowPrepares(t *testing.T) { prepare: prepareTriggerActionsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.allowed_to_fail,`+ - ` projections.actions2.timeout`+ - ` FROM projections.flows_triggers`+ - ` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.allowed_to_fail,`+ + ` projections.actions3.timeout`+ + ` FROM projections.flow_triggers2`+ + ` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`), []string{ "id", "creation_date", @@ -467,18 +467,18 @@ func Test_FlowPrepares(t *testing.T) { prepare: prepareTriggerActionsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.allowed_to_fail,`+ - ` projections.actions2.timeout`+ - ` FROM projections.flows_triggers`+ - ` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.allowed_to_fail,`+ + ` projections.actions3.timeout`+ + ` FROM projections.flow_triggers2`+ + ` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`), []string{ "id", "creation_date", @@ -551,18 +551,18 @@ func Test_FlowPrepares(t *testing.T) { prepare: prepareTriggerActionsQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.allowed_to_fail,`+ - ` projections.actions2.timeout`+ - ` FROM projections.flows_triggers`+ - ` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.allowed_to_fail,`+ + ` projections.actions3.timeout`+ + ` FROM projections.flow_triggers2`+ + ` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`), sql.ErrConnDone, ), err: func(err error) (error, bool) { @@ -579,8 +579,8 @@ func Test_FlowPrepares(t *testing.T) { prepare: prepareFlowTypesQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.flows_triggers.flow_type`+ - ` FROM projections.flows_triggers`), + regexp.QuoteMeta(`SELECT projections.flow_triggers2.flow_type`+ + ` FROM projections.flow_triggers2`), nil, nil, ), @@ -592,8 +592,8 @@ func Test_FlowPrepares(t *testing.T) { prepare: prepareFlowTypesQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.flows_triggers.flow_type`+ - ` FROM projections.flows_triggers`), + regexp.QuoteMeta(`SELECT projections.flow_triggers2.flow_type`+ + ` FROM projections.flow_triggers2`), []string{ "flow_type", }, @@ -613,8 +613,8 @@ func Test_FlowPrepares(t *testing.T) { prepare: prepareFlowTypesQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.flows_triggers.flow_type`+ - ` FROM projections.flows_triggers`), + regexp.QuoteMeta(`SELECT projections.flow_triggers2.flow_type`+ + ` FROM projections.flow_triggers2`), []string{ "flow_type", }, @@ -638,8 +638,8 @@ func Test_FlowPrepares(t *testing.T) { prepare: prepareFlowTypesQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.flows_triggers.flow_type`+ - ` FROM projections.flows_triggers`), + regexp.QuoteMeta(`SELECT projections.flow_triggers2.flow_type`+ + ` FROM projections.flow_triggers2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/action_test.go b/internal/query/action_test.go index dd7204e9e6..c75c5311b3 100644 --- a/internal/query/action_test.go +++ b/internal/query/action_test.go @@ -29,18 +29,18 @@ func Test_ActionPrepares(t *testing.T) { prepare: prepareActionsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.timeout,`+ - ` projections.actions2.allowed_to_fail,`+ + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.timeout,`+ + ` projections.actions3.allowed_to_fail,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.actions2`), + ` FROM projections.actions3`), nil, nil, ), @@ -52,18 +52,18 @@ func Test_ActionPrepares(t *testing.T) { prepare: prepareActionsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.timeout,`+ - ` projections.actions2.allowed_to_fail,`+ + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.timeout,`+ + ` projections.actions3.allowed_to_fail,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.actions2`), + ` FROM projections.actions3`), []string{ "id", "creation_date", @@ -118,18 +118,18 @@ func Test_ActionPrepares(t *testing.T) { prepare: prepareActionsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.timeout,`+ - ` projections.actions2.allowed_to_fail,`+ + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.timeout,`+ + ` projections.actions3.allowed_to_fail,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.actions2`), + ` FROM projections.actions3`), []string{ "id", "creation_date", @@ -208,18 +208,18 @@ func Test_ActionPrepares(t *testing.T) { prepare: prepareActionsQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.timeout,`+ - ` projections.actions2.allowed_to_fail,`+ + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.timeout,`+ + ` projections.actions3.allowed_to_fail,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.actions2`), + ` FROM projections.actions3`), sql.ErrConnDone, ), err: func(err error) (error, bool) { @@ -236,17 +236,17 @@ func Test_ActionPrepares(t *testing.T) { prepare: prepareActionQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.timeout,`+ - ` projections.actions2.allowed_to_fail`+ - ` FROM projections.actions2`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.timeout,`+ + ` projections.actions3.allowed_to_fail`+ + ` FROM projections.actions3`), nil, nil, ), @@ -264,17 +264,17 @@ func Test_ActionPrepares(t *testing.T) { prepare: prepareActionQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.timeout,`+ - ` projections.actions2.allowed_to_fail`+ - ` FROM projections.actions2`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.timeout,`+ + ` projections.actions3.allowed_to_fail`+ + ` FROM projections.actions3`), []string{ "id", "creation_date", @@ -319,17 +319,17 @@ func Test_ActionPrepares(t *testing.T) { prepare: prepareActionQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.actions2.id,`+ - ` projections.actions2.creation_date,`+ - ` projections.actions2.change_date,`+ - ` projections.actions2.resource_owner,`+ - ` projections.actions2.sequence,`+ - ` projections.actions2.action_state,`+ - ` projections.actions2.name,`+ - ` projections.actions2.script,`+ - ` projections.actions2.timeout,`+ - ` projections.actions2.allowed_to_fail`+ - ` FROM projections.actions2`), + regexp.QuoteMeta(`SELECT projections.actions3.id,`+ + ` projections.actions3.creation_date,`+ + ` projections.actions3.change_date,`+ + ` projections.actions3.resource_owner,`+ + ` projections.actions3.sequence,`+ + ` projections.actions3.action_state,`+ + ` projections.actions3.name,`+ + ` projections.actions3.script,`+ + ` projections.actions3.timeout,`+ + ` projections.actions3.allowed_to_fail`+ + ` FROM projections.actions3`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/app.go b/internal/query/app.go index c5bb8e39f3..8b58a9d351 100644 --- a/internal/query/app.go +++ b/internal/query/app.go @@ -122,6 +122,10 @@ var ( name: projection.AppColumnSequence, table: appsTable, } + AppColumnOwnerRemoved = Column{ + name: projection.AppColumnOwnerRemoved, + table: appsTable, + } ) var ( @@ -237,19 +241,21 @@ var ( } ) -func (q *Queries) AppByProjectAndAppID(ctx context.Context, shouldTriggerBulk bool, projectID, appID string) (*App, error) { +func (q *Queries) AppByProjectAndAppID(ctx context.Context, shouldTriggerBulk bool, projectID, appID string, withOwnerRemoved bool) (*App, error) { if shouldTriggerBulk { projection.AppProjection.Trigger(ctx) } stmt, scan := prepareAppQuery() - query, args, err := stmt.Where( - sq.Eq{ - AppColumnID.identifier(): appID, - AppColumnProjectID.identifier(): projectID, - AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ).ToSql() + eq := sq.Eq{ + AppColumnID.identifier(): appID, + AppColumnProjectID.identifier(): projectID, + AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[AppColumnOwnerRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-AFDgg", "Errors.Query.SQLStatement") } @@ -258,14 +264,16 @@ func (q *Queries) AppByProjectAndAppID(ctx context.Context, shouldTriggerBulk bo return scan(row) } -func (q *Queries) AppByID(ctx context.Context, appID string) (*App, error) { +func (q *Queries) AppByID(ctx context.Context, appID string, withOwnerRemoved bool) (*App, error) { stmt, scan := prepareAppQuery() - query, args, err := stmt.Where( - sq.Eq{ - AppColumnID.identifier(): appID, - AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ).ToSql() + eq := sq.Eq{ + AppColumnID.identifier(): appID, + AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[AppColumnOwnerRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-immt9", "Errors.Query.SQLStatement") } @@ -274,14 +282,16 @@ func (q *Queries) AppByID(ctx context.Context, appID string) (*App, error) { return scan(row) } -func (q *Queries) AppBySAMLEntityID(ctx context.Context, entityID string) (*App, error) { +func (q *Queries) AppBySAMLEntityID(ctx context.Context, entityID string, withOwnerRemoved bool) (*App, error) { stmt, scan := prepareAppQuery() - query, args, err := stmt.Where( - sq.Eq{ - AppSAMLConfigColumnEntityID.identifier(): entityID, - AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ).ToSql() + eq := sq.Eq{ + AppSAMLConfigColumnEntityID.identifier(): entityID, + AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[AppColumnOwnerRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-JgUop", "Errors.Query.SQLStatement") } @@ -290,18 +300,20 @@ func (q *Queries) AppBySAMLEntityID(ctx context.Context, entityID string) (*App, return scan(row) } -func (q *Queries) ProjectByClientID(ctx context.Context, appID string) (*Project, error) { +func (q *Queries) ProjectByClientID(ctx context.Context, appID string, withOwnerRemoved bool) (*Project, error) { stmt, scan := prepareProjectByAppQuery() - query, args, err := stmt.Where( - sq.And{ - sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, - sq.Or{ - sq.Eq{AppOIDCConfigColumnClientID.identifier(): appID}, - sq.Eq{AppAPIConfigColumnClientID.identifier(): appID}, - sq.Eq{AppSAMLConfigColumnAppID.identifier(): appID}, - }, + eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[ProjectColumnOwnerRemoved.identifier()] = false + } + query, args, err := stmt.Where(sq.And{ + eq, + sq.Or{ + sq.Eq{AppOIDCConfigColumnClientID.identifier(): appID}, + sq.Eq{AppAPIConfigColumnClientID.identifier(): appID}, + sq.Eq{AppSAMLConfigColumnAppID.identifier(): appID}, }, - ).ToSql() + }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-XhJi3", "Errors.Query.SQLStatement") } @@ -310,14 +322,16 @@ func (q *Queries) ProjectByClientID(ctx context.Context, appID string) (*Project return scan(row) } -func (q *Queries) ProjectIDFromOIDCClientID(ctx context.Context, appID string) (string, error) { +func (q *Queries) ProjectIDFromOIDCClientID(ctx context.Context, appID string, withOwnerRemoved bool) (string, error) { stmt, scan := prepareProjectIDByAppQuery() - query, args, err := stmt.Where( - sq.Eq{ - AppOIDCConfigColumnClientID.identifier(): appID, - AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ).ToSql() + eq := sq.Eq{ + AppOIDCConfigColumnClientID.identifier(): appID, + AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[AppColumnOwnerRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return "", errors.ThrowInternal(err, "QUERY-7d92U", "Errors.Query.SQLStatement") } @@ -326,18 +340,21 @@ func (q *Queries) ProjectIDFromOIDCClientID(ctx context.Context, appID string) ( return scan(row) } -func (q *Queries) ProjectIDFromClientID(ctx context.Context, appID string) (string, error) { +func (q *Queries) ProjectIDFromClientID(ctx context.Context, appID string, withOwnerRemoved bool) (string, error) { stmt, scan := prepareProjectIDByAppQuery() - query, args, err := stmt.Where( - sq.And{ - sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, - sq.Or{ - sq.Eq{AppOIDCConfigColumnClientID.identifier(): appID}, - sq.Eq{AppAPIConfigColumnClientID.identifier(): appID}, - sq.Eq{AppSAMLConfigColumnAppID.identifier(): appID}, - }, + eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[AppColumnOwnerRemoved.identifier()] = false + } + where := sq.And{ + eq, + sq.Or{ + sq.Eq{AppOIDCConfigColumnClientID.identifier(): appID}, + sq.Eq{AppAPIConfigColumnClientID.identifier(): appID}, + sq.Eq{AppSAMLConfigColumnAppID.identifier(): appID}, }, - ).ToSql() + } + query, args, err := stmt.Where(where).ToSql() if err != nil { return "", errors.ThrowInternal(err, "QUERY-SDfg3", "Errors.Query.SQLStatement") } @@ -346,14 +363,16 @@ func (q *Queries) ProjectIDFromClientID(ctx context.Context, appID string) (stri return scan(row) } -func (q *Queries) ProjectByOIDCClientID(ctx context.Context, id string) (*Project, error) { +func (q *Queries) ProjectByOIDCClientID(ctx context.Context, id string, withOwnerRemoved bool) (*Project, error) { stmt, scan := prepareProjectByAppQuery() - query, args, err := stmt.Where( - sq.Eq{ - AppOIDCConfigColumnClientID.identifier(): id, - AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ).ToSql() + eq := sq.Eq{ + AppOIDCConfigColumnClientID.identifier(): id, + AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[AppColumnOwnerRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-XhJi4", "Errors.Query.SQLStatement") } @@ -362,14 +381,16 @@ func (q *Queries) ProjectByOIDCClientID(ctx context.Context, id string) (*Projec return scan(row) } -func (q *Queries) AppByOIDCClientID(ctx context.Context, clientID string) (*App, error) { +func (q *Queries) AppByOIDCClientID(ctx context.Context, clientID string, withOwnerRemoved bool) (*App, error) { stmt, scan := prepareAppQuery() - query, args, err := stmt.Where( - sq.Eq{ - AppOIDCConfigColumnClientID.identifier(): clientID, - AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ).ToSql() + eq := sq.Eq{ + AppOIDCConfigColumnClientID.identifier(): clientID, + AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[AppColumnOwnerRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-JgVop", "Errors.Query.SQLStatement") } @@ -378,17 +399,20 @@ func (q *Queries) AppByOIDCClientID(ctx context.Context, clientID string) (*App, return scan(row) } -func (q *Queries) AppByClientID(ctx context.Context, clientID string) (*App, error) { +func (q *Queries) AppByClientID(ctx context.Context, clientID string, withOwnerRemoved bool) (*App, error) { stmt, scan := prepareAppQuery() - query, args, err := stmt.Where( - sq.And{ - sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, - sq.Or{ - sq.Eq{AppOIDCConfigColumnClientID.identifier(): clientID}, - sq.Eq{AppAPIConfigColumnClientID.identifier(): clientID}, - }, + var eq []sq.Sqlizer + eq = append(eq, sq.And{ + sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, + sq.Or{ + sq.Eq{AppOIDCConfigColumnClientID.identifier(): clientID}, + sq.Eq{AppAPIConfigColumnClientID.identifier(): clientID}, }, - ).ToSql() + }) + if !withOwnerRemoved { + eq = append(eq, sq.Eq{AppColumnOwnerRemoved.identifier(): false}) + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dfge2", "Errors.Query.SQLStatement") } @@ -397,12 +421,13 @@ func (q *Queries) AppByClientID(ctx context.Context, clientID string) (*App, err return scan(row) } -func (q *Queries) SearchApps(ctx context.Context, queries *AppSearchQueries) (*Apps, error) { +func (q *Queries) SearchApps(ctx context.Context, queries *AppSearchQueries, withOwnerRemoved bool) (*Apps, error) { query, scan := prepareAppsQuery() - stmt, args, err := queries.toQuery(query). - Where( - sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, - ).ToSql() + eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[AppColumnOwnerRemoved.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-fajp8", "Errors.Query.InvalidRequest") } @@ -419,12 +444,13 @@ func (q *Queries) SearchApps(ctx context.Context, queries *AppSearchQueries) (*A return apps, err } -func (q *Queries) SearchClientIDs(ctx context.Context, queries *AppSearchQueries) ([]string, error) { +func (q *Queries) SearchClientIDs(ctx context.Context, queries *AppSearchQueries, withOwnerRemoved bool) ([]string, error) { query, scan := prepareClientIDsQuery() - stmt, args, err := queries.toQuery(query). - Where( - sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, - ).ToSql() + eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[AppColumnOwnerRemoved.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-fajp8", "Errors.Query.InvalidRequest") } diff --git a/internal/query/app_test.go b/internal/query/app_test.go index d635c31e87..f69ca48875 100644 --- a/internal/query/app_test.go +++ b/internal/query/app_test.go @@ -15,109 +15,109 @@ import ( ) var ( - expectedAppQuery = regexp.QuoteMeta(`SELECT projections.apps3.id,` + - ` projections.apps3.name,` + - ` projections.apps3.project_id,` + - ` projections.apps3.creation_date,` + - ` projections.apps3.change_date,` + - ` projections.apps3.resource_owner,` + - ` projections.apps3.state,` + - ` projections.apps3.sequence,` + + expectedAppQuery = regexp.QuoteMeta(`SELECT projections.apps4.id,` + + ` projections.apps4.name,` + + ` projections.apps4.project_id,` + + ` projections.apps4.creation_date,` + + ` projections.apps4.change_date,` + + ` projections.apps4.resource_owner,` + + ` projections.apps4.state,` + + ` projections.apps4.sequence,` + // api config - ` projections.apps3_api_configs.app_id,` + - ` projections.apps3_api_configs.client_id,` + - ` projections.apps3_api_configs.auth_method,` + + ` projections.apps4_api_configs.app_id,` + + ` projections.apps4_api_configs.client_id,` + + ` projections.apps4_api_configs.auth_method,` + // oidc config - ` projections.apps3_oidc_configs.app_id,` + - ` projections.apps3_oidc_configs.version,` + - ` projections.apps3_oidc_configs.client_id,` + - ` projections.apps3_oidc_configs.redirect_uris,` + - ` projections.apps3_oidc_configs.response_types,` + - ` projections.apps3_oidc_configs.grant_types,` + - ` projections.apps3_oidc_configs.application_type,` + - ` projections.apps3_oidc_configs.auth_method_type,` + - ` projections.apps3_oidc_configs.post_logout_redirect_uris,` + - ` projections.apps3_oidc_configs.is_dev_mode,` + - ` projections.apps3_oidc_configs.access_token_type,` + - ` projections.apps3_oidc_configs.access_token_role_assertion,` + - ` projections.apps3_oidc_configs.id_token_role_assertion,` + - ` projections.apps3_oidc_configs.id_token_userinfo_assertion,` + - ` projections.apps3_oidc_configs.clock_skew,` + - ` projections.apps3_oidc_configs.additional_origins,` + + ` projections.apps4_oidc_configs.app_id,` + + ` projections.apps4_oidc_configs.version,` + + ` projections.apps4_oidc_configs.client_id,` + + ` projections.apps4_oidc_configs.redirect_uris,` + + ` projections.apps4_oidc_configs.response_types,` + + ` projections.apps4_oidc_configs.grant_types,` + + ` projections.apps4_oidc_configs.application_type,` + + ` projections.apps4_oidc_configs.auth_method_type,` + + ` projections.apps4_oidc_configs.post_logout_redirect_uris,` + + ` projections.apps4_oidc_configs.is_dev_mode,` + + ` projections.apps4_oidc_configs.access_token_type,` + + ` projections.apps4_oidc_configs.access_token_role_assertion,` + + ` projections.apps4_oidc_configs.id_token_role_assertion,` + + ` projections.apps4_oidc_configs.id_token_userinfo_assertion,` + + ` projections.apps4_oidc_configs.clock_skew,` + + ` projections.apps4_oidc_configs.additional_origins,` + //saml config - ` projections.apps3_saml_configs.app_id,` + - ` projections.apps3_saml_configs.entity_id,` + - ` projections.apps3_saml_configs.metadata,` + - ` projections.apps3_saml_configs.metadata_url` + - ` FROM projections.apps3` + - ` LEFT JOIN projections.apps3_api_configs ON projections.apps3.id = projections.apps3_api_configs.app_id AND projections.apps3.instance_id = projections.apps3_api_configs.instance_id` + - ` LEFT JOIN projections.apps3_oidc_configs ON projections.apps3.id = projections.apps3_oidc_configs.app_id AND projections.apps3.instance_id = projections.apps3_oidc_configs.instance_id` + - ` LEFT JOIN projections.apps3_saml_configs ON projections.apps3.id = projections.apps3_saml_configs.app_id AND projections.apps3.instance_id = projections.apps3_saml_configs.instance_id`) - expectedAppsQuery = regexp.QuoteMeta(`SELECT projections.apps3.id,` + - ` projections.apps3.name,` + - ` projections.apps3.project_id,` + - ` projections.apps3.creation_date,` + - ` projections.apps3.change_date,` + - ` projections.apps3.resource_owner,` + - ` projections.apps3.state,` + - ` projections.apps3.sequence,` + + ` projections.apps4_saml_configs.app_id,` + + ` projections.apps4_saml_configs.entity_id,` + + ` projections.apps4_saml_configs.metadata,` + + ` projections.apps4_saml_configs.metadata_url` + + ` FROM projections.apps4` + + ` LEFT JOIN projections.apps4_api_configs ON projections.apps4.id = projections.apps4_api_configs.app_id AND projections.apps4.instance_id = projections.apps4_api_configs.instance_id` + + ` LEFT JOIN projections.apps4_oidc_configs ON projections.apps4.id = projections.apps4_oidc_configs.app_id AND projections.apps4.instance_id = projections.apps4_oidc_configs.instance_id` + + ` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id`) + expectedAppsQuery = regexp.QuoteMeta(`SELECT projections.apps4.id,` + + ` projections.apps4.name,` + + ` projections.apps4.project_id,` + + ` projections.apps4.creation_date,` + + ` projections.apps4.change_date,` + + ` projections.apps4.resource_owner,` + + ` projections.apps4.state,` + + ` projections.apps4.sequence,` + // api config - ` projections.apps3_api_configs.app_id,` + - ` projections.apps3_api_configs.client_id,` + - ` projections.apps3_api_configs.auth_method,` + + ` projections.apps4_api_configs.app_id,` + + ` projections.apps4_api_configs.client_id,` + + ` projections.apps4_api_configs.auth_method,` + // oidc config - ` projections.apps3_oidc_configs.app_id,` + - ` projections.apps3_oidc_configs.version,` + - ` projections.apps3_oidc_configs.client_id,` + - ` projections.apps3_oidc_configs.redirect_uris,` + - ` projections.apps3_oidc_configs.response_types,` + - ` projections.apps3_oidc_configs.grant_types,` + - ` projections.apps3_oidc_configs.application_type,` + - ` projections.apps3_oidc_configs.auth_method_type,` + - ` projections.apps3_oidc_configs.post_logout_redirect_uris,` + - ` projections.apps3_oidc_configs.is_dev_mode,` + - ` projections.apps3_oidc_configs.access_token_type,` + - ` projections.apps3_oidc_configs.access_token_role_assertion,` + - ` projections.apps3_oidc_configs.id_token_role_assertion,` + - ` projections.apps3_oidc_configs.id_token_userinfo_assertion,` + - ` projections.apps3_oidc_configs.clock_skew,` + - ` projections.apps3_oidc_configs.additional_origins,` + + ` projections.apps4_oidc_configs.app_id,` + + ` projections.apps4_oidc_configs.version,` + + ` projections.apps4_oidc_configs.client_id,` + + ` projections.apps4_oidc_configs.redirect_uris,` + + ` projections.apps4_oidc_configs.response_types,` + + ` projections.apps4_oidc_configs.grant_types,` + + ` projections.apps4_oidc_configs.application_type,` + + ` projections.apps4_oidc_configs.auth_method_type,` + + ` projections.apps4_oidc_configs.post_logout_redirect_uris,` + + ` projections.apps4_oidc_configs.is_dev_mode,` + + ` projections.apps4_oidc_configs.access_token_type,` + + ` projections.apps4_oidc_configs.access_token_role_assertion,` + + ` projections.apps4_oidc_configs.id_token_role_assertion,` + + ` projections.apps4_oidc_configs.id_token_userinfo_assertion,` + + ` projections.apps4_oidc_configs.clock_skew,` + + ` projections.apps4_oidc_configs.additional_origins,` + //saml config - ` projections.apps3_saml_configs.app_id,` + - ` projections.apps3_saml_configs.entity_id,` + - ` projections.apps3_saml_configs.metadata,` + - ` projections.apps3_saml_configs.metadata_url,` + + ` projections.apps4_saml_configs.app_id,` + + ` projections.apps4_saml_configs.entity_id,` + + ` projections.apps4_saml_configs.metadata,` + + ` projections.apps4_saml_configs.metadata_url,` + ` COUNT(*) OVER ()` + - ` FROM projections.apps3` + - ` LEFT JOIN projections.apps3_api_configs ON projections.apps3.id = projections.apps3_api_configs.app_id AND projections.apps3.instance_id = projections.apps3_api_configs.instance_id` + - ` LEFT JOIN projections.apps3_oidc_configs ON projections.apps3.id = projections.apps3_oidc_configs.app_id AND projections.apps3.instance_id = projections.apps3_oidc_configs.instance_id` + - ` LEFT JOIN projections.apps3_saml_configs ON projections.apps3.id = projections.apps3_saml_configs.app_id AND projections.apps3.instance_id = projections.apps3_saml_configs.instance_id`) - expectedAppIDsQuery = regexp.QuoteMeta(`SELECT projections.apps3_api_configs.client_id,` + - ` projections.apps3_oidc_configs.client_id` + - ` FROM projections.apps3` + - ` LEFT JOIN projections.apps3_api_configs ON projections.apps3.id = projections.apps3_api_configs.app_id AND projections.apps3.instance_id = projections.apps3_api_configs.instance_id` + - ` LEFT JOIN projections.apps3_oidc_configs ON projections.apps3.id = projections.apps3_oidc_configs.app_id AND projections.apps3.instance_id = projections.apps3_oidc_configs.instance_id`) - expectedProjectIDByAppQuery = regexp.QuoteMeta(`SELECT projections.apps3.project_id` + - ` FROM projections.apps3` + - ` LEFT JOIN projections.apps3_api_configs ON projections.apps3.id = projections.apps3_api_configs.app_id AND projections.apps3.instance_id = projections.apps3_api_configs.instance_id` + - ` LEFT JOIN projections.apps3_oidc_configs ON projections.apps3.id = projections.apps3_oidc_configs.app_id AND projections.apps3.instance_id = projections.apps3_oidc_configs.instance_id` + - ` LEFT JOIN projections.apps3_saml_configs ON projections.apps3.id = projections.apps3_saml_configs.app_id AND projections.apps3.instance_id = projections.apps3_saml_configs.instance_id`) - expectedProjectByAppQuery = regexp.QuoteMeta(`SELECT projections.projects2.id,` + - ` projections.projects2.creation_date,` + - ` projections.projects2.change_date,` + - ` projections.projects2.resource_owner,` + - ` projections.projects2.state,` + - ` projections.projects2.sequence,` + - ` projections.projects2.name,` + - ` projections.projects2.project_role_assertion,` + - ` projections.projects2.project_role_check,` + - ` projections.projects2.has_project_check,` + - ` projections.projects2.private_labeling_setting` + - ` FROM projections.projects2` + - ` JOIN projections.apps3 ON projections.projects2.id = projections.apps3.project_id AND projections.projects2.instance_id = projections.apps3.instance_id` + - ` LEFT JOIN projections.apps3_api_configs ON projections.apps3.id = projections.apps3_api_configs.app_id AND projections.apps3.instance_id = projections.apps3_api_configs.instance_id` + - ` LEFT JOIN projections.apps3_oidc_configs ON projections.apps3.id = projections.apps3_oidc_configs.app_id AND projections.apps3.instance_id = projections.apps3_oidc_configs.instance_id` + - ` LEFT JOIN projections.apps3_saml_configs ON projections.apps3.id = projections.apps3_saml_configs.app_id AND projections.apps3.instance_id = projections.apps3_saml_configs.instance_id`) + ` FROM projections.apps4` + + ` LEFT JOIN projections.apps4_api_configs ON projections.apps4.id = projections.apps4_api_configs.app_id AND projections.apps4.instance_id = projections.apps4_api_configs.instance_id` + + ` LEFT JOIN projections.apps4_oidc_configs ON projections.apps4.id = projections.apps4_oidc_configs.app_id AND projections.apps4.instance_id = projections.apps4_oidc_configs.instance_id` + + ` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id`) + expectedAppIDsQuery = regexp.QuoteMeta(`SELECT projections.apps4_api_configs.client_id,` + + ` projections.apps4_oidc_configs.client_id` + + ` FROM projections.apps4` + + ` LEFT JOIN projections.apps4_api_configs ON projections.apps4.id = projections.apps4_api_configs.app_id AND projections.apps4.instance_id = projections.apps4_api_configs.instance_id` + + ` LEFT JOIN projections.apps4_oidc_configs ON projections.apps4.id = projections.apps4_oidc_configs.app_id AND projections.apps4.instance_id = projections.apps4_oidc_configs.instance_id`) + expectedProjectIDByAppQuery = regexp.QuoteMeta(`SELECT projections.apps4.project_id` + + ` FROM projections.apps4` + + ` LEFT JOIN projections.apps4_api_configs ON projections.apps4.id = projections.apps4_api_configs.app_id AND projections.apps4.instance_id = projections.apps4_api_configs.instance_id` + + ` LEFT JOIN projections.apps4_oidc_configs ON projections.apps4.id = projections.apps4_oidc_configs.app_id AND projections.apps4.instance_id = projections.apps4_oidc_configs.instance_id` + + ` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id`) + expectedProjectByAppQuery = regexp.QuoteMeta(`SELECT projections.projects3.id,` + + ` projections.projects3.creation_date,` + + ` projections.projects3.change_date,` + + ` projections.projects3.resource_owner,` + + ` projections.projects3.state,` + + ` projections.projects3.sequence,` + + ` projections.projects3.name,` + + ` projections.projects3.project_role_assertion,` + + ` projections.projects3.project_role_check,` + + ` projections.projects3.has_project_check,` + + ` projections.projects3.private_labeling_setting` + + ` FROM projections.projects3` + + ` JOIN projections.apps4 ON projections.projects3.id = projections.apps4.project_id AND projections.projects3.instance_id = projections.apps4.instance_id` + + ` LEFT JOIN projections.apps4_api_configs ON projections.apps4.id = projections.apps4_api_configs.app_id AND projections.apps4.instance_id = projections.apps4_api_configs.instance_id` + + ` LEFT JOIN projections.apps4_oidc_configs ON projections.apps4.id = projections.apps4_oidc_configs.app_id AND projections.apps4.instance_id = projections.apps4_oidc_configs.instance_id` + + ` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id`) appCols = database.StringArray{ "id", diff --git a/internal/query/authn_key.go b/internal/query/authn_key.go index b5fdc9306d..01cb10bdf6 100644 --- a/internal/query/authn_key.go +++ b/internal/query/authn_key.go @@ -28,6 +28,10 @@ var ( name: projection.AuthNKeyCreationDateCol, table: authNKeyTable, } + AuthNKeyColumnChangeDate = Column{ + name: projection.AuthNKeyChangeDateCol, + table: authNKeyTable, + } AuthNKeyColumnResourceOwner = Column{ name: projection.AuthNKeyResourceOwnerCol, table: authNKeyTable, @@ -68,6 +72,10 @@ var ( name: projection.AuthNKeyEnabledCol, table: authNKeyTable, } + AuthNKeyOwnerRemovedCol = Column{ + name: projection.AuthNKeyOwnerRemovedCol, + table: authNKeyTable, + } ) type AuthNKeys struct { @@ -78,6 +86,7 @@ type AuthNKeys struct { type AuthNKey struct { ID string CreationDate time.Time + ChangeDate time.Time ResourceOwner string Sequence uint64 @@ -93,6 +102,7 @@ type AuthNKeysData struct { type AuthNKeyData struct { ID string CreationDate time.Time + ChangeDate time.Time ResourceOwner string Sequence uint64 @@ -115,15 +125,17 @@ func (q *AuthNKeySearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder return query } -func (q *Queries) SearchAuthNKeys(ctx context.Context, queries *AuthNKeySearchQueries) (authNKeys *AuthNKeys, err error) { +func (q *Queries) SearchAuthNKeys(ctx context.Context, queries *AuthNKeySearchQueries, withOwnerRemoved bool) (authNKeys *AuthNKeys, err error) { query, scan := prepareAuthNKeysQuery() query = queries.toQuery(query) - stmt, args, err := query.Where( - sq.Eq{ - AuthNKeyColumnEnabled.identifier(): true, - AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ).ToSql() + eq := sq.Eq{ + AuthNKeyColumnEnabled.identifier(): true, + AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[AuthNKeyOwnerRemovedCol.identifier()] = false + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-SAf3f", "Errors.Query.InvalidRequest") } @@ -140,14 +152,17 @@ func (q *Queries) SearchAuthNKeys(ctx context.Context, queries *AuthNKeySearchQu return authNKeys, err } -func (q *Queries) SearchAuthNKeysData(ctx context.Context, queries *AuthNKeySearchQueries) (authNKeys *AuthNKeysData, err error) { +func (q *Queries) SearchAuthNKeysData(ctx context.Context, queries *AuthNKeySearchQueries, withOwnerRemoved bool) (authNKeys *AuthNKeysData, err error) { query, scan := prepareAuthNKeysDataQuery() query = queries.toQuery(query) - stmt, args, err := query.Where( - sq.Eq{ - AuthNKeyColumnEnabled.identifier(): true, - }, - ).ToSql() + eq := sq.Eq{ + AuthNKeyColumnEnabled.identifier(): true, + AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[AuthNKeyOwnerRemovedCol.identifier()] = false + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-SAg3f", "Errors.Query.InvalidRequest") } @@ -164,7 +179,7 @@ func (q *Queries) SearchAuthNKeysData(ctx context.Context, queries *AuthNKeySear return authNKeys, err } -func (q *Queries) GetAuthNKeyByID(ctx context.Context, shouldTriggerBulk bool, id string, queries ...SearchQuery) (*AuthNKey, error) { +func (q *Queries) GetAuthNKeyByID(ctx context.Context, shouldTriggerBulk bool, id string, withOwnerRemoved bool, queries ...SearchQuery) (*AuthNKey, error) { if shouldTriggerBulk { projection.AuthNKeyProjection.Trigger(ctx) } @@ -173,12 +188,15 @@ func (q *Queries) GetAuthNKeyByID(ctx context.Context, shouldTriggerBulk bool, i for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where( - sq.Eq{ - AuthNKeyColumnID.identifier(): id, - AuthNKeyColumnEnabled.identifier(): true, - AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{ + AuthNKeyColumnID.identifier(): id, + AuthNKeyColumnEnabled.identifier(): true, + AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[AuthNKeyOwnerRemovedCol.identifier()] = false + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-AGhg4", "Errors.Query.SQLStatement") } @@ -187,21 +205,34 @@ func (q *Queries) GetAuthNKeyByID(ctx context.Context, shouldTriggerBulk bool, i return scan(row) } -func (q *Queries) GetAuthNKeyPublicKeyByIDAndIdentifier(ctx context.Context, id string, identifier string) ([]byte, error) { +func (q *Queries) GetAuthNKeyPublicKeyByIDAndIdentifier(ctx context.Context, id string, identifier string, withOwnerRemoved bool) ([]byte, error) { stmt, scan := prepareAuthNKeyPublicKeyQuery() - query, args, err := stmt.Where( - sq.And{ + eq := sq.And{ + sq.Eq{ + AuthNKeyColumnID.identifier(): id, + AuthNKeyColumnIdentifier.identifier(): identifier, + AuthNKeyColumnEnabled.identifier(): true, + AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + }, + sq.Gt{ + AuthNKeyColumnExpiration.identifier(): time.Now(), + }, + } + if !withOwnerRemoved { + eq = sq.And{ sq.Eq{ AuthNKeyColumnID.identifier(): id, AuthNKeyColumnIdentifier.identifier(): identifier, AuthNKeyColumnEnabled.identifier(): true, AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + AuthNKeyOwnerRemovedCol.identifier(): false, }, sq.Gt{ AuthNKeyColumnExpiration.identifier(): time.Now(), }, - }, - ).ToSql() + } + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-DAb32", "Errors.Query.SQLStatement") } @@ -226,6 +257,7 @@ func prepareAuthNKeysQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeys return sq.Select( AuthNKeyColumnID.identifier(), AuthNKeyColumnCreationDate.identifier(), + AuthNKeyColumnChangeDate.identifier(), AuthNKeyColumnResourceOwner.identifier(), AuthNKeyColumnSequence.identifier(), AuthNKeyColumnExpiration.identifier(), @@ -240,6 +272,7 @@ func prepareAuthNKeysQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeys err := rows.Scan( &authNKey.ID, &authNKey.CreationDate, + &authNKey.ChangeDate, &authNKey.ResourceOwner, &authNKey.Sequence, &authNKey.Expiration, @@ -269,6 +302,7 @@ func prepareAuthNKeyQuery() (sq.SelectBuilder, func(row *sql.Row) (*AuthNKey, er return sq.Select( AuthNKeyColumnID.identifier(), AuthNKeyColumnCreationDate.identifier(), + AuthNKeyColumnChangeDate.identifier(), AuthNKeyColumnResourceOwner.identifier(), AuthNKeyColumnSequence.identifier(), AuthNKeyColumnExpiration.identifier(), @@ -279,6 +313,7 @@ func prepareAuthNKeyQuery() (sq.SelectBuilder, func(row *sql.Row) (*AuthNKey, er err := row.Scan( &authNKey.ID, &authNKey.CreationDate, + &authNKey.ChangeDate, &authNKey.ResourceOwner, &authNKey.Sequence, &authNKey.Expiration, @@ -317,6 +352,7 @@ func prepareAuthNKeysDataQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthN return sq.Select( AuthNKeyColumnID.identifier(), AuthNKeyColumnCreationDate.identifier(), + AuthNKeyColumnChangeDate.identifier(), AuthNKeyColumnResourceOwner.identifier(), AuthNKeyColumnSequence.identifier(), AuthNKeyColumnExpiration.identifier(), @@ -333,6 +369,7 @@ func prepareAuthNKeysDataQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthN err := rows.Scan( &authNKey.ID, &authNKey.CreationDate, + &authNKey.ChangeDate, &authNKey.ResourceOwner, &authNKey.Sequence, &authNKey.Expiration, diff --git a/internal/query/authn_key_test.go b/internal/query/authn_key_test.go index 958d0d051d..947f46aaf6 100644 --- a/internal/query/authn_key_test.go +++ b/internal/query/authn_key_test.go @@ -28,14 +28,15 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeysQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.authn_keys.id,`+ - ` projections.authn_keys.creation_date,`+ - ` projections.authn_keys.resource_owner,`+ - ` projections.authn_keys.sequence,`+ - ` projections.authn_keys.expiration,`+ - ` projections.authn_keys.type,`+ + regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+ + ` projections.authn_keys2.creation_date,`+ + ` projections.authn_keys2.change_date,`+ + ` projections.authn_keys2.resource_owner,`+ + ` projections.authn_keys2.sequence,`+ + ` projections.authn_keys2.expiration,`+ + ` projections.authn_keys2.type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.authn_keys`), + ` FROM projections.authn_keys2`), nil, nil, ), @@ -47,17 +48,19 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeysQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.authn_keys.id,`+ - ` projections.authn_keys.creation_date,`+ - ` projections.authn_keys.resource_owner,`+ - ` projections.authn_keys.sequence,`+ - ` projections.authn_keys.expiration,`+ - ` projections.authn_keys.type,`+ + regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+ + ` projections.authn_keys2.creation_date,`+ + ` projections.authn_keys2.change_date,`+ + ` projections.authn_keys2.resource_owner,`+ + ` projections.authn_keys2.sequence,`+ + ` projections.authn_keys2.expiration,`+ + ` projections.authn_keys2.type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.authn_keys`), + ` FROM projections.authn_keys2`), []string{ "id", "creation_date", + "change_date", "resource_owner", "sequence", "expiration", @@ -68,6 +71,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { "id", testNow, + testNow, "ro", uint64(20211109), testNow, @@ -84,6 +88,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { ID: "id", CreationDate: testNow, + ChangeDate: testNow, ResourceOwner: "ro", Sequence: 20211109, Expiration: testNow, @@ -97,17 +102,19 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeysQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.authn_keys.id,`+ - ` projections.authn_keys.creation_date,`+ - ` projections.authn_keys.resource_owner,`+ - ` projections.authn_keys.sequence,`+ - ` projections.authn_keys.expiration,`+ - ` projections.authn_keys.type,`+ + regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+ + ` projections.authn_keys2.creation_date,`+ + ` projections.authn_keys2.change_date,`+ + ` projections.authn_keys2.resource_owner,`+ + ` projections.authn_keys2.sequence,`+ + ` projections.authn_keys2.expiration,`+ + ` projections.authn_keys2.type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.authn_keys`), + ` FROM projections.authn_keys2`), []string{ "id", "creation_date", + "change_date", "resource_owner", "sequence", "expiration", @@ -118,6 +125,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { "id-1", testNow, + testNow, "ro", uint64(20211109), testNow, @@ -126,6 +134,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { "id-2", testNow, + testNow, "ro", uint64(20211109), testNow, @@ -142,6 +151,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { ID: "id-1", CreationDate: testNow, + ChangeDate: testNow, ResourceOwner: "ro", Sequence: 20211109, Expiration: testNow, @@ -150,6 +160,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { ID: "id-2", CreationDate: testNow, + ChangeDate: testNow, ResourceOwner: "ro", Sequence: 20211109, Expiration: testNow, @@ -163,14 +174,15 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeysQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.authn_keys.id,`+ - ` projections.authn_keys.creation_date,`+ - ` projections.authn_keys.resource_owner,`+ - ` projections.authn_keys.sequence,`+ - ` projections.authn_keys.expiration,`+ - ` projections.authn_keys.type,`+ + regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+ + ` projections.authn_keys2.creation_date,`+ + ` projections.authn_keys2.change_date,`+ + ` projections.authn_keys2.resource_owner,`+ + ` projections.authn_keys2.sequence,`+ + ` projections.authn_keys2.expiration,`+ + ` projections.authn_keys2.type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.authn_keys`), + ` FROM projections.authn_keys2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { @@ -187,16 +199,17 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeysDataQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.authn_keys.id,`+ - ` projections.authn_keys.creation_date,`+ - ` projections.authn_keys.resource_owner,`+ - ` projections.authn_keys.sequence,`+ - ` projections.authn_keys.expiration,`+ - ` projections.authn_keys.type,`+ - ` projections.authn_keys.identifier,`+ - ` projections.authn_keys.public_key,`+ + regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+ + ` projections.authn_keys2.creation_date,`+ + ` projections.authn_keys2.change_date,`+ + ` projections.authn_keys2.resource_owner,`+ + ` projections.authn_keys2.sequence,`+ + ` projections.authn_keys2.expiration,`+ + ` projections.authn_keys2.type,`+ + ` projections.authn_keys2.identifier,`+ + ` projections.authn_keys2.public_key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.authn_keys`), + ` FROM projections.authn_keys2`), nil, nil, ), @@ -208,19 +221,21 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeysDataQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.authn_keys.id,`+ - ` projections.authn_keys.creation_date,`+ - ` projections.authn_keys.resource_owner,`+ - ` projections.authn_keys.sequence,`+ - ` projections.authn_keys.expiration,`+ - ` projections.authn_keys.type,`+ - ` projections.authn_keys.identifier,`+ - ` projections.authn_keys.public_key,`+ + regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+ + ` projections.authn_keys2.creation_date,`+ + ` projections.authn_keys2.change_date,`+ + ` projections.authn_keys2.resource_owner,`+ + ` projections.authn_keys2.sequence,`+ + ` projections.authn_keys2.expiration,`+ + ` projections.authn_keys2.type,`+ + ` projections.authn_keys2.identifier,`+ + ` projections.authn_keys2.public_key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.authn_keys`), + ` FROM projections.authn_keys2`), []string{ "id", "creation_date", + "change_date", "resource_owner", "sequence", "expiration", @@ -233,6 +248,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { "id", testNow, + testNow, "ro", uint64(20211109), testNow, @@ -251,6 +267,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { ID: "id", CreationDate: testNow, + ChangeDate: testNow, ResourceOwner: "ro", Sequence: 20211109, Expiration: testNow, @@ -266,19 +283,21 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeysDataQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.authn_keys.id,`+ - ` projections.authn_keys.creation_date,`+ - ` projections.authn_keys.resource_owner,`+ - ` projections.authn_keys.sequence,`+ - ` projections.authn_keys.expiration,`+ - ` projections.authn_keys.type,`+ - ` projections.authn_keys.identifier,`+ - ` projections.authn_keys.public_key,`+ + regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+ + ` projections.authn_keys2.creation_date,`+ + ` projections.authn_keys2.change_date,`+ + ` projections.authn_keys2.resource_owner,`+ + ` projections.authn_keys2.sequence,`+ + ` projections.authn_keys2.expiration,`+ + ` projections.authn_keys2.type,`+ + ` projections.authn_keys2.identifier,`+ + ` projections.authn_keys2.public_key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.authn_keys`), + ` FROM projections.authn_keys2`), []string{ "id", "creation_date", + "change_date", "resource_owner", "sequence", "expiration", @@ -291,6 +310,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { "id-1", testNow, + testNow, "ro", uint64(20211109), testNow, @@ -301,6 +321,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { "id-2", testNow, + testNow, "ro", uint64(20211109), testNow, @@ -319,6 +340,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { ID: "id-1", CreationDate: testNow, + ChangeDate: testNow, ResourceOwner: "ro", Sequence: 20211109, Expiration: testNow, @@ -329,6 +351,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { { ID: "id-2", CreationDate: testNow, + ChangeDate: testNow, ResourceOwner: "ro", Sequence: 20211109, Expiration: testNow, @@ -344,16 +367,17 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeysDataQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.authn_keys.id,`+ - ` projections.authn_keys.creation_date,`+ - ` projections.authn_keys.resource_owner,`+ - ` projections.authn_keys.sequence,`+ - ` projections.authn_keys.expiration,`+ - ` projections.authn_keys.type,`+ - ` projections.authn_keys.identifier,`+ - ` projections.authn_keys.public_key,`+ + regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+ + ` projections.authn_keys2.creation_date,`+ + ` projections.authn_keys2.change_date,`+ + ` projections.authn_keys2.resource_owner,`+ + ` projections.authn_keys2.sequence,`+ + ` projections.authn_keys2.expiration,`+ + ` projections.authn_keys2.type,`+ + ` projections.authn_keys2.identifier,`+ + ` projections.authn_keys2.public_key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.authn_keys`), + ` FROM projections.authn_keys2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { @@ -370,13 +394,14 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeyQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.authn_keys.id,`+ - ` projections.authn_keys.creation_date,`+ - ` projections.authn_keys.resource_owner,`+ - ` projections.authn_keys.sequence,`+ - ` projections.authn_keys.expiration,`+ - ` projections.authn_keys.type`+ - ` FROM projections.authn_keys`), + regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+ + ` projections.authn_keys2.creation_date,`+ + ` projections.authn_keys2.change_date,`+ + ` projections.authn_keys2.resource_owner,`+ + ` projections.authn_keys2.sequence,`+ + ` projections.authn_keys2.expiration,`+ + ` projections.authn_keys2.type`+ + ` FROM projections.authn_keys2`), nil, nil, ), @@ -394,16 +419,18 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeyQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.authn_keys.id,`+ - ` projections.authn_keys.creation_date,`+ - ` projections.authn_keys.resource_owner,`+ - ` projections.authn_keys.sequence,`+ - ` projections.authn_keys.expiration,`+ - ` projections.authn_keys.type`+ - ` FROM projections.authn_keys`), + regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+ + ` projections.authn_keys2.creation_date,`+ + ` projections.authn_keys2.change_date,`+ + ` projections.authn_keys2.resource_owner,`+ + ` projections.authn_keys2.sequence,`+ + ` projections.authn_keys2.expiration,`+ + ` projections.authn_keys2.type`+ + ` FROM projections.authn_keys2`), []string{ "id", "creation_date", + "change_date", "resource_owner", "sequence", "expiration", @@ -412,6 +439,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { []driver.Value{ "id", testNow, + testNow, "ro", uint64(20211109), testNow, @@ -422,6 +450,7 @@ func Test_AuthNKeyPrepares(t *testing.T) { object: &AuthNKey{ ID: "id", CreationDate: testNow, + ChangeDate: testNow, ResourceOwner: "ro", Sequence: 20211109, Expiration: testNow, @@ -433,13 +462,14 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeyQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.authn_keys.id,`+ - ` projections.authn_keys.creation_date,`+ - ` projections.authn_keys.resource_owner,`+ - ` projections.authn_keys.sequence,`+ - ` projections.authn_keys.expiration,`+ - ` projections.authn_keys.type`+ - ` FROM projections.authn_keys`), + regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+ + ` projections.authn_keys2.creation_date,`+ + ` projections.authn_keys2.change_date,`+ + ` projections.authn_keys2.resource_owner,`+ + ` projections.authn_keys2.sequence,`+ + ` projections.authn_keys2.expiration,`+ + ` projections.authn_keys2.type`+ + ` FROM projections.authn_keys2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { @@ -456,8 +486,8 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeyPublicKeyQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.authn_keys.public_key`+ - ` FROM projections.authn_keys`), + regexp.QuoteMeta(`SELECT projections.authn_keys2.public_key`+ + ` FROM projections.authn_keys2`), nil, nil, ), @@ -475,8 +505,8 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeyPublicKeyQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.authn_keys.public_key`+ - ` FROM projections.authn_keys`), + regexp.QuoteMeta(`SELECT projections.authn_keys2.public_key`+ + ` FROM projections.authn_keys2`), []string{ "public_key", }, @@ -492,8 +522,8 @@ func Test_AuthNKeyPrepares(t *testing.T) { prepare: prepareAuthNKeyPublicKeyQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.authn_keys.public_key`+ - ` FROM projections.authn_keys`), + regexp.QuoteMeta(`SELECT projections.authn_keys2.public_key`+ + ` FROM projections.authn_keys2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/certificate.go b/internal/query/certificate.go index 1e890407fb..5ecf053fc5 100644 --- a/internal/query/certificate.go +++ b/internal/query/certificate.go @@ -75,13 +75,10 @@ func (q *Queries) ActiveCertificates(ctx context.Context, t time.Time, usage dom KeyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), KeyColUse.identifier(): usage, }, - sq.Gt{ - CertificateColExpiry.identifier(): t, - }, - sq.Gt{ - KeyPrivateColExpiry.identifier(): t, - }, - }).OrderBy(KeyPrivateColExpiry.identifier()).ToSql() + sq.Gt{CertificateColExpiry.identifier(): t}, + sq.Gt{KeyPrivateColExpiry.identifier(): t}, + }, + ).OrderBy(KeyPrivateColExpiry.identifier()).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-SDfkg", "Errors.Query.SQLStatement") } diff --git a/internal/query/certificate_test.go b/internal/query/certificate_test.go index f776ad5ddc..99cc9cb742 100644 --- a/internal/query/certificate_test.go +++ b/internal/query/certificate_test.go @@ -29,20 +29,20 @@ func Test_CertificatePrepares(t *testing.T) { prepare: prepareCertificateQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.keys3.id,`+ - ` projections.keys3.creation_date,`+ - ` projections.keys3.change_date,`+ - ` projections.keys3.sequence,`+ - ` projections.keys3.resource_owner,`+ - ` projections.keys3.algorithm,`+ - ` projections.keys3.use,`+ - ` projections.keys3_certificate.expiry,`+ - ` projections.keys3_certificate.certificate,`+ - ` projections.keys3_private.key,`+ + regexp.QuoteMeta(`SELECT projections.keys4.id,`+ + ` projections.keys4.creation_date,`+ + ` projections.keys4.change_date,`+ + ` projections.keys4.sequence,`+ + ` projections.keys4.resource_owner,`+ + ` projections.keys4.algorithm,`+ + ` projections.keys4.use,`+ + ` projections.keys4_certificate.expiry,`+ + ` projections.keys4_certificate.certificate,`+ + ` projections.keys4_private.key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.keys3`+ - ` LEFT JOIN projections.keys3_certificate ON projections.keys3.id = projections.keys3_certificate.id AND projections.keys3.instance_id = projections.keys3_certificate.instance_id`+ - ` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id AND projections.keys3.instance_id = projections.keys3_private.instance_id`), + ` FROM projections.keys4`+ + ` LEFT JOIN projections.keys4_certificate ON projections.keys4.id = projections.keys4_certificate.id AND projections.keys4.instance_id = projections.keys4_certificate.instance_id`+ + ` LEFT JOIN projections.keys4_private ON projections.keys4.id = projections.keys4_private.id AND projections.keys4.instance_id = projections.keys4_private.instance_id`), nil, nil, ), @@ -60,20 +60,20 @@ func Test_CertificatePrepares(t *testing.T) { prepare: prepareCertificateQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.keys3.id,`+ - ` projections.keys3.creation_date,`+ - ` projections.keys3.change_date,`+ - ` projections.keys3.sequence,`+ - ` projections.keys3.resource_owner,`+ - ` projections.keys3.algorithm,`+ - ` projections.keys3.use,`+ - ` projections.keys3_certificate.expiry,`+ - ` projections.keys3_certificate.certificate,`+ - ` projections.keys3_private.key,`+ + regexp.QuoteMeta(`SELECT projections.keys4.id,`+ + ` projections.keys4.creation_date,`+ + ` projections.keys4.change_date,`+ + ` projections.keys4.sequence,`+ + ` projections.keys4.resource_owner,`+ + ` projections.keys4.algorithm,`+ + ` projections.keys4.use,`+ + ` projections.keys4_certificate.expiry,`+ + ` projections.keys4_certificate.certificate,`+ + ` projections.keys4_private.key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.keys3`+ - ` LEFT JOIN projections.keys3_certificate ON projections.keys3.id = projections.keys3_certificate.id AND projections.keys3.instance_id = projections.keys3_certificate.instance_id`+ - ` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id AND projections.keys3.instance_id = projections.keys3_private.instance_id`), + ` FROM projections.keys4`+ + ` LEFT JOIN projections.keys4_certificate ON projections.keys4.id = projections.keys4_certificate.id AND projections.keys4.instance_id = projections.keys4_certificate.instance_id`+ + ` LEFT JOIN projections.keys4_private ON projections.keys4.id = projections.keys4_private.id AND projections.keys4.instance_id = projections.keys4_private.instance_id`), []string{ "id", "creation_date", @@ -135,20 +135,20 @@ func Test_CertificatePrepares(t *testing.T) { prepare: prepareCertificateQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.keys3.id,`+ - ` projections.keys3.creation_date,`+ - ` projections.keys3.change_date,`+ - ` projections.keys3.sequence,`+ - ` projections.keys3.resource_owner,`+ - ` projections.keys3.algorithm,`+ - ` projections.keys3.use,`+ - ` projections.keys3_certificate.expiry,`+ - ` projections.keys3_certificate.certificate,`+ - ` projections.keys3_private.key,`+ + regexp.QuoteMeta(`SELECT projections.keys4.id,`+ + ` projections.keys4.creation_date,`+ + ` projections.keys4.change_date,`+ + ` projections.keys4.sequence,`+ + ` projections.keys4.resource_owner,`+ + ` projections.keys4.algorithm,`+ + ` projections.keys4.use,`+ + ` projections.keys4_certificate.expiry,`+ + ` projections.keys4_certificate.certificate,`+ + ` projections.keys4_private.key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.keys3`+ - ` LEFT JOIN projections.keys3_certificate ON projections.keys3.id = projections.keys3_certificate.id AND projections.keys3.instance_id = projections.keys3_certificate.instance_id`+ - ` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id AND projections.keys3.instance_id = projections.keys3_private.instance_id`), + ` FROM projections.keys4`+ + ` LEFT JOIN projections.keys4_certificate ON projections.keys4.id = projections.keys4_certificate.id AND projections.keys4.instance_id = projections.keys4_certificate.instance_id`+ + ` LEFT JOIN projections.keys4_private ON projections.keys4.id = projections.keys4_private.id AND projections.keys4.instance_id = projections.keys4_private.instance_id`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/changes.go b/internal/query/changes.go index 6e1e79f1a4..27fc931775 100644 --- a/internal/query/changes.go +++ b/internal/query/changes.go @@ -110,7 +110,7 @@ func (q *Queries) changes(ctx context.Context, query func(query *eventstore.Sear ModifierName: event.EditorUser(), ModifierLoginName: event.EditorUser(), } - editor, _ := q.GetUserByID(ctx, false, change.ModifierId) + editor, _ := q.GetUserByID(ctx, false, change.ModifierId, false) if editor != nil { change.ModifierLoginName = editor.PreferredLoginName change.ModifierResourceOwner = editor.ResourceOwner diff --git a/internal/query/custom_text.go b/internal/query/custom_text.go index d25deec6b3..99eb8b033f 100644 --- a/internal/query/custom_text.go +++ b/internal/query/custom_text.go @@ -78,18 +78,24 @@ var ( name: projection.CustomTextTextCol, table: customTextTable, } + CustomTextOwnerRemoved = Column{ + name: projection.CustomTextOwnerRemovedCol, + table: customTextTable, + } ) -func (q *Queries) CustomTextList(ctx context.Context, aggregateID, template, language string) (texts *CustomTexts, err error) { +func (q *Queries) CustomTextList(ctx context.Context, aggregateID, template, language string, withOwnerRemoved bool) (texts *CustomTexts, err error) { stmt, scan := prepareCustomTextsQuery() - query, args, err := stmt.Where( - sq.Eq{ - CustomTextColAggregateID.identifier(): aggregateID, - CustomTextColTemplate.identifier(): template, - CustomTextColLanguage.identifier(): language, - CustomTextColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ).ToSql() + eq := sq.Eq{ + CustomTextColAggregateID.identifier(): aggregateID, + CustomTextColTemplate.identifier(): template, + CustomTextColLanguage.identifier(): language, + CustomTextColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[CustomTextOwnerRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-M9gse", "Errors.Query.SQLStatement") } @@ -106,15 +112,17 @@ func (q *Queries) CustomTextList(ctx context.Context, aggregateID, template, lan return texts, err } -func (q *Queries) CustomTextListByTemplate(ctx context.Context, aggregateID, template string) (texts *CustomTexts, err error) { +func (q *Queries) CustomTextListByTemplate(ctx context.Context, aggregateID, template string, withOwnerRemoved bool) (texts *CustomTexts, err error) { stmt, scan := prepareCustomTextsQuery() - query, args, err := stmt.Where( - sq.Eq{ - CustomTextColAggregateID.identifier(): aggregateID, - CustomTextColTemplate.identifier(): template, - CustomTextColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ).ToSql() + eq := sq.Eq{ + CustomTextColAggregateID.identifier(): aggregateID, + CustomTextColTemplate.identifier(): template, + CustomTextColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[CustomTextOwnerRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-M49fs", "Errors.Query.SQLStatement") } @@ -146,7 +154,7 @@ func (q *Queries) GetDefaultLoginTexts(ctx context.Context, lang string) (*domai } func (q *Queries) GetCustomLoginTexts(ctx context.Context, aggregateID, lang string) (*domain.CustomLoginText, error) { - texts, err := q.CustomTextList(ctx, aggregateID, domain.LoginCustomText, lang) + texts, err := q.CustomTextList(ctx, aggregateID, domain.LoginCustomText, lang, false) if err != nil { return nil, err } @@ -162,7 +170,7 @@ func (q *Queries) IAMLoginTexts(ctx context.Context, lang string) (*domain.Custo if err := yaml.Unmarshal(contents, &loginTextMap); err != nil { return nil, errors.ThrowInternal(err, "QUERY-m0Jf3", "Errors.TranslationFile.ReadError") } - texts, err := q.CustomTextList(ctx, authz.GetInstance(ctx).InstanceID(), domain.LoginCustomText, lang) + texts, err := q.CustomTextList(ctx, authz.GetInstance(ctx).InstanceID(), domain.LoginCustomText, lang, false) if err != nil { return nil, err } diff --git a/internal/query/custom_text_test.go b/internal/query/custom_text_test.go index d189891dda..c37f06f2c0 100644 --- a/internal/query/custom_text_test.go +++ b/internal/query/custom_text_test.go @@ -29,16 +29,16 @@ func Test_CustomTextPrepares(t *testing.T) { prepare: prepareCustomTextsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.custom_texts.aggregate_id,`+ - ` projections.custom_texts.sequence,`+ - ` projections.custom_texts.creation_date,`+ - ` projections.custom_texts.change_date,`+ - ` projections.custom_texts.language,`+ - ` projections.custom_texts.template,`+ - ` projections.custom_texts.key,`+ - ` projections.custom_texts.text,`+ + regexp.QuoteMeta(`SELECT projections.custom_texts2.aggregate_id,`+ + ` projections.custom_texts2.sequence,`+ + ` projections.custom_texts2.creation_date,`+ + ` projections.custom_texts2.change_date,`+ + ` projections.custom_texts2.language,`+ + ` projections.custom_texts2.template,`+ + ` projections.custom_texts2.key,`+ + ` projections.custom_texts2.text,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.custom_texts`), + ` FROM projections.custom_texts2`), nil, nil, ), @@ -56,16 +56,16 @@ func Test_CustomTextPrepares(t *testing.T) { prepare: prepareCustomTextsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.custom_texts.aggregate_id,`+ - ` projections.custom_texts.sequence,`+ - ` projections.custom_texts.creation_date,`+ - ` projections.custom_texts.change_date,`+ - ` projections.custom_texts.language,`+ - ` projections.custom_texts.template,`+ - ` projections.custom_texts.key,`+ - ` projections.custom_texts.text,`+ + regexp.QuoteMeta(`SELECT projections.custom_texts2.aggregate_id,`+ + ` projections.custom_texts2.sequence,`+ + ` projections.custom_texts2.creation_date,`+ + ` projections.custom_texts2.change_date,`+ + ` projections.custom_texts2.language,`+ + ` projections.custom_texts2.template,`+ + ` projections.custom_texts2.key,`+ + ` projections.custom_texts2.text,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.custom_texts`), + ` FROM projections.custom_texts2`), []string{ "aggregate_id", "sequence", @@ -114,16 +114,16 @@ func Test_CustomTextPrepares(t *testing.T) { prepare: prepareCustomTextsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.custom_texts.aggregate_id,`+ - ` projections.custom_texts.sequence,`+ - ` projections.custom_texts.creation_date,`+ - ` projections.custom_texts.change_date,`+ - ` projections.custom_texts.language,`+ - ` projections.custom_texts.template,`+ - ` projections.custom_texts.key,`+ - ` projections.custom_texts.text,`+ + regexp.QuoteMeta(`SELECT projections.custom_texts2.aggregate_id,`+ + ` projections.custom_texts2.sequence,`+ + ` projections.custom_texts2.creation_date,`+ + ` projections.custom_texts2.change_date,`+ + ` projections.custom_texts2.language,`+ + ` projections.custom_texts2.template,`+ + ` projections.custom_texts2.key,`+ + ` projections.custom_texts2.text,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.custom_texts`), + ` FROM projections.custom_texts2`), []string{ "aggregate_id", "sequence", @@ -192,16 +192,16 @@ func Test_CustomTextPrepares(t *testing.T) { prepare: prepareCustomTextsQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.custom_texts.aggregate_id,`+ - ` projections.custom_texts.sequence,`+ - ` projections.custom_texts.creation_date,`+ - ` projections.custom_texts.change_date,`+ - ` projections.custom_texts.language,`+ - ` projections.custom_texts.template,`+ - ` projections.custom_texts.key,`+ - ` projections.custom_texts.text,`+ + regexp.QuoteMeta(`SELECT projections.custom_texts2.aggregate_id,`+ + ` projections.custom_texts2.sequence,`+ + ` projections.custom_texts2.creation_date,`+ + ` projections.custom_texts2.change_date,`+ + ` projections.custom_texts2.language,`+ + ` projections.custom_texts2.template,`+ + ` projections.custom_texts2.key,`+ + ` projections.custom_texts2.text,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.custom_texts`), + ` FROM projections.custom_texts2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/domain_policy.go b/internal/query/domain_policy.go index 15ad35d96e..175a8c6a7a 100644 --- a/internal/query/domain_policy.go +++ b/internal/query/domain_policy.go @@ -79,29 +79,38 @@ var ( name: projection.DomainPolicyStateCol, table: domainPolicyTable, } + DomainPolicyColOwnerRemoved = Column{ + name: projection.DomainPolicyOwnerRemovedCol, + table: domainPolicyTable, + } ) -func (q *Queries) DomainPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string) (*DomainPolicy, error) { +func (q *Queries) DomainPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string, withOwnerRemoved bool) (*DomainPolicy, error) { if shouldTriggerBulk { projection.DomainPolicyProjection.Trigger(ctx) } - - stmt, scan := prepareDomainPolicyQuery() - query, args, err := stmt.Where( - sq.And{ + eq := sq.And{ + sq.Eq{DomainPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, + sq.Or{ + sq.Eq{DomainPolicyColID.identifier(): orgID}, + sq.Eq{DomainPolicyColID.identifier(): authz.GetInstance(ctx).InstanceID()}, + }, + } + if !withOwnerRemoved { + eq = sq.And{ sq.Eq{ - DomainPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + DomainPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + DomainPolicyColOwnerRemoved.identifier(): false, }, sq.Or{ - sq.Eq{ - DomainPolicyColID.identifier(): orgID, - }, - sq.Eq{ - DomainPolicyColID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + sq.Eq{DomainPolicyColID.identifier(): orgID}, + sq.Eq{DomainPolicyColID.identifier(): authz.GetInstance(ctx).InstanceID()}, }, - }). - OrderBy(DomainPolicyColIsDefault.identifier()). + } + } + + stmt, scan := prepareDomainPolicyQuery() + query, args, err := stmt.Where(eq).OrderBy(DomainPolicyColIsDefault.identifier()). Limit(1).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-D3CqT", "Errors.Query.SQLStatement") diff --git a/internal/query/domain_policy_test.go b/internal/query/domain_policy_test.go index c396536383..d41fb40257 100644 --- a/internal/query/domain_policy_test.go +++ b/internal/query/domain_policy_test.go @@ -28,17 +28,17 @@ func Test_DomainPolicyPrepares(t *testing.T) { prepare: prepareDomainPolicyQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.domain_policies.id,`+ - ` projections.domain_policies.sequence,`+ - ` projections.domain_policies.creation_date,`+ - ` projections.domain_policies.change_date,`+ - ` projections.domain_policies.resource_owner,`+ - ` projections.domain_policies.user_login_must_be_domain,`+ - ` projections.domain_policies.validate_org_domains,`+ - ` projections.domain_policies.smtp_sender_address_matches_instance_domain,`+ - ` projections.domain_policies.is_default,`+ - ` projections.domain_policies.state`+ - ` FROM projections.domain_policies`), + regexp.QuoteMeta(`SELECT projections.domain_policies2.id,`+ + ` projections.domain_policies2.sequence,`+ + ` projections.domain_policies2.creation_date,`+ + ` projections.domain_policies2.change_date,`+ + ` projections.domain_policies2.resource_owner,`+ + ` projections.domain_policies2.user_login_must_be_domain,`+ + ` projections.domain_policies2.validate_org_domains,`+ + ` projections.domain_policies2.smtp_sender_address_matches_instance_domain,`+ + ` projections.domain_policies2.is_default,`+ + ` projections.domain_policies2.state`+ + ` FROM projections.domain_policies2`), nil, nil, ), @@ -56,17 +56,17 @@ func Test_DomainPolicyPrepares(t *testing.T) { prepare: prepareDomainPolicyQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.domain_policies.id,`+ - ` projections.domain_policies.sequence,`+ - ` projections.domain_policies.creation_date,`+ - ` projections.domain_policies.change_date,`+ - ` projections.domain_policies.resource_owner,`+ - ` projections.domain_policies.user_login_must_be_domain,`+ - ` projections.domain_policies.validate_org_domains,`+ - ` projections.domain_policies.smtp_sender_address_matches_instance_domain,`+ - ` projections.domain_policies.is_default,`+ - ` projections.domain_policies.state`+ - ` FROM projections.domain_policies`), + regexp.QuoteMeta(`SELECT projections.domain_policies2.id,`+ + ` projections.domain_policies2.sequence,`+ + ` projections.domain_policies2.creation_date,`+ + ` projections.domain_policies2.change_date,`+ + ` projections.domain_policies2.resource_owner,`+ + ` projections.domain_policies2.user_login_must_be_domain,`+ + ` projections.domain_policies2.validate_org_domains,`+ + ` projections.domain_policies2.smtp_sender_address_matches_instance_domain,`+ + ` projections.domain_policies2.is_default,`+ + ` projections.domain_policies2.state`+ + ` FROM projections.domain_policies2`), []string{ "id", "sequence", @@ -111,17 +111,17 @@ func Test_DomainPolicyPrepares(t *testing.T) { prepare: prepareDomainPolicyQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.domain_policies.id,`+ - ` projections.domain_policies.sequence,`+ - ` projections.domain_policies.creation_date,`+ - ` projections.domain_policies.change_date,`+ - ` projections.domain_policies.resource_owner,`+ - ` projections.domain_policies.user_login_must_be_domain,`+ - ` projections.domain_policies.validate_org_domains,`+ - ` projections.domain_policies.smtp_sender_address_matches_instance_domain,`+ - ` projections.domain_policies.is_default,`+ - ` projections.domain_policies.state`+ - ` FROM projections.domain_policies`), + regexp.QuoteMeta(`SELECT projections.domain_policies2.id,`+ + ` projections.domain_policies2.sequence,`+ + ` projections.domain_policies2.creation_date,`+ + ` projections.domain_policies2.change_date,`+ + ` projections.domain_policies2.resource_owner,`+ + ` projections.domain_policies2.user_login_must_be_domain,`+ + ` projections.domain_policies2.validate_org_domains,`+ + ` projections.domain_policies2.smtp_sender_address_matches_instance_domain,`+ + ` projections.domain_policies2.is_default,`+ + ` projections.domain_policies2.state`+ + ` FROM projections.domain_policies2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/iam_member.go b/internal/query/iam_member.go index 8a1ea60a0c..44e8031aa4 100644 --- a/internal/query/iam_member.go +++ b/internal/query/iam_member.go @@ -7,7 +7,6 @@ import ( sq "github.com/Masterminds/squirrel" "github.com/zitadel/zitadel/internal/api/authz" - "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/query/projection" ) @@ -50,6 +49,14 @@ var ( name: projection.InstanceMemberIAMIDCol, table: instanceMemberTable, } + InstanceMemberOwnerRemoved = Column{ + name: projection.MemberOwnerRemoved, + table: instanceMemberTable, + } + InstanceMemberOwnerRemovedUser = Column{ + name: projection.MemberUserOwnerRemoved, + table: instanceMemberTable, + } ) type IAMMembersQuery struct { @@ -61,12 +68,19 @@ func (q *IAMMembersQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { toQuery(query) } -func (q *Queries) IAMMembers(ctx context.Context, queries *IAMMembersQuery) (*Members, error) { +func addIamMemberWithoutOwnerRemoved(eq map[string]interface{}) { + eq[InstanceMemberOwnerRemoved.identifier()] = false + eq[InstanceMemberOwnerRemovedUser.identifier()] = false +} + +func (q *Queries) IAMMembers(ctx context.Context, queries *IAMMembersQuery, withOwnerRemoved bool) (*Members, error) { query, scan := prepareInstanceMembersQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - InstanceMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{InstanceMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + addIamMemberWithoutOwnerRemoved(eq) + addLoginNameWithoutOwnerRemoved(eq) + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-USNwM", "Errors.Query.InvalidRequest") } diff --git a/internal/query/iam_member_test.go b/internal/query/iam_member_test.go index cec9415a3a..6a6251dcc9 100644 --- a/internal/query/iam_member_test.go +++ b/internal/query/iam_member_test.go @@ -19,22 +19,22 @@ var ( ", members.resource_owner" + ", members.user_id" + ", members.roles" + - ", projections.login_names.login_name" + - ", projections.users5_humans.email" + - ", projections.users5_humans.first_name" + - ", projections.users5_humans.last_name" + - ", projections.users5_humans.display_name" + - ", projections.users5_machines.name" + - ", projections.users5_humans.avatar_key" + + ", projections.login_names2.login_name" + + ", projections.users6_humans.email" + + ", projections.users6_humans.first_name" + + ", projections.users6_humans.last_name" + + ", projections.users6_humans.display_name" + + ", projections.users6_machines.name" + + ", projections.users6_humans.avatar_key" + ", COUNT(*) OVER () " + - "FROM projections.instance_members2 AS members " + - "LEFT JOIN projections.users5_humans " + - "ON members.user_id = projections.users5_humans.user_id AND members.instance_id = projections.users5_humans.instance_id " + - "LEFT JOIN projections.users5_machines " + - "ON members.user_id = projections.users5_machines.user_id AND members.instance_id = projections.users5_machines.instance_id " + - "LEFT JOIN projections.login_names " + - "ON members.user_id = projections.login_names.user_id AND members.instance_id = projections.login_names.instance_id " + - "WHERE projections.login_names.is_primary = $1") + "FROM projections.instance_members3 AS members " + + "LEFT JOIN projections.users6_humans " + + "ON members.user_id = projections.users6_humans.user_id AND members.instance_id = projections.users6_humans.instance_id " + + "LEFT JOIN projections.users6_machines " + + "ON members.user_id = projections.users6_machines.user_id AND members.instance_id = projections.users6_machines.instance_id " + + "LEFT JOIN projections.login_names2 " + + "ON members.user_id = projections.login_names2.user_id AND members.instance_id = projections.login_names2.instance_id " + + "WHERE projections.login_names2.is_primary = $1") instanceMembersColumns = []string{ "creation_date", "change_date", diff --git a/internal/query/idp.go b/internal/query/idp.go index 8daaa48eae..115231e85e 100644 --- a/internal/query/idp.go +++ b/internal/query/idp.go @@ -110,6 +110,10 @@ var ( name: projection.IDPTypeCol, table: idpTable, } + IDPOwnerRemovedCol = Column{ + name: projection.IDPOwnerRemovedCol, + table: idpTable, + } ) var ( @@ -183,28 +187,27 @@ var ( ) // IDPByIDAndResourceOwner searches for the requested id in the context of the resource owner and IAM -func (q *Queries) IDPByIDAndResourceOwner(ctx context.Context, shouldTriggerBulk bool, id, resourceOwner string) (*IDP, error) { +func (q *Queries) IDPByIDAndResourceOwner(ctx context.Context, shouldTriggerBulk bool, id, resourceOwner string, withOwnerRemoved bool) (*IDP, error) { if shouldTriggerBulk { projection.IDPProjection.Trigger(ctx) } - stmt, scan := prepareIDPByIDQuery() - query, args, err := stmt.Where( - sq.And{ - sq.Eq{ - IDPIDCol.identifier(): id, - IDPInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - sq.Or{ - sq.Eq{ - IDPResourceOwnerCol.identifier(): resourceOwner, - }, - sq.Eq{ - IDPResourceOwnerCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - }, + eq := sq.Eq{ + IDPIDCol.identifier(): id, + IDPInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[IDPOwnerRemovedCol.identifier()] = false + } + where := sq.And{ + eq, + sq.Or{ + sq.Eq{IDPResourceOwnerCol.identifier(): resourceOwner}, + sq.Eq{IDPResourceOwnerCol.identifier(): authz.GetInstance(ctx).InstanceID()}, }, - ).ToSql() + } + stmt, scan := prepareIDPByIDQuery() + query, args, err := stmt.Where(where).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-0gocI", "Errors.Query.SQLStatement") } @@ -214,12 +217,15 @@ func (q *Queries) IDPByIDAndResourceOwner(ctx context.Context, shouldTriggerBulk } // IDPs searches idps matching the query -func (q *Queries) IDPs(ctx context.Context, queries *IDPSearchQueries) (idps *IDPs, err error) { +func (q *Queries) IDPs(ctx context.Context, queries *IDPSearchQueries, withOwnerRemoved bool) (idps *IDPs, err error) { query, scan := prepareIDPsQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - IDPInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{ + IDPInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[IDPOwnerRemovedCol.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-X6X7y", "Errors.Query.InvalidRequest") } @@ -506,8 +512,8 @@ func prepareIDPsQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPs, error)) { } } -func (q *Queries) GetOIDCIDPClientSecret(ctx context.Context, shouldRealTime bool, resourceowner, idpID string) (string, error) { - idp, err := q.IDPByIDAndResourceOwner(ctx, shouldRealTime, idpID, resourceowner) +func (q *Queries) GetOIDCIDPClientSecret(ctx context.Context, shouldRealTime bool, resourceowner, idpID string, withOwnerRemoved bool) (string, error) { + idp, err := q.IDPByIDAndResourceOwner(ctx, shouldRealTime, idpID, resourceowner, withOwnerRemoved) if err != nil { return "", err } diff --git a/internal/query/idp_login_policy_link.go b/internal/query/idp_login_policy_link.go index 0a0ac3bab1..17ec9c1c27 100644 --- a/internal/query/idp_login_policy_link.go +++ b/internal/query/idp_login_policy_link.go @@ -73,16 +73,22 @@ var ( name: projection.IDPLoginPolicyLinkProviderTypeCol, table: idpLoginPolicyLinkTable, } + IDPLoginPolicyLinkOwnerRemovedCol = Column{ + name: projection.IDPLoginPolicyLinkOwnerRemovedCol, + table: idpLoginPolicyLinkTable, + } ) -func (q *Queries) IDPLoginPolicyLinks(ctx context.Context, resourceOwner string, queries *IDPLoginPolicyLinksSearchQuery) (idps *IDPLoginPolicyLinks, err error) { +func (q *Queries) IDPLoginPolicyLinks(ctx context.Context, resourceOwner string, queries *IDPLoginPolicyLinksSearchQuery, withOwnerRemoved bool) (idps *IDPLoginPolicyLinks, err error) { query, scan := prepareIDPLoginPolicyLinksQuery() - stmt, args, err := queries.toQuery(query).Where( - sq.Eq{ - IDPLoginPolicyLinkResourceOwnerCol.identifier(): resourceOwner, - IDPLoginPolicyLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ).ToSql() + eq := sq.Eq{ + IDPLoginPolicyLinkResourceOwnerCol.identifier(): resourceOwner, + IDPLoginPolicyLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[IDPLoginPolicyLinkOwnerRemovedCol.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-FDbKW", "Errors.Query.InvalidRequest") } diff --git a/internal/query/idp_login_policy_link_test.go b/internal/query/idp_login_policy_link_test.go index e1349f770e..2dfb2965a9 100644 --- a/internal/query/idp_login_policy_link_test.go +++ b/internal/query/idp_login_policy_link_test.go @@ -12,12 +12,12 @@ import ( ) var ( - loginPolicyIDPLinksQuery = regexp.QuoteMeta(`SELECT projections.idp_login_policy_links3.idp_id,` + - ` projections.idps2.name,` + - ` projections.idps2.type,` + + loginPolicyIDPLinksQuery = regexp.QuoteMeta(`SELECT projections.idp_login_policy_links4.idp_id,` + + ` projections.idps3.name,` + + ` projections.idps3.type,` + ` COUNT(*) OVER ()` + - ` FROM projections.idp_login_policy_links3` + - ` LEFT JOIN projections.idps2 ON projections.idp_login_policy_links3.idp_id = projections.idps2.id`) + ` FROM projections.idp_login_policy_links4` + + ` LEFT JOIN projections.idps3 ON projections.idp_login_policy_links4.idp_id = projections.idps3.id`) loginPolicyIDPLinksCols = []string{ "idp_id", "name", diff --git a/internal/query/idp_test.go b/internal/query/idp_test.go index 092c17f1d4..b29306c9e3 100644 --- a/internal/query/idp_test.go +++ b/internal/query/idp_test.go @@ -15,33 +15,33 @@ import ( ) var ( - idpQuery = `SELECT projections.idps2.id,` + - ` projections.idps2.resource_owner,` + - ` projections.idps2.creation_date,` + - ` projections.idps2.change_date,` + - ` projections.idps2.sequence,` + - ` projections.idps2.state,` + - ` projections.idps2.name,` + - ` projections.idps2.styling_type,` + - ` projections.idps2.owner_type,` + - ` projections.idps2.auto_register,` + - ` projections.idps2_oidc_config.idp_id,` + - ` projections.idps2_oidc_config.client_id,` + - ` projections.idps2_oidc_config.client_secret,` + - ` projections.idps2_oidc_config.issuer,` + - ` projections.idps2_oidc_config.scopes,` + - ` projections.idps2_oidc_config.display_name_mapping,` + - ` projections.idps2_oidc_config.username_mapping,` + - ` projections.idps2_oidc_config.authorization_endpoint,` + - ` projections.idps2_oidc_config.token_endpoint,` + - ` projections.idps2_jwt_config.idp_id,` + - ` projections.idps2_jwt_config.issuer,` + - ` projections.idps2_jwt_config.keys_endpoint,` + - ` projections.idps2_jwt_config.header_name,` + - ` projections.idps2_jwt_config.endpoint` + - ` FROM projections.idps2` + - ` LEFT JOIN projections.idps2_oidc_config ON projections.idps2.id = projections.idps2_oidc_config.idp_id AND projections.idps2.instance_id = projections.idps2_oidc_config.instance_id` + - ` LEFT JOIN projections.idps2_jwt_config ON projections.idps2.id = projections.idps2_jwt_config.idp_id AND projections.idps2.instance_id = projections.idps2_jwt_config.instance_id` + idpQuery = `SELECT projections.idps3.id,` + + ` projections.idps3.resource_owner,` + + ` projections.idps3.creation_date,` + + ` projections.idps3.change_date,` + + ` projections.idps3.sequence,` + + ` projections.idps3.state,` + + ` projections.idps3.name,` + + ` projections.idps3.styling_type,` + + ` projections.idps3.owner_type,` + + ` projections.idps3.auto_register,` + + ` projections.idps3_oidc_config.idp_id,` + + ` projections.idps3_oidc_config.client_id,` + + ` projections.idps3_oidc_config.client_secret,` + + ` projections.idps3_oidc_config.issuer,` + + ` projections.idps3_oidc_config.scopes,` + + ` projections.idps3_oidc_config.display_name_mapping,` + + ` projections.idps3_oidc_config.username_mapping,` + + ` projections.idps3_oidc_config.authorization_endpoint,` + + ` projections.idps3_oidc_config.token_endpoint,` + + ` projections.idps3_jwt_config.idp_id,` + + ` projections.idps3_jwt_config.issuer,` + + ` projections.idps3_jwt_config.keys_endpoint,` + + ` projections.idps3_jwt_config.header_name,` + + ` projections.idps3_jwt_config.endpoint` + + ` FROM projections.idps3` + + ` LEFT JOIN projections.idps3_oidc_config ON projections.idps3.id = projections.idps3_oidc_config.idp_id AND projections.idps3.instance_id = projections.idps3_oidc_config.instance_id` + + ` LEFT JOIN projections.idps3_jwt_config ON projections.idps3.id = projections.idps3_jwt_config.idp_id AND projections.idps3.instance_id = projections.idps3_jwt_config.instance_id` idpCols = []string{ "id", "resource_owner", @@ -70,34 +70,34 @@ var ( "header_name", "endpoint", } - idpsQuery = `SELECT projections.idps2.id,` + - ` projections.idps2.resource_owner,` + - ` projections.idps2.creation_date,` + - ` projections.idps2.change_date,` + - ` projections.idps2.sequence,` + - ` projections.idps2.state,` + - ` projections.idps2.name,` + - ` projections.idps2.styling_type,` + - ` projections.idps2.owner_type,` + - ` projections.idps2.auto_register,` + - ` projections.idps2_oidc_config.idp_id,` + - ` projections.idps2_oidc_config.client_id,` + - ` projections.idps2_oidc_config.client_secret,` + - ` projections.idps2_oidc_config.issuer,` + - ` projections.idps2_oidc_config.scopes,` + - ` projections.idps2_oidc_config.display_name_mapping,` + - ` projections.idps2_oidc_config.username_mapping,` + - ` projections.idps2_oidc_config.authorization_endpoint,` + - ` projections.idps2_oidc_config.token_endpoint,` + - ` projections.idps2_jwt_config.idp_id,` + - ` projections.idps2_jwt_config.issuer,` + - ` projections.idps2_jwt_config.keys_endpoint,` + - ` projections.idps2_jwt_config.header_name,` + - ` projections.idps2_jwt_config.endpoint,` + + idpsQuery = `SELECT projections.idps3.id,` + + ` projections.idps3.resource_owner,` + + ` projections.idps3.creation_date,` + + ` projections.idps3.change_date,` + + ` projections.idps3.sequence,` + + ` projections.idps3.state,` + + ` projections.idps3.name,` + + ` projections.idps3.styling_type,` + + ` projections.idps3.owner_type,` + + ` projections.idps3.auto_register,` + + ` projections.idps3_oidc_config.idp_id,` + + ` projections.idps3_oidc_config.client_id,` + + ` projections.idps3_oidc_config.client_secret,` + + ` projections.idps3_oidc_config.issuer,` + + ` projections.idps3_oidc_config.scopes,` + + ` projections.idps3_oidc_config.display_name_mapping,` + + ` projections.idps3_oidc_config.username_mapping,` + + ` projections.idps3_oidc_config.authorization_endpoint,` + + ` projections.idps3_oidc_config.token_endpoint,` + + ` projections.idps3_jwt_config.idp_id,` + + ` projections.idps3_jwt_config.issuer,` + + ` projections.idps3_jwt_config.keys_endpoint,` + + ` projections.idps3_jwt_config.header_name,` + + ` projections.idps3_jwt_config.endpoint,` + ` COUNT(*) OVER ()` + - ` FROM projections.idps2` + - ` LEFT JOIN projections.idps2_oidc_config ON projections.idps2.id = projections.idps2_oidc_config.idp_id AND projections.idps2.instance_id = projections.idps2_oidc_config.instance_id` + - ` LEFT JOIN projections.idps2_jwt_config ON projections.idps2.id = projections.idps2_jwt_config.idp_id AND projections.idps2.instance_id = projections.idps2_jwt_config.instance_id` + ` FROM projections.idps3` + + ` LEFT JOIN projections.idps3_oidc_config ON projections.idps3.id = projections.idps3_oidc_config.idp_id AND projections.idps3.instance_id = projections.idps3_oidc_config.instance_id` + + ` LEFT JOIN projections.idps3_jwt_config ON projections.idps3.id = projections.idps3_jwt_config.idp_id AND projections.idps3.instance_id = projections.idps3_jwt_config.instance_id` idpsCols = []string{ "id", "resource_owner", diff --git a/internal/query/idp_user_link.go b/internal/query/idp_user_link.go index 5f8983a8b5..3138787f77 100644 --- a/internal/query/idp_user_link.go +++ b/internal/query/idp_user_link.go @@ -81,14 +81,19 @@ var ( name: projection.IDPUserLinkDisplayNameCol, table: idpUserLinkTable, } + IDPUserLinkOwnerRemovedCol = Column{ + name: projection.IDPUserLinkOwnerRemovedCol, + table: idpUserLinkTable, + } ) -func (q *Queries) IDPUserLinks(ctx context.Context, queries *IDPUserLinksSearchQuery) (idps *IDPUserLinks, err error) { +func (q *Queries) IDPUserLinks(ctx context.Context, queries *IDPUserLinksSearchQuery, withOwnerRemoved bool) (idps *IDPUserLinks, err error) { query, scan := prepareIDPUserLinksQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - IDPUserLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{IDPUserLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[IDPUserLinkOwnerRemovedCol.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-4zzFK", "Errors.Query.InvalidRequest") } diff --git a/internal/query/idp_user_link_test.go b/internal/query/idp_user_link_test.go index 4078662559..aa7387b970 100644 --- a/internal/query/idp_user_link_test.go +++ b/internal/query/idp_user_link_test.go @@ -12,16 +12,16 @@ import ( ) var ( - idpUserLinksQuery = regexp.QuoteMeta(`SELECT projections.idp_user_links2.idp_id,` + - ` projections.idp_user_links2.user_id,` + - ` projections.idps2.name,` + - ` projections.idp_user_links2.external_user_id,` + - ` projections.idp_user_links2.display_name,` + - ` projections.idps2.type,` + - ` projections.idp_user_links2.resource_owner,` + + idpUserLinksQuery = regexp.QuoteMeta(`SELECT projections.idp_user_links3.idp_id,` + + ` projections.idp_user_links3.user_id,` + + ` projections.idps3.name,` + + ` projections.idp_user_links3.external_user_id,` + + ` projections.idp_user_links3.display_name,` + + ` projections.idps3.type,` + + ` projections.idp_user_links3.resource_owner,` + ` COUNT(*) OVER ()` + - ` FROM projections.idp_user_links2` + - ` LEFT JOIN projections.idps2 ON projections.idp_user_links2.idp_id = projections.idps2.id`) + ` FROM projections.idp_user_links3` + + ` LEFT JOIN projections.idps3 ON projections.idp_user_links3.idp_id = projections.idps3.id`) idpUserLinksCols = []string{ "idp_id", "user_id", diff --git a/internal/query/key.go b/internal/query/key.go index 0f91539a10..510c520c5b 100644 --- a/internal/query/key.go +++ b/internal/query/key.go @@ -183,12 +183,8 @@ func (q *Queries) ActivePublicKeys(ctx context.Context, t time.Time) (*PublicKey } stmt, args, err := query.Where( sq.And{ - sq.Eq{ - KeyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - sq.Gt{ - KeyPublicColExpiry.identifier(): t, - }, + sq.Eq{KeyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, + sq.Gt{KeyPublicColExpiry.identifier(): t}, }).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-SDFfg", "Errors.Query.SQLStatement") @@ -220,9 +216,7 @@ func (q *Queries) ActivePrivateSigningKey(ctx context.Context, t time.Time) (*Pr KeyColUse.identifier(): domain.KeyUsageSigning, KeyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), }, - sq.Gt{ - KeyPrivateColExpiry.identifier(): t, - }, + sq.Gt{KeyPrivateColExpiry.identifier(): t}, }).OrderBy(KeyPrivateColExpiry.identifier()).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-SDff2", "Errors.Query.SQLStatement") diff --git a/internal/query/key_test.go b/internal/query/key_test.go index aaca437b16..fee2ea552f 100644 --- a/internal/query/key_test.go +++ b/internal/query/key_test.go @@ -31,18 +31,18 @@ func Test_KeyPrepares(t *testing.T) { prepare: preparePublicKeysQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.keys3.id,`+ - ` projections.keys3.creation_date,`+ - ` projections.keys3.change_date,`+ - ` projections.keys3.sequence,`+ - ` projections.keys3.resource_owner,`+ - ` projections.keys3.algorithm,`+ - ` projections.keys3.use,`+ - ` projections.keys3_public.expiry,`+ - ` projections.keys3_public.key,`+ + regexp.QuoteMeta(`SELECT projections.keys4.id,`+ + ` projections.keys4.creation_date,`+ + ` projections.keys4.change_date,`+ + ` projections.keys4.sequence,`+ + ` projections.keys4.resource_owner,`+ + ` projections.keys4.algorithm,`+ + ` projections.keys4.use,`+ + ` projections.keys4_public.expiry,`+ + ` projections.keys4_public.key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.keys3`+ - ` LEFT JOIN projections.keys3_public ON projections.keys3.id = projections.keys3_public.id`), + ` FROM projections.keys4`+ + ` LEFT JOIN projections.keys4_public ON projections.keys4.id = projections.keys4_public.id`), nil, nil, ), @@ -60,18 +60,18 @@ func Test_KeyPrepares(t *testing.T) { prepare: preparePublicKeysQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.keys3.id,`+ - ` projections.keys3.creation_date,`+ - ` projections.keys3.change_date,`+ - ` projections.keys3.sequence,`+ - ` projections.keys3.resource_owner,`+ - ` projections.keys3.algorithm,`+ - ` projections.keys3.use,`+ - ` projections.keys3_public.expiry,`+ - ` projections.keys3_public.key,`+ + regexp.QuoteMeta(`SELECT projections.keys4.id,`+ + ` projections.keys4.creation_date,`+ + ` projections.keys4.change_date,`+ + ` projections.keys4.sequence,`+ + ` projections.keys4.resource_owner,`+ + ` projections.keys4.algorithm,`+ + ` projections.keys4.use,`+ + ` projections.keys4_public.expiry,`+ + ` projections.keys4_public.key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.keys3`+ - ` LEFT JOIN projections.keys3_public ON projections.keys3.id = projections.keys3_public.id`), + ` FROM projections.keys4`+ + ` LEFT JOIN projections.keys4_public ON projections.keys4.id = projections.keys4_public.id`), []string{ "id", "creation_date", @@ -128,18 +128,18 @@ func Test_KeyPrepares(t *testing.T) { prepare: preparePublicKeysQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.keys3.id,`+ - ` projections.keys3.creation_date,`+ - ` projections.keys3.change_date,`+ - ` projections.keys3.sequence,`+ - ` projections.keys3.resource_owner,`+ - ` projections.keys3.algorithm,`+ - ` projections.keys3.use,`+ - ` projections.keys3_public.expiry,`+ - ` projections.keys3_public.key,`+ + regexp.QuoteMeta(`SELECT projections.keys4.id,`+ + ` projections.keys4.creation_date,`+ + ` projections.keys4.change_date,`+ + ` projections.keys4.sequence,`+ + ` projections.keys4.resource_owner,`+ + ` projections.keys4.algorithm,`+ + ` projections.keys4.use,`+ + ` projections.keys4_public.expiry,`+ + ` projections.keys4_public.key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.keys3`+ - ` LEFT JOIN projections.keys3_public ON projections.keys3.id = projections.keys3_public.id`), + ` FROM projections.keys4`+ + ` LEFT JOIN projections.keys4_public ON projections.keys4.id = projections.keys4_public.id`), sql.ErrConnDone, ), err: func(err error) (error, bool) { @@ -156,18 +156,18 @@ func Test_KeyPrepares(t *testing.T) { prepare: preparePrivateKeysQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.keys3.id,`+ - ` projections.keys3.creation_date,`+ - ` projections.keys3.change_date,`+ - ` projections.keys3.sequence,`+ - ` projections.keys3.resource_owner,`+ - ` projections.keys3.algorithm,`+ - ` projections.keys3.use,`+ - ` projections.keys3_private.expiry,`+ - ` projections.keys3_private.key,`+ + regexp.QuoteMeta(`SELECT projections.keys4.id,`+ + ` projections.keys4.creation_date,`+ + ` projections.keys4.change_date,`+ + ` projections.keys4.sequence,`+ + ` projections.keys4.resource_owner,`+ + ` projections.keys4.algorithm,`+ + ` projections.keys4.use,`+ + ` projections.keys4_private.expiry,`+ + ` projections.keys4_private.key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.keys3`+ - ` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id`), + ` FROM projections.keys4`+ + ` LEFT JOIN projections.keys4_private ON projections.keys4.id = projections.keys4_private.id`), nil, nil, ), @@ -185,18 +185,18 @@ func Test_KeyPrepares(t *testing.T) { prepare: preparePrivateKeysQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.keys3.id,`+ - ` projections.keys3.creation_date,`+ - ` projections.keys3.change_date,`+ - ` projections.keys3.sequence,`+ - ` projections.keys3.resource_owner,`+ - ` projections.keys3.algorithm,`+ - ` projections.keys3.use,`+ - ` projections.keys3_private.expiry,`+ - ` projections.keys3_private.key,`+ + regexp.QuoteMeta(`SELECT projections.keys4.id,`+ + ` projections.keys4.creation_date,`+ + ` projections.keys4.change_date,`+ + ` projections.keys4.sequence,`+ + ` projections.keys4.resource_owner,`+ + ` projections.keys4.algorithm,`+ + ` projections.keys4.use,`+ + ` projections.keys4_private.expiry,`+ + ` projections.keys4_private.key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.keys3`+ - ` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id`), + ` FROM projections.keys4`+ + ` LEFT JOIN projections.keys4_private ON projections.keys4.id = projections.keys4_private.id`), []string{ "id", "creation_date", @@ -255,18 +255,18 @@ func Test_KeyPrepares(t *testing.T) { prepare: preparePrivateKeysQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.keys3.id,`+ - ` projections.keys3.creation_date,`+ - ` projections.keys3.change_date,`+ - ` projections.keys3.sequence,`+ - ` projections.keys3.resource_owner,`+ - ` projections.keys3.algorithm,`+ - ` projections.keys3.use,`+ - ` projections.keys3_private.expiry,`+ - ` projections.keys3_private.key,`+ + regexp.QuoteMeta(`SELECT projections.keys4.id,`+ + ` projections.keys4.creation_date,`+ + ` projections.keys4.change_date,`+ + ` projections.keys4.sequence,`+ + ` projections.keys4.resource_owner,`+ + ` projections.keys4.algorithm,`+ + ` projections.keys4.use,`+ + ` projections.keys4_private.expiry,`+ + ` projections.keys4_private.key,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.keys3`+ - ` LEFT JOIN projections.keys3_private ON projections.keys3.id = projections.keys3_private.id`), + ` FROM projections.keys4`+ + ` LEFT JOIN projections.keys4_private ON projections.keys4.id = projections.keys4_private.id`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/label_policy.go b/internal/query/label_policy.go index 88b49b0e4a..8ce611b24e 100644 --- a/internal/query/label_policy.go +++ b/internal/query/label_policy.go @@ -40,22 +40,22 @@ type Theme struct { IconURL string } -func (q *Queries) ActiveLabelPolicyByOrg(ctx context.Context, orgID string) (*LabelPolicy, error) { +func (q *Queries) ActiveLabelPolicyByOrg(ctx context.Context, orgID string, withOwnerRemoved bool) (*LabelPolicy, error) { stmt, scan := prepareLabelPolicyQuery() + eq := sq.Eq{ + LabelPolicyColState.identifier(): domain.LabelPolicyStateActive, + LabelPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[LabelPolicyOwnerRemoved.identifier()] = false + } query, args, err := stmt.Where( sq.And{ sq.Or{ - sq.Eq{ - LabelPolicyColID.identifier(): orgID, - }, - sq.Eq{ - LabelPolicyColID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - }, - sq.Eq{ - LabelPolicyColState.identifier(): domain.LabelPolicyStateActive, - LabelPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + sq.Eq{LabelPolicyColID.identifier(): orgID}, + sq.Eq{LabelPolicyColID.identifier(): authz.GetInstance(ctx).InstanceID()}, }, + eq, }). OrderBy(LabelPolicyColIsDefault.identifier()). Limit(1).ToSql() @@ -205,6 +205,9 @@ var ( LabelPolicyColDarkIconURL = Column{ name: projection.LabelPolicyDarkIconURLCol, } + LabelPolicyOwnerRemoved = Column{ + name: projection.LabelPolicyOwnerRemovedCol, + } ) func prepareLabelPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*LabelPolicy, error)) { diff --git a/internal/query/lockout_policy.go b/internal/query/lockout_policy.go index 3ce51fa305..65f779317a 100644 --- a/internal/query/lockout_policy.go +++ b/internal/query/lockout_policy.go @@ -74,26 +74,30 @@ var ( name: projection.LockoutPolicyStateCol, table: lockoutTable, } + LockoutPolicyOwnerRemoved = Column{ + name: projection.LockoutPolicyOwnerRemovedCol, + table: lockoutTable, + } ) -func (q *Queries) LockoutPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string) (*LockoutPolicy, error) { +func (q *Queries) LockoutPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string, withOwnerRemoved bool) (*LockoutPolicy, error) { if shouldTriggerBulk { projection.LockoutPolicyProjection.Trigger(ctx) } + eq := sq.Eq{ + LockoutColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[LockoutPolicyOwnerRemoved.identifier()] = false + } stmt, scan := prepareLockoutPolicyQuery() query, args, err := stmt.Where( sq.And{ - sq.Eq{ - LockoutColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + eq, sq.Or{ - sq.Eq{ - LockoutColID.identifier(): orgID, - }, - sq.Eq{ - LockoutColID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + sq.Eq{LockoutColID.identifier(): orgID}, + sq.Eq{LockoutColID.identifier(): authz.GetInstance(ctx).InstanceID()}, }, }). OrderBy(LockoutColIsDefault.identifier()). diff --git a/internal/query/lockout_policy_test.go b/internal/query/lockout_policy_test.go index 41b1a78b0b..f8ebb70e25 100644 --- a/internal/query/lockout_policy_test.go +++ b/internal/query/lockout_policy_test.go @@ -28,16 +28,16 @@ func Test_LockoutPolicyPrepares(t *testing.T) { prepare: prepareLockoutPolicyQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.lockout_policies.id,`+ - ` projections.lockout_policies.sequence,`+ - ` projections.lockout_policies.creation_date,`+ - ` projections.lockout_policies.change_date,`+ - ` projections.lockout_policies.resource_owner,`+ - ` projections.lockout_policies.show_failure,`+ - ` projections.lockout_policies.max_password_attempts,`+ - ` projections.lockout_policies.is_default,`+ - ` projections.lockout_policies.state`+ - ` FROM projections.lockout_policies`), + regexp.QuoteMeta(`SELECT projections.lockout_policies2.id,`+ + ` projections.lockout_policies2.sequence,`+ + ` projections.lockout_policies2.creation_date,`+ + ` projections.lockout_policies2.change_date,`+ + ` projections.lockout_policies2.resource_owner,`+ + ` projections.lockout_policies2.show_failure,`+ + ` projections.lockout_policies2.max_password_attempts,`+ + ` projections.lockout_policies2.is_default,`+ + ` projections.lockout_policies2.state`+ + ` FROM projections.lockout_policies2`), nil, nil, ), @@ -55,16 +55,16 @@ func Test_LockoutPolicyPrepares(t *testing.T) { prepare: prepareLockoutPolicyQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.lockout_policies.id,`+ - ` projections.lockout_policies.sequence,`+ - ` projections.lockout_policies.creation_date,`+ - ` projections.lockout_policies.change_date,`+ - ` projections.lockout_policies.resource_owner,`+ - ` projections.lockout_policies.show_failure,`+ - ` projections.lockout_policies.max_password_attempts,`+ - ` projections.lockout_policies.is_default,`+ - ` projections.lockout_policies.state`+ - ` FROM projections.lockout_policies`), + regexp.QuoteMeta(`SELECT projections.lockout_policies2.id,`+ + ` projections.lockout_policies2.sequence,`+ + ` projections.lockout_policies2.creation_date,`+ + ` projections.lockout_policies2.change_date,`+ + ` projections.lockout_policies2.resource_owner,`+ + ` projections.lockout_policies2.show_failure,`+ + ` projections.lockout_policies2.max_password_attempts,`+ + ` projections.lockout_policies2.is_default,`+ + ` projections.lockout_policies2.state`+ + ` FROM projections.lockout_policies2`), []string{ "id", "sequence", @@ -106,16 +106,16 @@ func Test_LockoutPolicyPrepares(t *testing.T) { prepare: prepareLockoutPolicyQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.lockout_policies.id,`+ - ` projections.lockout_policies.sequence,`+ - ` projections.lockout_policies.creation_date,`+ - ` projections.lockout_policies.change_date,`+ - ` projections.lockout_policies.resource_owner,`+ - ` projections.lockout_policies.show_failure,`+ - ` projections.lockout_policies.max_password_attempts,`+ - ` projections.lockout_policies.is_default,`+ - ` projections.lockout_policies.state`+ - ` FROM projections.lockout_policies`), + regexp.QuoteMeta(`SELECT projections.lockout_policies2.id,`+ + ` projections.lockout_policies2.sequence,`+ + ` projections.lockout_policies2.creation_date,`+ + ` projections.lockout_policies2.change_date,`+ + ` projections.lockout_policies2.resource_owner,`+ + ` projections.lockout_policies2.show_failure,`+ + ` projections.lockout_policies2.max_password_attempts,`+ + ` projections.lockout_policies2.is_default,`+ + ` projections.lockout_policies2.state`+ + ` FROM projections.lockout_policies2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/login_name.go b/internal/query/login_name.go index a63b499ce1..736f37f98a 100644 --- a/internal/query/login_name.go +++ b/internal/query/login_name.go @@ -8,7 +8,7 @@ var ( instanceIDCol: projection.LoginNameUserInstanceIDCol, } LoginNameUserIDCol = Column{ - name: "user_id", + name: projection.LoginNameUserCol, table: loginNameTable, } LoginNameNameCol = Column{ @@ -16,11 +16,29 @@ var ( table: loginNameTable, } LoginNameIsPrimaryCol = Column{ - name: projection.LoginNameDomainIsPrimaryCol, + name: projection.LoginNameIsPrimaryCol, table: loginNameTable, } LoginNameInstanceIDCol = Column{ - name: projection.LoginNameUserInstanceIDCol, + name: projection.LoginNameInstanceIDCol, + table: loginNameTable, + } + LoginNameOwnerRemovedDomainCol = Column{ + name: projection.LoginNameOwnerRemovedDomainCol, + table: loginNameTable, + } + LoginNameOwnerRemovedUserCol = Column{ + name: projection.LoginNameOwnerRemovedUserCol, + table: loginNameTable, + } + LoginNameOwnerRemovedPolicyCol = Column{ + name: projection.LoginNameOwnerRemovedPolicyCol, table: loginNameTable, } ) + +func addLoginNameWithoutOwnerRemoved(eq map[string]interface{}) { + eq[LoginNameOwnerRemovedDomainCol.identifier()] = false + eq[LoginNameOwnerRemovedUserCol.identifier()] = false + eq[LoginNameOwnerRemovedPolicyCol.identifier()] = false +} diff --git a/internal/query/login_policy.go b/internal/query/login_policy.go index 01460dc6f1..f468da8003 100644 --- a/internal/query/login_policy.go +++ b/internal/query/login_policy.go @@ -149,30 +149,32 @@ var ( name: projection.SecondFactorCheckLifetimeCol, table: loginPolicyTable, } - LoginPolicyColumnMultiFacotrCheckLifetime = Column{ + LoginPolicyColumnMultiFactorCheckLifetime = Column{ name: projection.MultiFactorCheckLifetimeCol, table: loginPolicyTable, } + LoginPolicyColumnOwnerRemoved = Column{ + name: projection.LoginPolicyOwnerRemovedCol, + table: loginPolicyTable, + } ) -func (q *Queries) LoginPolicyByID(ctx context.Context, shouldTriggerBulk bool, orgID string) (*LoginPolicy, error) { +func (q *Queries) LoginPolicyByID(ctx context.Context, shouldTriggerBulk bool, orgID string, withOwnerRemoved bool) (*LoginPolicy, error) { if shouldTriggerBulk { projection.LoginPolicyProjection.Trigger(ctx) } + eq := sq.Eq{LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[LoginPolicyColumnOwnerRemoved.identifier()] = false + } query, scan := prepareLoginPolicyQuery() stmt, args, err := query.Where( sq.And{ - sq.Eq{ - LoginPolicyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + eq, sq.Or{ - sq.Eq{ - LoginPolicyColumnOrgID.identifier(): orgID, - }, - sq.Eq{ - LoginPolicyColumnOrgID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + sq.Eq{LoginPolicyColumnOrgID.identifier(): orgID}, + sq.Eq{LoginPolicyColumnOrgID.identifier(): authz.GetInstance(ctx).InstanceID()}, }, }).Limit(1).OrderBy(LoginPolicyColumnIsDefault.identifier()).ToSql() if err != nil { @@ -192,7 +194,7 @@ func (q *Queries) scanAndAddLinksToLoginPolicy(ctx context.Context, rows *sql.Ro return nil, err } - links, err := q.IDPLoginPolicyLinks(ctx, policy.OrgID, &IDPLoginPolicyLinksSearchQuery{}) + links, err := q.IDPLoginPolicyLinks(ctx, policy.OrgID, &IDPLoginPolicyLinksSearchQuery{}, false) if err != nil { return nil, err } @@ -343,7 +345,7 @@ func prepareLoginPolicyQuery() (sq.SelectBuilder, func(*sql.Rows) (*LoginPolicy, LoginPolicyColumnExternalLoginCheckLifetime.identifier(), LoginPolicyColumnMFAInitSkipLifetime.identifier(), LoginPolicyColumnSecondFactorCheckLifetime.identifier(), - LoginPolicyColumnMultiFacotrCheckLifetime.identifier(), + LoginPolicyColumnMultiFactorCheckLifetime.identifier(), ).From(loginPolicyTable.identifier()). PlaceholderFormat(sq.Dollar), func(rows *sql.Rows) (*LoginPolicy, error) { diff --git a/internal/query/login_policy_test.go b/internal/query/login_policy_test.go index f4f36cb497..fdf2230908 100644 --- a/internal/query/login_policy_test.go +++ b/internal/query/login_policy_test.go @@ -15,30 +15,30 @@ import ( ) var ( - loginPolicyQuery = `SELECT projections.login_policies3.aggregate_id,` + - ` projections.login_policies3.creation_date,` + - ` projections.login_policies3.change_date,` + - ` projections.login_policies3.sequence,` + - ` projections.login_policies3.allow_register,` + - ` projections.login_policies3.allow_username_password,` + - ` projections.login_policies3.allow_external_idps,` + - ` projections.login_policies3.force_mfa,` + - ` projections.login_policies3.second_factors,` + - ` projections.login_policies3.multi_factors,` + - ` projections.login_policies3.passwordless_type,` + - ` projections.login_policies3.is_default,` + - ` projections.login_policies3.hide_password_reset,` + - ` projections.login_policies3.ignore_unknown_usernames,` + - ` projections.login_policies3.allow_domain_discovery,` + - ` projections.login_policies3.disable_login_with_email,` + - ` projections.login_policies3.disable_login_with_phone,` + - ` projections.login_policies3.default_redirect_uri,` + - ` projections.login_policies3.password_check_lifetime,` + - ` projections.login_policies3.external_login_check_lifetime,` + - ` projections.login_policies3.mfa_init_skip_lifetime,` + - ` projections.login_policies3.second_factor_check_lifetime,` + - ` projections.login_policies3.multi_factor_check_lifetime` + - ` FROM projections.login_policies3` + loginPolicyQuery = `SELECT projections.login_policies4.aggregate_id,` + + ` projections.login_policies4.creation_date,` + + ` projections.login_policies4.change_date,` + + ` projections.login_policies4.sequence,` + + ` projections.login_policies4.allow_register,` + + ` projections.login_policies4.allow_username_password,` + + ` projections.login_policies4.allow_external_idps,` + + ` projections.login_policies4.force_mfa,` + + ` projections.login_policies4.second_factors,` + + ` projections.login_policies4.multi_factors,` + + ` projections.login_policies4.passwordless_type,` + + ` projections.login_policies4.is_default,` + + ` projections.login_policies4.hide_password_reset,` + + ` projections.login_policies4.ignore_unknown_usernames,` + + ` projections.login_policies4.allow_domain_discovery,` + + ` projections.login_policies4.disable_login_with_email,` + + ` projections.login_policies4.disable_login_with_phone,` + + ` projections.login_policies4.default_redirect_uri,` + + ` projections.login_policies4.password_check_lifetime,` + + ` projections.login_policies4.external_login_check_lifetime,` + + ` projections.login_policies4.mfa_init_skip_lifetime,` + + ` projections.login_policies4.second_factor_check_lifetime,` + + ` projections.login_policies4.multi_factor_check_lifetime` + + ` FROM projections.login_policies4` loginPolicyCols = []string{ "aggregate_id", "creation_date", @@ -177,8 +177,8 @@ func Test_LoginPolicyPrepares(t *testing.T) { prepare: prepareLoginPolicy2FAsQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.login_policies3.second_factors`+ - ` FROM projections.login_policies3`), + regexp.QuoteMeta(`SELECT projections.login_policies4.second_factors`+ + ` FROM projections.login_policies4`), []string{ "second_factors", }, @@ -198,8 +198,8 @@ func Test_LoginPolicyPrepares(t *testing.T) { prepare: prepareLoginPolicy2FAsQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.login_policies3.second_factors`+ - ` FROM projections.login_policies3`), + regexp.QuoteMeta(`SELECT projections.login_policies4.second_factors`+ + ` FROM projections.login_policies4`), []string{ "second_factors", }, @@ -220,8 +220,8 @@ func Test_LoginPolicyPrepares(t *testing.T) { prepare: prepareLoginPolicy2FAsQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.login_policies3.second_factors`+ - ` FROM projections.login_policies3`), + regexp.QuoteMeta(`SELECT projections.login_policies4.second_factors`+ + ` FROM projections.login_policies4`), []string{ "second_factors", }, @@ -237,8 +237,8 @@ func Test_LoginPolicyPrepares(t *testing.T) { prepare: prepareLoginPolicy2FAsQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.login_policies3.second_factors`+ - ` FROM projections.login_policies3`), + regexp.QuoteMeta(`SELECT projections.login_policies4.second_factors`+ + ` FROM projections.login_policies4`), sql.ErrConnDone, ), err: func(err error) (error, bool) { @@ -255,8 +255,8 @@ func Test_LoginPolicyPrepares(t *testing.T) { prepare: prepareLoginPolicyMFAsQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.login_policies3.multi_factors`+ - ` FROM projections.login_policies3`), + regexp.QuoteMeta(`SELECT projections.login_policies4.multi_factors`+ + ` FROM projections.login_policies4`), []string{ "multi_factors", }, @@ -276,8 +276,8 @@ func Test_LoginPolicyPrepares(t *testing.T) { prepare: prepareLoginPolicyMFAsQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.login_policies3.multi_factors`+ - ` FROM projections.login_policies3`), + regexp.QuoteMeta(`SELECT projections.login_policies4.multi_factors`+ + ` FROM projections.login_policies4`), []string{ "multi_factors", }, @@ -298,8 +298,8 @@ func Test_LoginPolicyPrepares(t *testing.T) { prepare: prepareLoginPolicyMFAsQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.login_policies3.multi_factors`+ - ` FROM projections.login_policies3`), + regexp.QuoteMeta(`SELECT projections.login_policies4.multi_factors`+ + ` FROM projections.login_policies4`), []string{ "multi_factors", }, @@ -315,8 +315,8 @@ func Test_LoginPolicyPrepares(t *testing.T) { prepare: prepareLoginPolicyMFAsQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.login_policies3.multi_factors`+ - ` FROM projections.login_policies3`), + regexp.QuoteMeta(`SELECT projections.login_policies4.multi_factors`+ + ` FROM projections.login_policies4`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/mail_template.go b/internal/query/mail_template.go index 59ccfeeaa6..4ea256a854 100644 --- a/internal/query/mail_template.go +++ b/internal/query/mail_template.go @@ -62,22 +62,24 @@ var ( name: projection.MailTemplateStateCol, table: mailTemplateTable, } + MailTemplateColOwnerRemoved = Column{ + name: projection.MailTemplateOwnerRemovedCol, + table: mailTemplateTable, + } ) -func (q *Queries) MailTemplateByOrg(ctx context.Context, orgID string) (*MailTemplate, error) { +func (q *Queries) MailTemplateByOrg(ctx context.Context, orgID string, withOwnerRemoved bool) (*MailTemplate, error) { stmt, scan := prepareMailTemplateQuery() + eq := sq.Eq{MailTemplateColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[MailTemplateColOwnerRemoved.identifier()] = false + } query, args, err := stmt.Where( sq.And{ - sq.Eq{ - MailTemplateColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + eq, sq.Or{ - sq.Eq{ - MailTemplateColAggregateID.identifier(): orgID, - }, - sq.Eq{ - MailTemplateColAggregateID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + sq.Eq{MailTemplateColAggregateID.identifier(): orgID}, + sq.Eq{MailTemplateColAggregateID.identifier(): authz.GetInstance(ctx).InstanceID()}, }, }). OrderBy(MailTemplateColIsDefault.identifier()). diff --git a/internal/query/message_text.go b/internal/query/message_text.go index ff2ddf037a..7a49abf0a2 100644 --- a/internal/query/message_text.go +++ b/internal/query/message_text.go @@ -116,6 +116,10 @@ var ( name: projection.MessageTextFooterCol, table: messageTextTable, } + MessageTextColOwnerRemoved = Column{ + name: projection.MessageTextOwnerRemovedCol, + table: messageTextTable, + } ) func (q *Queries) DefaultMessageText(ctx context.Context) (*MessageText, error) { @@ -145,18 +149,19 @@ func (q *Queries) DefaultMessageTextByTypeAndLanguageFromFileSystem(ctx context. return messageTexts.GetMessageTextByType(messageType), nil } -func (q *Queries) CustomMessageTextByTypeAndLanguage(ctx context.Context, aggregateID, messageType, language string) (*MessageText, error) { +func (q *Queries) CustomMessageTextByTypeAndLanguage(ctx context.Context, aggregateID, messageType, language string, withOwnerRemoved bool) (*MessageText, error) { stmt, scan := prepareMessageTextQuery() - query, args, err := stmt.Where( - sq.Eq{ - MessageTextColLanguage.identifier(): language, - MessageTextColType.identifier(): messageType, - MessageTextColAggregateID.identifier(): aggregateID, - MessageTextColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, - ). - OrderBy(MessageTextColAggregateID.identifier()). - Limit(1).ToSql() + eq := sq.Eq{ + MessageTextColLanguage.identifier(): language, + MessageTextColType.identifier(): messageType, + MessageTextColAggregateID.identifier(): aggregateID, + MessageTextColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[MessageTextColOwnerRemoved.identifier()] = false + } + + query, args, err := stmt.Where(eq).OrderBy(MessageTextColAggregateID.identifier()).Limit(1).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-1b9mf", "Errors.Query.SQLStatement") } @@ -178,7 +183,7 @@ func (q *Queries) IAMMessageTextByTypeAndLanguage(ctx context.Context, messageTy if err := yaml.Unmarshal(contents, ¬ificationTextMap); err != nil { return nil, errors.ThrowInternal(err, "QUERY-ekjFF", "Errors.TranslationFile.ReadError") } - texts, err := q.CustomTextList(ctx, authz.GetInstance(ctx).InstanceID(), messageType, language) + texts, err := q.CustomTextList(ctx, authz.GetInstance(ctx).InstanceID(), messageType, language, false) if err != nil { return nil, err } diff --git a/internal/query/message_text_test.go b/internal/query/message_text_test.go index 2208b23eee..af54f6ac7d 100644 --- a/internal/query/message_text_test.go +++ b/internal/query/message_text_test.go @@ -30,21 +30,21 @@ func Test_MessageTextPrepares(t *testing.T) { prepare: prepareMessageTextQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.message_texts.aggregate_id,`+ - ` projections.message_texts.sequence,`+ - ` projections.message_texts.creation_date,`+ - ` projections.message_texts.change_date,`+ - ` projections.message_texts.state,`+ - ` projections.message_texts.type,`+ - ` projections.message_texts.language,`+ - ` projections.message_texts.title,`+ - ` projections.message_texts.pre_header,`+ - ` projections.message_texts.subject,`+ - ` projections.message_texts.greeting,`+ - ` projections.message_texts.text,`+ - ` projections.message_texts.button_text,`+ - ` projections.message_texts.footer_text`+ - ` FROM projections.message_texts`), + regexp.QuoteMeta(`SELECT projections.message_texts2.aggregate_id,`+ + ` projections.message_texts2.sequence,`+ + ` projections.message_texts2.creation_date,`+ + ` projections.message_texts2.change_date,`+ + ` projections.message_texts2.state,`+ + ` projections.message_texts2.type,`+ + ` projections.message_texts2.language,`+ + ` projections.message_texts2.title,`+ + ` projections.message_texts2.pre_header,`+ + ` projections.message_texts2.subject,`+ + ` projections.message_texts2.greeting,`+ + ` projections.message_texts2.text,`+ + ` projections.message_texts2.button_text,`+ + ` projections.message_texts2.footer_text`+ + ` FROM projections.message_texts2`), nil, nil, ), @@ -62,21 +62,21 @@ func Test_MessageTextPrepares(t *testing.T) { prepare: prepareMessageTextQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.message_texts.aggregate_id,`+ - ` projections.message_texts.sequence,`+ - ` projections.message_texts.creation_date,`+ - ` projections.message_texts.change_date,`+ - ` projections.message_texts.state,`+ - ` projections.message_texts.type,`+ - ` projections.message_texts.language,`+ - ` projections.message_texts.title,`+ - ` projections.message_texts.pre_header,`+ - ` projections.message_texts.subject,`+ - ` projections.message_texts.greeting,`+ - ` projections.message_texts.text,`+ - ` projections.message_texts.button_text,`+ - ` projections.message_texts.footer_text`+ - ` FROM projections.message_texts`), + regexp.QuoteMeta(`SELECT projections.message_texts2.aggregate_id,`+ + ` projections.message_texts2.sequence,`+ + ` projections.message_texts2.creation_date,`+ + ` projections.message_texts2.change_date,`+ + ` projections.message_texts2.state,`+ + ` projections.message_texts2.type,`+ + ` projections.message_texts2.language,`+ + ` projections.message_texts2.title,`+ + ` projections.message_texts2.pre_header,`+ + ` projections.message_texts2.subject,`+ + ` projections.message_texts2.greeting,`+ + ` projections.message_texts2.text,`+ + ` projections.message_texts2.button_text,`+ + ` projections.message_texts2.footer_text`+ + ` FROM projections.message_texts2`), []string{ "aggregate_id", "sequence", @@ -133,21 +133,21 @@ func Test_MessageTextPrepares(t *testing.T) { prepare: prepareMessageTextQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.message_texts.aggregate_id,`+ - ` projections.message_texts.sequence,`+ - ` projections.message_texts.creation_date,`+ - ` projections.message_texts.change_date,`+ - ` projections.message_texts.state,`+ - ` projections.message_texts.type,`+ - ` projections.message_texts.language,`+ - ` projections.message_texts.title,`+ - ` projections.message_texts.pre_header,`+ - ` projections.message_texts.subject,`+ - ` projections.message_texts.greeting,`+ - ` projections.message_texts.text,`+ - ` projections.message_texts.button_text,`+ - ` projections.message_texts.footer_text`+ - ` FROM projections.message_texts`), + regexp.QuoteMeta(`SELECT projections.message_texts2.aggregate_id,`+ + ` projections.message_texts2.sequence,`+ + ` projections.message_texts2.creation_date,`+ + ` projections.message_texts2.change_date,`+ + ` projections.message_texts2.state,`+ + ` projections.message_texts2.type,`+ + ` projections.message_texts2.language,`+ + ` projections.message_texts2.title,`+ + ` projections.message_texts2.pre_header,`+ + ` projections.message_texts2.subject,`+ + ` projections.message_texts2.greeting,`+ + ` projections.message_texts2.text,`+ + ` projections.message_texts2.button_text,`+ + ` projections.message_texts2.footer_text`+ + ` FROM projections.message_texts2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/notification_provider.go b/internal/query/notification_provider.go index 60be34c09a..9a3b104309 100644 --- a/internal/query/notification_provider.go +++ b/internal/query/notification_provider.go @@ -73,9 +73,7 @@ func (q *Queries) NotificationProviderByIDAndType(ctx context.Context, aggID str query, scan := prepareDebugNotificationProviderQuery() stmt, args, err := query.Where( sq.And{ - sq.Eq{ - NotificationProviderColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + sq.Eq{NotificationProviderColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}, sq.Or{ sq.Eq{ NotificationProviderColumnAggID.identifier(): aggID, diff --git a/internal/query/org_domain.go b/internal/query/org_domain.go index f0d051aa6a..bdb1a345ad 100644 --- a/internal/query/org_domain.go +++ b/internal/query/org_domain.go @@ -54,12 +54,13 @@ func NewOrgDomainVerifiedSearchQuery(verified bool) (SearchQuery, error) { return NewBoolQuery(OrgDomainIsVerifiedCol, verified) } -func (q *Queries) SearchOrgDomains(ctx context.Context, queries *OrgDomainSearchQueries) (domains *Domains, err error) { +func (q *Queries) SearchOrgDomains(ctx context.Context, queries *OrgDomainSearchQueries, withOwnerRemoved bool) (domains *Domains, err error) { query, scan := prepareDomainsQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - OrgDomainInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{OrgDomainInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[OrgDomainOwnerRemovedCol.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-ZRfj1", "Errors.Query.SQLStatement") } @@ -165,4 +166,8 @@ var ( name: projection.OrgDomainValidationTypeCol, table: orgDomainsTable, } + OrgDomainOwnerRemovedCol = Column{ + name: projection.OrgDomainOwnerRemovedCol, + table: orgDomainsTable, + } ) diff --git a/internal/query/org_domain_test.go b/internal/query/org_domain_test.go index 73f18f20be..3a4395a081 100644 --- a/internal/query/org_domain_test.go +++ b/internal/query/org_domain_test.go @@ -27,16 +27,16 @@ func Test_OrgDomainPrepares(t *testing.T) { prepare: prepareDomainsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.org_domains.creation_date,`+ - ` projections.org_domains.change_date,`+ - ` projections.org_domains.sequence,`+ - ` projections.org_domains.domain,`+ - ` projections.org_domains.org_id,`+ - ` projections.org_domains.is_verified,`+ - ` projections.org_domains.is_primary,`+ - ` projections.org_domains.validation_type,`+ + regexp.QuoteMeta(`SELECT projections.org_domains2.creation_date,`+ + ` projections.org_domains2.change_date,`+ + ` projections.org_domains2.sequence,`+ + ` projections.org_domains2.domain,`+ + ` projections.org_domains2.org_id,`+ + ` projections.org_domains2.is_verified,`+ + ` projections.org_domains2.is_primary,`+ + ` projections.org_domains2.validation_type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.org_domains`), + ` FROM projections.org_domains2`), nil, nil, ), @@ -48,16 +48,16 @@ func Test_OrgDomainPrepares(t *testing.T) { prepare: prepareDomainsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.org_domains.creation_date,`+ - ` projections.org_domains.change_date,`+ - ` projections.org_domains.sequence,`+ - ` projections.org_domains.domain,`+ - ` projections.org_domains.org_id,`+ - ` projections.org_domains.is_verified,`+ - ` projections.org_domains.is_primary,`+ - ` projections.org_domains.validation_type,`+ + regexp.QuoteMeta(`SELECT projections.org_domains2.creation_date,`+ + ` projections.org_domains2.change_date,`+ + ` projections.org_domains2.sequence,`+ + ` projections.org_domains2.domain,`+ + ` projections.org_domains2.org_id,`+ + ` projections.org_domains2.is_verified,`+ + ` projections.org_domains2.is_primary,`+ + ` projections.org_domains2.validation_type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.org_domains`), + ` FROM projections.org_domains2`), []string{ "id", "creation_date", @@ -106,16 +106,16 @@ func Test_OrgDomainPrepares(t *testing.T) { prepare: prepareDomainsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.org_domains.creation_date,`+ - ` projections.org_domains.change_date,`+ - ` projections.org_domains.sequence,`+ - ` projections.org_domains.domain,`+ - ` projections.org_domains.org_id,`+ - ` projections.org_domains.is_verified,`+ - ` projections.org_domains.is_primary,`+ - ` projections.org_domains.validation_type,`+ + regexp.QuoteMeta(`SELECT projections.org_domains2.creation_date,`+ + ` projections.org_domains2.change_date,`+ + ` projections.org_domains2.sequence,`+ + ` projections.org_domains2.domain,`+ + ` projections.org_domains2.org_id,`+ + ` projections.org_domains2.is_verified,`+ + ` projections.org_domains2.is_primary,`+ + ` projections.org_domains2.validation_type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.org_domains`), + ` FROM projections.org_domains2`), []string{ "id", "creation_date", @@ -184,16 +184,16 @@ func Test_OrgDomainPrepares(t *testing.T) { prepare: prepareDomainsQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.org_domains.creation_date,`+ - ` projections.org_domains.change_date,`+ - ` projections.org_domains.sequence,`+ - ` projections.org_domains.domain,`+ - ` projections.org_domains.org_id,`+ - ` projections.org_domains.is_verified,`+ - ` projections.org_domains.is_primary,`+ - ` projections.org_domains.validation_type,`+ + regexp.QuoteMeta(`SELECT projections.org_domains2.creation_date,`+ + ` projections.org_domains2.change_date,`+ + ` projections.org_domains2.sequence,`+ + ` projections.org_domains2.domain,`+ + ` projections.org_domains2.org_id,`+ + ` projections.org_domains2.is_verified,`+ + ` projections.org_domains2.is_primary,`+ + ` projections.org_domains2.validation_type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.org_domains`), + ` FROM projections.org_domains2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/org_member.go b/internal/query/org_member.go index 3e7114dad2..e04232f6b9 100644 --- a/internal/query/org_member.go +++ b/internal/query/org_member.go @@ -49,6 +49,14 @@ var ( name: projection.OrgMemberOrgIDCol, table: orgMemberTable, } + OrgMemberOwnerRemoved = Column{ + name: projection.MemberOwnerRemoved, + table: orgMemberTable, + } + OrgMemberOwnerRemovedUser = Column{ + name: projection.MemberUserOwnerRemoved, + table: orgMemberTable, + } ) type OrgMembersQuery struct { @@ -62,12 +70,19 @@ func (q *OrgMembersQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { Where(sq.Eq{OrgMemberOrgID.identifier(): q.OrgID}) } -func (q *Queries) OrgMembers(ctx context.Context, queries *OrgMembersQuery) (*Members, error) { +func addOrgMemberWithoutOwnerRemoved(eq map[string]interface{}) { + eq[OrgMemberOwnerRemoved.identifier()] = false + eq[OrgMemberOwnerRemovedUser.identifier()] = false +} + +func (q *Queries) OrgMembers(ctx context.Context, queries *OrgMembersQuery, withOwnerRemoved bool) (*Members, error) { query, scan := prepareOrgMembersQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - OrgMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{OrgMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + addOrgMemberWithoutOwnerRemoved(eq) + addLoginNameWithoutOwnerRemoved(eq) + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-PDAVB", "Errors.Query.InvalidRequest") } diff --git a/internal/query/org_member_test.go b/internal/query/org_member_test.go index fe3b5c4aee..583b8a15ad 100644 --- a/internal/query/org_member_test.go +++ b/internal/query/org_member_test.go @@ -19,25 +19,25 @@ var ( ", members.resource_owner" + ", members.user_id" + ", members.roles" + - ", projections.login_names.login_name" + - ", projections.users5_humans.email" + - ", projections.users5_humans.first_name" + - ", projections.users5_humans.last_name" + - ", projections.users5_humans.display_name" + - ", projections.users5_machines.name" + - ", projections.users5_humans.avatar_key" + + ", projections.login_names2.login_name" + + ", projections.users6_humans.email" + + ", projections.users6_humans.first_name" + + ", projections.users6_humans.last_name" + + ", projections.users6_humans.display_name" + + ", projections.users6_machines.name" + + ", projections.users6_humans.avatar_key" + ", COUNT(*) OVER () " + - "FROM projections.org_members2 AS members " + - "LEFT JOIN projections.users5_humans " + - "ON members.user_id = projections.users5_humans.user_id " + - "AND members.instance_id = projections.users5_humans.instance_id " + - "LEFT JOIN projections.users5_machines " + - "ON members.user_id = projections.users5_machines.user_id " + - "AND members.instance_id = projections.users5_machines.instance_id " + - "LEFT JOIN projections.login_names " + - "ON members.user_id = projections.login_names.user_id " + - "AND members.instance_id = projections.login_names.instance_id " + - "WHERE projections.login_names.is_primary = $1") + "FROM projections.org_members3 AS members " + + "LEFT JOIN projections.users6_humans " + + "ON members.user_id = projections.users6_humans.user_id " + + "AND members.instance_id = projections.users6_humans.instance_id " + + "LEFT JOIN projections.users6_machines " + + "ON members.user_id = projections.users6_machines.user_id " + + "AND members.instance_id = projections.users6_machines.instance_id " + + "LEFT JOIN projections.login_names2 " + + "ON members.user_id = projections.login_names2.user_id " + + "AND members.instance_id = projections.login_names2.instance_id " + + "WHERE projections.login_names2.is_primary = $1") orgMembersColumns = []string{ "creation_date", "change_date", diff --git a/internal/query/org_metadata.go b/internal/query/org_metadata.go index ddb618e996..4b0f20b0a2 100644 --- a/internal/query/org_metadata.go +++ b/internal/query/org_metadata.go @@ -69,9 +69,13 @@ var ( name: projection.OrgMetadataColumnValue, table: orgMetadataTable, } + OrgMetadataOwnerRemovedCol = Column{ + name: projection.OrgMetadataColumnOwnerRemoved, + table: orgMetadataTable, + } ) -func (q *Queries) GetOrgMetadataByKey(ctx context.Context, shouldTriggerBulk bool, orgID string, key string, queries ...SearchQuery) (*OrgMetadata, error) { +func (q *Queries) GetOrgMetadataByKey(ctx context.Context, shouldTriggerBulk bool, orgID string, key string, withOwnerRemoved bool, queries ...SearchQuery) (*OrgMetadata, error) { if shouldTriggerBulk { projection.OrgMetadataProjection.Trigger(ctx) } @@ -80,12 +84,15 @@ func (q *Queries) GetOrgMetadataByKey(ctx context.Context, shouldTriggerBulk boo for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where( - sq.Eq{ - OrgMetadataOrgIDCol.identifier(): orgID, - OrgMetadataKeyCol.identifier(): key, - OrgMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{ + OrgMetadataOrgIDCol.identifier(): orgID, + OrgMetadataKeyCol.identifier(): key, + OrgMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[OrgMetadataOwnerRemovedCol.identifier()] = false + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-aDaG2", "Errors.Query.SQLStatment") } @@ -94,18 +101,19 @@ func (q *Queries) GetOrgMetadataByKey(ctx context.Context, shouldTriggerBulk boo return scan(row) } -func (q *Queries) SearchOrgMetadata(ctx context.Context, shouldTriggerBulk bool, orgID string, queries *OrgMetadataSearchQueries) (*OrgMetadataList, error) { +func (q *Queries) SearchOrgMetadata(ctx context.Context, shouldTriggerBulk bool, orgID string, queries *OrgMetadataSearchQueries, withOwnerRemoved bool) (*OrgMetadataList, error) { if shouldTriggerBulk { projection.OrgMetadataProjection.Trigger(ctx) } - + eq := sq.Eq{ + OrgMetadataOrgIDCol.identifier(): orgID, + OrgMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[OrgMetadataOwnerRemovedCol.identifier()] = false + } query, scan := prepareOrgMetadataListQuery() - stmt, args, err := queries.toQuery(query).Where( - sq.Eq{ - OrgMetadataOrgIDCol.identifier(): orgID, - OrgMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }). - ToSql() + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Egbld", "Errors.Query.SQLStatment") } diff --git a/internal/query/org_metadata_test.go b/internal/query/org_metadata_test.go index eec9f96f0c..78bb48a176 100644 --- a/internal/query/org_metadata_test.go +++ b/internal/query/org_metadata_test.go @@ -12,13 +12,13 @@ import ( ) var ( - orgMetadataQuery = `SELECT projections.org_metadata.creation_date,` + - ` projections.org_metadata.change_date,` + - ` projections.org_metadata.resource_owner,` + - ` projections.org_metadata.sequence,` + - ` projections.org_metadata.key,` + - ` projections.org_metadata.value` + - ` FROM projections.org_metadata` + orgMetadataQuery = `SELECT projections.org_metadata2.creation_date,` + + ` projections.org_metadata2.change_date,` + + ` projections.org_metadata2.resource_owner,` + + ` projections.org_metadata2.sequence,` + + ` projections.org_metadata2.key,` + + ` projections.org_metadata2.value` + + ` FROM projections.org_metadata2` orgMetadataCols = []string{ "creation_date", "change_date", @@ -27,14 +27,14 @@ var ( "key", "value", } - orgMetadataListQuery = `SELECT projections.org_metadata.creation_date,` + - ` projections.org_metadata.change_date,` + - ` projections.org_metadata.resource_owner,` + - ` projections.org_metadata.sequence,` + - ` projections.org_metadata.key,` + - ` projections.org_metadata.value,` + + orgMetadataListQuery = `SELECT projections.org_metadata2.creation_date,` + + ` projections.org_metadata2.change_date,` + + ` projections.org_metadata2.resource_owner,` + + ` projections.org_metadata2.sequence,` + + ` projections.org_metadata2.key,` + + ` projections.org_metadata2.value,` + ` COUNT(*) OVER ()` + - ` FROM projections.org_metadata` + ` FROM projections.org_metadata2` orgMetadataListCols = []string{ "creation_date", "change_date", diff --git a/internal/query/password_age_policy.go b/internal/query/password_age_policy.go index 868dda0566..60bb7e46af 100644 --- a/internal/query/password_age_policy.go +++ b/internal/query/password_age_policy.go @@ -73,26 +73,27 @@ var ( name: projection.AgePolicyStateCol, table: passwordAgeTable, } + PasswordAgeColOwnerRemoved = Column{ + name: projection.AgePolicyOwnerRemovedCol, + table: passwordAgeTable, + } ) -func (q *Queries) PasswordAgePolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string) (*PasswordAgePolicy, error) { +func (q *Queries) PasswordAgePolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string, withOwnerRemoved bool) (*PasswordAgePolicy, error) { if shouldTriggerBulk { projection.PasswordAgeProjection.Trigger(ctx) } - + eq := sq.Eq{PasswordAgeColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[PasswordAgeColOwnerRemoved.identifier()] = false + } stmt, scan := preparePasswordAgePolicyQuery() query, args, err := stmt.Where( sq.And{ - sq.Eq{ - PasswordAgeColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + eq, sq.Or{ - sq.Eq{ - PasswordAgeColID.identifier(): orgID, - }, - sq.Eq{ - PasswordAgeColID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + sq.Eq{PasswordAgeColID.identifier(): orgID}, + sq.Eq{PasswordAgeColID.identifier(): authz.GetInstance(ctx).InstanceID()}, }, }). OrderBy(PasswordAgeColIsDefault.identifier()). diff --git a/internal/query/password_age_policy_test.go b/internal/query/password_age_policy_test.go index 6caaa685c0..f11a78f4b1 100644 --- a/internal/query/password_age_policy_test.go +++ b/internal/query/password_age_policy_test.go @@ -28,16 +28,16 @@ func Test_PasswordAgePolicyPrepares(t *testing.T) { prepare: preparePasswordAgePolicyQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.password_age_policies.id,`+ - ` projections.password_age_policies.sequence,`+ - ` projections.password_age_policies.creation_date,`+ - ` projections.password_age_policies.change_date,`+ - ` projections.password_age_policies.resource_owner,`+ - ` projections.password_age_policies.expire_warn_days,`+ - ` projections.password_age_policies.max_age_days,`+ - ` projections.password_age_policies.is_default,`+ - ` projections.password_age_policies.state`+ - ` FROM projections.password_age_policies`), + regexp.QuoteMeta(`SELECT projections.password_age_policies2.id,`+ + ` projections.password_age_policies2.sequence,`+ + ` projections.password_age_policies2.creation_date,`+ + ` projections.password_age_policies2.change_date,`+ + ` projections.password_age_policies2.resource_owner,`+ + ` projections.password_age_policies2.expire_warn_days,`+ + ` projections.password_age_policies2.max_age_days,`+ + ` projections.password_age_policies2.is_default,`+ + ` projections.password_age_policies2.state`+ + ` FROM projections.password_age_policies2`), nil, nil, ), @@ -55,16 +55,16 @@ func Test_PasswordAgePolicyPrepares(t *testing.T) { prepare: preparePasswordAgePolicyQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.password_age_policies.id,`+ - ` projections.password_age_policies.sequence,`+ - ` projections.password_age_policies.creation_date,`+ - ` projections.password_age_policies.change_date,`+ - ` projections.password_age_policies.resource_owner,`+ - ` projections.password_age_policies.expire_warn_days,`+ - ` projections.password_age_policies.max_age_days,`+ - ` projections.password_age_policies.is_default,`+ - ` projections.password_age_policies.state`+ - ` FROM projections.password_age_policies`), + regexp.QuoteMeta(`SELECT projections.password_age_policies2.id,`+ + ` projections.password_age_policies2.sequence,`+ + ` projections.password_age_policies2.creation_date,`+ + ` projections.password_age_policies2.change_date,`+ + ` projections.password_age_policies2.resource_owner,`+ + ` projections.password_age_policies2.expire_warn_days,`+ + ` projections.password_age_policies2.max_age_days,`+ + ` projections.password_age_policies2.is_default,`+ + ` projections.password_age_policies2.state`+ + ` FROM projections.password_age_policies2`), []string{ "id", "sequence", @@ -106,16 +106,16 @@ func Test_PasswordAgePolicyPrepares(t *testing.T) { prepare: preparePasswordAgePolicyQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.password_age_policies.id,`+ - ` projections.password_age_policies.sequence,`+ - ` projections.password_age_policies.creation_date,`+ - ` projections.password_age_policies.change_date,`+ - ` projections.password_age_policies.resource_owner,`+ - ` projections.password_age_policies.expire_warn_days,`+ - ` projections.password_age_policies.max_age_days,`+ - ` projections.password_age_policies.is_default,`+ - ` projections.password_age_policies.state`+ - ` FROM projections.password_age_policies`), + regexp.QuoteMeta(`SELECT projections.password_age_policies2.id,`+ + ` projections.password_age_policies2.sequence,`+ + ` projections.password_age_policies2.creation_date,`+ + ` projections.password_age_policies2.change_date,`+ + ` projections.password_age_policies2.resource_owner,`+ + ` projections.password_age_policies2.expire_warn_days,`+ + ` projections.password_age_policies2.max_age_days,`+ + ` projections.password_age_policies2.is_default,`+ + ` projections.password_age_policies2.state`+ + ` FROM projections.password_age_policies2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/password_complexity_policy.go b/internal/query/password_complexity_policy.go index 262f3d7683..1af16092b3 100644 --- a/internal/query/password_complexity_policy.go +++ b/internal/query/password_complexity_policy.go @@ -31,24 +31,21 @@ type PasswordComplexityPolicy struct { IsDefault bool } -func (q *Queries) PasswordComplexityPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string) (*PasswordComplexityPolicy, error) { +func (q *Queries) PasswordComplexityPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string, withOwnerRemoved bool) (*PasswordComplexityPolicy, error) { if shouldTriggerBulk { projection.PasswordComplexityProjection.Trigger(ctx) } - + eq := sq.Eq{PasswordComplexityColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[PasswordComplexityColOwnerRemoved.identifier()] = false + } stmt, scan := preparePasswordComplexityPolicyQuery() query, args, err := stmt.Where( sq.And{ - sq.Eq{ - PasswordComplexityColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + eq, sq.Or{ - sq.Eq{ - PasswordComplexityColID.identifier(): orgID, - }, - sq.Eq{ - PasswordComplexityColID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + sq.Eq{PasswordComplexityColID.identifier(): orgID}, + sq.Eq{PasswordComplexityColID.identifier(): authz.GetInstance(ctx).InstanceID()}, }, }). OrderBy(PasswordComplexityColIsDefault.identifier()). @@ -138,6 +135,10 @@ var ( name: projection.ComplexityPolicyStateCol, table: passwordComplexityTable, } + PasswordComplexityColOwnerRemoved = Column{ + name: projection.ComplexityPolicyOwnerRemovedCol, + table: passwordComplexityTable, + } ) func preparePasswordComplexityPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*PasswordComplexityPolicy, error)) { diff --git a/internal/query/password_complexity_policy_test.go b/internal/query/password_complexity_policy_test.go index 50066dad35..6071d6617b 100644 --- a/internal/query/password_complexity_policy_test.go +++ b/internal/query/password_complexity_policy_test.go @@ -28,19 +28,19 @@ func Test_PasswordComplexityPolicyPrepares(t *testing.T) { prepare: preparePasswordComplexityPolicyQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.password_complexity_policies.id,`+ - ` projections.password_complexity_policies.sequence,`+ - ` projections.password_complexity_policies.creation_date,`+ - ` projections.password_complexity_policies.change_date,`+ - ` projections.password_complexity_policies.resource_owner,`+ - ` projections.password_complexity_policies.min_length,`+ - ` projections.password_complexity_policies.has_lowercase,`+ - ` projections.password_complexity_policies.has_uppercase,`+ - ` projections.password_complexity_policies.has_number,`+ - ` projections.password_complexity_policies.has_symbol,`+ - ` projections.password_complexity_policies.is_default,`+ - ` projections.password_complexity_policies.state`+ - ` FROM projections.password_complexity_policies`), + regexp.QuoteMeta(`SELECT projections.password_complexity_policies2.id,`+ + ` projections.password_complexity_policies2.sequence,`+ + ` projections.password_complexity_policies2.creation_date,`+ + ` projections.password_complexity_policies2.change_date,`+ + ` projections.password_complexity_policies2.resource_owner,`+ + ` projections.password_complexity_policies2.min_length,`+ + ` projections.password_complexity_policies2.has_lowercase,`+ + ` projections.password_complexity_policies2.has_uppercase,`+ + ` projections.password_complexity_policies2.has_number,`+ + ` projections.password_complexity_policies2.has_symbol,`+ + ` projections.password_complexity_policies2.is_default,`+ + ` projections.password_complexity_policies2.state`+ + ` FROM projections.password_complexity_policies2`), nil, nil, ), @@ -58,19 +58,19 @@ func Test_PasswordComplexityPolicyPrepares(t *testing.T) { prepare: preparePasswordComplexityPolicyQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.password_complexity_policies.id,`+ - ` projections.password_complexity_policies.sequence,`+ - ` projections.password_complexity_policies.creation_date,`+ - ` projections.password_complexity_policies.change_date,`+ - ` projections.password_complexity_policies.resource_owner,`+ - ` projections.password_complexity_policies.min_length,`+ - ` projections.password_complexity_policies.has_lowercase,`+ - ` projections.password_complexity_policies.has_uppercase,`+ - ` projections.password_complexity_policies.has_number,`+ - ` projections.password_complexity_policies.has_symbol,`+ - ` projections.password_complexity_policies.is_default,`+ - ` projections.password_complexity_policies.state`+ - ` FROM projections.password_complexity_policies`), + regexp.QuoteMeta(`SELECT projections.password_complexity_policies2.id,`+ + ` projections.password_complexity_policies2.sequence,`+ + ` projections.password_complexity_policies2.creation_date,`+ + ` projections.password_complexity_policies2.change_date,`+ + ` projections.password_complexity_policies2.resource_owner,`+ + ` projections.password_complexity_policies2.min_length,`+ + ` projections.password_complexity_policies2.has_lowercase,`+ + ` projections.password_complexity_policies2.has_uppercase,`+ + ` projections.password_complexity_policies2.has_number,`+ + ` projections.password_complexity_policies2.has_symbol,`+ + ` projections.password_complexity_policies2.is_default,`+ + ` projections.password_complexity_policies2.state`+ + ` FROM projections.password_complexity_policies2`), []string{ "id", "sequence", @@ -121,19 +121,19 @@ func Test_PasswordComplexityPolicyPrepares(t *testing.T) { prepare: preparePasswordComplexityPolicyQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.password_complexity_policies.id,`+ - ` projections.password_complexity_policies.sequence,`+ - ` projections.password_complexity_policies.creation_date,`+ - ` projections.password_complexity_policies.change_date,`+ - ` projections.password_complexity_policies.resource_owner,`+ - ` projections.password_complexity_policies.min_length,`+ - ` projections.password_complexity_policies.has_lowercase,`+ - ` projections.password_complexity_policies.has_uppercase,`+ - ` projections.password_complexity_policies.has_number,`+ - ` projections.password_complexity_policies.has_symbol,`+ - ` projections.password_complexity_policies.is_default,`+ - ` projections.password_complexity_policies.state`+ - ` FROM projections.password_complexity_policies`), + regexp.QuoteMeta(`SELECT projections.password_complexity_policies2.id,`+ + ` projections.password_complexity_policies2.sequence,`+ + ` projections.password_complexity_policies2.creation_date,`+ + ` projections.password_complexity_policies2.change_date,`+ + ` projections.password_complexity_policies2.resource_owner,`+ + ` projections.password_complexity_policies2.min_length,`+ + ` projections.password_complexity_policies2.has_lowercase,`+ + ` projections.password_complexity_policies2.has_uppercase,`+ + ` projections.password_complexity_policies2.has_number,`+ + ` projections.password_complexity_policies2.has_symbol,`+ + ` projections.password_complexity_policies2.is_default,`+ + ` projections.password_complexity_policies2.state`+ + ` FROM projections.password_complexity_policies2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/privacy_policy.go b/internal/query/privacy_policy.go index 0a3565bbf5..2d52f5a7ac 100644 --- a/internal/query/privacy_policy.go +++ b/internal/query/privacy_policy.go @@ -78,30 +78,30 @@ var ( name: projection.PrivacyPolicyStateCol, table: privacyTable, } + PrivacyColOwnerRemoved = Column{ + name: projection.PrivacyPolicyOwnerRemovedCol, + table: privacyTable, + } ) -func (q *Queries) PrivacyPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string) (*PrivacyPolicy, error) { +func (q *Queries) PrivacyPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string, withOwnerRemoved bool) (*PrivacyPolicy, error) { if shouldTriggerBulk { projection.PrivacyPolicyProjection.Trigger(ctx) } - + eq := sq.Eq{PrivacyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[PrivacyColOwnerRemoved.identifier()] = false + } stmt, scan := preparePrivacyPolicyQuery() query, args, err := stmt.Where( sq.And{ - sq.Eq{ - PrivacyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + eq, sq.Or{ - sq.Eq{ - PrivacyColID.identifier(): orgID, - }, - sq.Eq{ - PrivacyColID.identifier(): authz.GetInstance(ctx).InstanceID(), - }, + sq.Eq{PrivacyColID.identifier(): orgID}, + sq.Eq{PrivacyColID.identifier(): authz.GetInstance(ctx).InstanceID()}, }, }). - OrderBy(PrivacyColIsDefault.identifier()). - Limit(1).ToSql() + OrderBy(PrivacyColIsDefault.identifier()).Limit(1).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-UXuPI", "Errors.Query.SQLStatement") } diff --git a/internal/query/privacy_policy_test.go b/internal/query/privacy_policy_test.go index cce6546714..9aa801c854 100644 --- a/internal/query/privacy_policy_test.go +++ b/internal/query/privacy_policy_test.go @@ -28,17 +28,17 @@ func Test_PrivacyPolicyPrepares(t *testing.T) { prepare: preparePrivacyPolicyQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.privacy_policies.id,`+ - ` projections.privacy_policies.sequence,`+ - ` projections.privacy_policies.creation_date,`+ - ` projections.privacy_policies.change_date,`+ - ` projections.privacy_policies.resource_owner,`+ - ` projections.privacy_policies.privacy_link,`+ - ` projections.privacy_policies.tos_link,`+ - ` projections.privacy_policies.help_link,`+ - ` projections.privacy_policies.is_default,`+ - ` projections.privacy_policies.state`+ - ` FROM projections.privacy_policies`), + regexp.QuoteMeta(`SELECT projections.privacy_policies2.id,`+ + ` projections.privacy_policies2.sequence,`+ + ` projections.privacy_policies2.creation_date,`+ + ` projections.privacy_policies2.change_date,`+ + ` projections.privacy_policies2.resource_owner,`+ + ` projections.privacy_policies2.privacy_link,`+ + ` projections.privacy_policies2.tos_link,`+ + ` projections.privacy_policies2.help_link,`+ + ` projections.privacy_policies2.is_default,`+ + ` projections.privacy_policies2.state`+ + ` FROM projections.privacy_policies2`), nil, nil, ), @@ -56,17 +56,17 @@ func Test_PrivacyPolicyPrepares(t *testing.T) { prepare: preparePrivacyPolicyQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.privacy_policies.id,`+ - ` projections.privacy_policies.sequence,`+ - ` projections.privacy_policies.creation_date,`+ - ` projections.privacy_policies.change_date,`+ - ` projections.privacy_policies.resource_owner,`+ - ` projections.privacy_policies.privacy_link,`+ - ` projections.privacy_policies.tos_link,`+ - ` projections.privacy_policies.help_link,`+ - ` projections.privacy_policies.is_default,`+ - ` projections.privacy_policies.state`+ - ` FROM projections.privacy_policies`), + regexp.QuoteMeta(`SELECT projections.privacy_policies2.id,`+ + ` projections.privacy_policies2.sequence,`+ + ` projections.privacy_policies2.creation_date,`+ + ` projections.privacy_policies2.change_date,`+ + ` projections.privacy_policies2.resource_owner,`+ + ` projections.privacy_policies2.privacy_link,`+ + ` projections.privacy_policies2.tos_link,`+ + ` projections.privacy_policies2.help_link,`+ + ` projections.privacy_policies2.is_default,`+ + ` projections.privacy_policies2.state`+ + ` FROM projections.privacy_policies2`), []string{ "id", "sequence", @@ -111,17 +111,17 @@ func Test_PrivacyPolicyPrepares(t *testing.T) { prepare: preparePrivacyPolicyQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.privacy_policies.id,`+ - ` projections.privacy_policies.sequence,`+ - ` projections.privacy_policies.creation_date,`+ - ` projections.privacy_policies.change_date,`+ - ` projections.privacy_policies.resource_owner,`+ - ` projections.privacy_policies.privacy_link,`+ - ` projections.privacy_policies.tos_link,`+ - ` projections.privacy_policies.help_link,`+ - ` projections.privacy_policies.is_default,`+ - ` projections.privacy_policies.state`+ - ` FROM projections.privacy_policies`), + regexp.QuoteMeta(`SELECT projections.privacy_policies2.id,`+ + ` projections.privacy_policies2.sequence,`+ + ` projections.privacy_policies2.creation_date,`+ + ` projections.privacy_policies2.change_date,`+ + ` projections.privacy_policies2.resource_owner,`+ + ` projections.privacy_policies2.privacy_link,`+ + ` projections.privacy_policies2.tos_link,`+ + ` projections.privacy_policies2.help_link,`+ + ` projections.privacy_policies2.is_default,`+ + ` projections.privacy_policies2.state`+ + ` FROM projections.privacy_policies2`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/project.go b/internal/query/project.go index 07c7fe7fba..56e9bf0d64 100644 --- a/internal/query/project.go +++ b/internal/query/project.go @@ -68,6 +68,10 @@ var ( name: projection.ProjectColumnState, table: projectsTable, } + ProjectColumnOwnerRemoved = Column{ + name: projection.ProjectColumnOwnerRemoved, + table: projectsTable, + } ) type Projects struct { @@ -95,16 +99,20 @@ type ProjectSearchQueries struct { Queries []SearchQuery } -func (q *Queries) ProjectByID(ctx context.Context, shouldTriggerBulk bool, id string) (*Project, error) { +func (q *Queries) ProjectByID(ctx context.Context, shouldTriggerBulk bool, id string, withOwnerRemoved bool) (*Project, error) { if shouldTriggerBulk { projection.ProjectProjection.Trigger(ctx) } stmt, scan := prepareProjectQuery() - query, args, err := stmt.Where(sq.Eq{ + eq := sq.Eq{ ProjectColumnID.identifier(): id, ProjectColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + } + if !withOwnerRemoved { + eq[ProjectColumnOwnerRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-2m00Q", "Errors.Query.SQLStatment") } @@ -113,12 +121,13 @@ func (q *Queries) ProjectByID(ctx context.Context, shouldTriggerBulk bool, id st return scan(row) } -func (q *Queries) SearchProjects(ctx context.Context, queries *ProjectSearchQueries) (projects *Projects, err error) { +func (q *Queries) SearchProjects(ctx context.Context, queries *ProjectSearchQueries, withOwnerRemoved bool) (projects *Projects, err error) { query, scan := prepareProjectsQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - ProjectColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{ProjectColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[ProjectColumnOwnerRemoved.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-fn9ew", "Errors.Query.InvalidRequest") } diff --git a/internal/query/project_grant.go b/internal/query/project_grant.go index 2ca83f6a69..04f3558fa9 100644 --- a/internal/query/project_grant.go +++ b/internal/query/project_grant.go @@ -74,6 +74,14 @@ var ( name: projection.OrgColumnName, table: orgsTable.setAlias(ProjectGrantResourceOwnerTableAlias), } + ProjectGrantColumnOwnerRemoved = Column{ + name: projection.ProjectGrantColumnOwnerRemoved, + table: projectGrantsTable, + } + ProjectGrantColumnGrantGrantedOrgRemoved = Column{ + name: projection.ProjectGrantColumnGrantedOrgRemoved, + table: projectGrantsTable, + } ) type ProjectGrants struct { @@ -102,16 +110,21 @@ type ProjectGrantSearchQueries struct { Queries []SearchQuery } -func (q *Queries) ProjectGrantByID(ctx context.Context, shouldTriggerBulk bool, id string) (*ProjectGrant, error) { +func (q *Queries) ProjectGrantByID(ctx context.Context, shouldTriggerBulk bool, id string, withOwnerRemoved bool) (*ProjectGrant, error) { if shouldTriggerBulk { projection.ProjectGrantProjection.Trigger(ctx) } stmt, scan := prepareProjectGrantQuery() - query, args, err := stmt.Where(sq.Eq{ + eq := sq.Eq{ ProjectGrantColumnGrantID.identifier(): id, ProjectGrantColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + } + if !withOwnerRemoved { + eq[ProjectGrantColumnOwnerRemoved.identifier()] = false + eq[ProjectGrantColumnGrantGrantedOrgRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Nf93d", "Errors.Query.SQLStatment") } @@ -120,13 +133,18 @@ func (q *Queries) ProjectGrantByID(ctx context.Context, shouldTriggerBulk bool, return scan(row) } -func (q *Queries) ProjectGrantByIDAndGrantedOrg(ctx context.Context, id, grantedOrg string) (*ProjectGrant, error) { +func (q *Queries) ProjectGrantByIDAndGrantedOrg(ctx context.Context, id, grantedOrg string, withOwnerRemoved bool) (*ProjectGrant, error) { stmt, scan := prepareProjectGrantQuery() - query, args, err := stmt.Where(sq.Eq{ + eq := sq.Eq{ ProjectGrantColumnGrantID.identifier(): id, ProjectGrantColumnGrantedOrgID.identifier(): grantedOrg, ProjectGrantColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + } + if !withOwnerRemoved { + eq[ProjectGrantColumnOwnerRemoved.identifier()] = false + eq[ProjectGrantColumnGrantGrantedOrgRemoved.identifier()] = false + } + query, args, err := stmt.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-MO9fs", "Errors.Query.SQLStatment") } @@ -135,12 +153,16 @@ func (q *Queries) ProjectGrantByIDAndGrantedOrg(ctx context.Context, id, granted return scan(row) } -func (q *Queries) SearchProjectGrants(ctx context.Context, queries *ProjectGrantSearchQueries) (projects *ProjectGrants, err error) { +func (q *Queries) SearchProjectGrants(ctx context.Context, queries *ProjectGrantSearchQueries, withOwnerRemoved bool) (projects *ProjectGrants, err error) { query, scan := prepareProjectGrantsQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - ProjectGrantColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{ + ProjectGrantColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[ProjectGrantColumnOwnerRemoved.identifier()] = false + eq[ProjectGrantColumnGrantGrantedOrgRemoved.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-N9fsg", "Errors.Query.InvalidRequest") } @@ -157,7 +179,7 @@ func (q *Queries) SearchProjectGrants(ctx context.Context, queries *ProjectGrant return projects, err } -func (q *Queries) SearchProjectGrantsByProjectIDAndRoleKey(ctx context.Context, projectID, roleKey string) (projects *ProjectGrants, err error) { +func (q *Queries) SearchProjectGrantsByProjectIDAndRoleKey(ctx context.Context, projectID, roleKey string, withOwnerRemoved bool) (projects *ProjectGrants, err error) { searchQuery := &ProjectGrantSearchQueries{ SearchRequest: SearchRequest{}, Queries: make([]SearchQuery, 2), @@ -170,7 +192,7 @@ func (q *Queries) SearchProjectGrantsByProjectIDAndRoleKey(ctx context.Context, if err != nil { return nil, err } - return q.SearchProjectGrants(ctx, searchQuery) + return q.SearchProjectGrants(ctx, searchQuery, withOwnerRemoved) } func NewProjectGrantProjectIDSearchQuery(value string) (SearchQuery, error) { diff --git a/internal/query/project_grant_member.go b/internal/query/project_grant_member.go index cd0a8bd957..6a43e298da 100644 --- a/internal/query/project_grant_member.go +++ b/internal/query/project_grant_member.go @@ -54,6 +54,18 @@ var ( name: projection.ProjectGrantMemberGrantIDCol, table: projectGrantMemberTable, } + ProjectGrantMemberOwnerRemoved = Column{ + name: projection.MemberOwnerRemoved, + table: projectGrantMemberTable, + } + ProjectGrantMemberUserOwnerRemoved = Column{ + name: projection.MemberUserOwnerRemoved, + table: projectGrantMemberTable, + } + ProjectGrantMemberGrantedOrgRemoved = Column{ + name: projection.ProjectGrantMemberGrantedOrgRemoved, + table: projectGrantMemberTable, + } ) type ProjectGrantMembersQuery struct { @@ -76,12 +88,20 @@ func (q *ProjectGrantMembersQuery) toQuery(query sq.SelectBuilder) sq.SelectBuil }) } -func (q *Queries) ProjectGrantMembers(ctx context.Context, queries *ProjectGrantMembersQuery) (*Members, error) { +func addProjectGrantMemberWithoutOwnerRemoved(eq map[string]interface{}) { + eq[ProjectGrantMemberOwnerRemoved.identifier()] = false + eq[ProjectGrantMemberUserOwnerRemoved.identifier()] = false + eq[ProjectGrantMemberGrantedOrgRemoved.identifier()] = false +} + +func (q *Queries) ProjectGrantMembers(ctx context.Context, queries *ProjectGrantMembersQuery, withOwnerRemoved bool) (*Members, error) { query, scan := prepareProjectGrantMembersQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - ProjectGrantMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{ProjectGrantMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + addProjectGrantMemberWithoutOwnerRemoved(eq) + addLoginNameWithoutOwnerRemoved(eq) + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-USNwM", "Errors.Query.InvalidRequest") } diff --git a/internal/query/project_grant_member_test.go b/internal/query/project_grant_member_test.go index 5bd2b1cfc9..c9ebdcce39 100644 --- a/internal/query/project_grant_member_test.go +++ b/internal/query/project_grant_member_test.go @@ -19,28 +19,28 @@ var ( ", members.resource_owner" + ", members.user_id" + ", members.roles" + - ", projections.login_names.login_name" + - ", projections.users5_humans.email" + - ", projections.users5_humans.first_name" + - ", projections.users5_humans.last_name" + - ", projections.users5_humans.display_name" + - ", projections.users5_machines.name" + - ", projections.users5_humans.avatar_key" + + ", projections.login_names2.login_name" + + ", projections.users6_humans.email" + + ", projections.users6_humans.first_name" + + ", projections.users6_humans.last_name" + + ", projections.users6_humans.display_name" + + ", projections.users6_machines.name" + + ", projections.users6_humans.avatar_key" + ", COUNT(*) OVER () " + - "FROM projections.project_grant_members2 AS members " + - "LEFT JOIN projections.users5_humans " + - "ON members.user_id = projections.users5_humans.user_id " + - "AND members.instance_id = projections.users5_humans.instance_id " + - "LEFT JOIN projections.users5_machines " + - "ON members.user_id = projections.users5_machines.user_id " + - "AND members.instance_id = projections.users5_machines.instance_id " + - "LEFT JOIN projections.login_names " + - "ON members.user_id = projections.login_names.user_id " + - "AND members.instance_id = projections.login_names.instance_id " + - "LEFT JOIN projections.project_grants2 " + - "ON members.grant_id = projections.project_grants2.grant_id " + - "AND members.instance_id = projections.project_grants2.instance_id " + - "WHERE projections.login_names.is_primary = $1") + "FROM projections.project_grant_members3 AS members " + + "LEFT JOIN projections.users6_humans " + + "ON members.user_id = projections.users6_humans.user_id " + + "AND members.instance_id = projections.users6_humans.instance_id " + + "LEFT JOIN projections.users6_machines " + + "ON members.user_id = projections.users6_machines.user_id " + + "AND members.instance_id = projections.users6_machines.instance_id " + + "LEFT JOIN projections.login_names2 " + + "ON members.user_id = projections.login_names2.user_id " + + "AND members.instance_id = projections.login_names2.instance_id " + + "LEFT JOIN projections.project_grants3 " + + "ON members.grant_id = projections.project_grants3.grant_id " + + "AND members.instance_id = projections.project_grants3.instance_id " + + "WHERE projections.login_names2.is_primary = $1") projectGrantMembersColumns = []string{ "creation_date", "change_date", diff --git a/internal/query/project_grant_test.go b/internal/query/project_grant_test.go index ca7ea44a10..89de79f65b 100644 --- a/internal/query/project_grant_test.go +++ b/internal/query/project_grant_test.go @@ -14,23 +14,23 @@ import ( ) var ( - projectGrantsQuery = `SELECT projections.project_grants2.project_id,` + - ` projections.project_grants2.grant_id,` + - ` projections.project_grants2.creation_date,` + - ` projections.project_grants2.change_date,` + - ` projections.project_grants2.resource_owner,` + - ` projections.project_grants2.state,` + - ` projections.project_grants2.sequence,` + - ` projections.projects2.name,` + - ` projections.project_grants2.granted_org_id,` + + projectGrantsQuery = `SELECT projections.project_grants3.project_id,` + + ` projections.project_grants3.grant_id,` + + ` projections.project_grants3.creation_date,` + + ` projections.project_grants3.change_date,` + + ` projections.project_grants3.resource_owner,` + + ` projections.project_grants3.state,` + + ` projections.project_grants3.sequence,` + + ` projections.projects3.name,` + + ` projections.project_grants3.granted_org_id,` + ` o.name,` + - ` projections.project_grants2.granted_role_keys,` + + ` projections.project_grants3.granted_role_keys,` + ` r.name,` + ` COUNT(*) OVER () ` + - ` FROM projections.project_grants2 ` + - ` LEFT JOIN projections.projects2 ON projections.project_grants2.project_id = projections.projects2.id AND projections.project_grants2.instance_id = projections.projects2.instance_id ` + - ` LEFT JOIN projections.orgs AS r ON projections.project_grants2.resource_owner = r.id AND projections.project_grants2.instance_id = r.instance_id` + - ` LEFT JOIN projections.orgs AS o ON projections.project_grants2.granted_org_id = o.id AND projections.project_grants2.instance_id = o.instance_id` + ` FROM projections.project_grants3 ` + + ` LEFT JOIN projections.projects3 ON projections.project_grants3.project_id = projections.projects3.id AND projections.project_grants3.instance_id = projections.projects3.instance_id ` + + ` LEFT JOIN projections.orgs AS r ON projections.project_grants3.resource_owner = r.id AND projections.project_grants3.instance_id = r.instance_id` + + ` LEFT JOIN projections.orgs AS o ON projections.project_grants3.granted_org_id = o.id AND projections.project_grants3.instance_id = o.instance_id` projectGrantsCols = []string{ "project_id", "grant_id", @@ -46,22 +46,22 @@ var ( "name", "count", } - projectGrantQuery = `SELECT projections.project_grants2.project_id,` + - ` projections.project_grants2.grant_id,` + - ` projections.project_grants2.creation_date,` + - ` projections.project_grants2.change_date,` + - ` projections.project_grants2.resource_owner,` + - ` projections.project_grants2.state,` + - ` projections.project_grants2.sequence,` + - ` projections.projects2.name,` + - ` projections.project_grants2.granted_org_id,` + + projectGrantQuery = `SELECT projections.project_grants3.project_id,` + + ` projections.project_grants3.grant_id,` + + ` projections.project_grants3.creation_date,` + + ` projections.project_grants3.change_date,` + + ` projections.project_grants3.resource_owner,` + + ` projections.project_grants3.state,` + + ` projections.project_grants3.sequence,` + + ` projections.projects3.name,` + + ` projections.project_grants3.granted_org_id,` + ` o.name,` + - ` projections.project_grants2.granted_role_keys,` + + ` projections.project_grants3.granted_role_keys,` + ` r.name` + - ` FROM projections.project_grants2 ` + - ` LEFT JOIN projections.projects2 ON projections.project_grants2.project_id = projections.projects2.id AND projections.project_grants2.instance_id = projections.projects2.instance_id ` + - ` LEFT JOIN projections.orgs AS r ON projections.project_grants2.resource_owner = r.id AND projections.project_grants2.instance_id = r.instance_id` + - ` LEFT JOIN projections.orgs AS o ON projections.project_grants2.granted_org_id = o.id AND projections.project_grants2.instance_id = o.instance_id` + ` FROM projections.project_grants3 ` + + ` LEFT JOIN projections.projects3 ON projections.project_grants3.project_id = projections.projects3.id AND projections.project_grants3.instance_id = projections.projects3.instance_id ` + + ` LEFT JOIN projections.orgs AS r ON projections.project_grants3.resource_owner = r.id AND projections.project_grants3.instance_id = r.instance_id` + + ` LEFT JOIN projections.orgs AS o ON projections.project_grants3.granted_org_id = o.id AND projections.project_grants3.instance_id = o.instance_id` projectGrantCols = []string{ "project_id", "grant_id", diff --git a/internal/query/project_member.go b/internal/query/project_member.go index 19e785c0af..22ca200ade 100644 --- a/internal/query/project_member.go +++ b/internal/query/project_member.go @@ -50,6 +50,14 @@ var ( name: projection.ProjectMemberProjectIDCol, table: projectMemberTable, } + ProjectMemberOwnerRemoved = Column{ + name: projection.MemberOwnerRemoved, + table: orgMemberTable, + } + ProjectMemberOwnerRemovedUser = Column{ + name: projection.MemberUserOwnerRemoved, + table: orgMemberTable, + } ) type ProjectMembersQuery struct { @@ -63,12 +71,19 @@ func (q *ProjectMembersQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { Where(sq.Eq{ProjectMemberProjectID.identifier(): q.ProjectID}) } -func (q *Queries) ProjectMembers(ctx context.Context, queries *ProjectMembersQuery) (*Members, error) { +func addProjectMemberWithoutOwnerRemoved(eq map[string]interface{}) { + eq[ProjectMemberOwnerRemoved.identifier()] = false + eq[ProjectMemberOwnerRemovedUser.identifier()] = false +} + +func (q *Queries) ProjectMembers(ctx context.Context, queries *ProjectMembersQuery, withOwnerRemoved bool) (*Members, error) { query, scan := prepareProjectMembersQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - ProjectMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{ProjectMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + addProjectMemberWithoutOwnerRemoved(eq) + addLoginNameWithoutOwnerRemoved(eq) + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-T8CuT", "Errors.Query.InvalidRequest") } diff --git a/internal/query/project_member_test.go b/internal/query/project_member_test.go index 55d70a6c73..ea41dc5f9e 100644 --- a/internal/query/project_member_test.go +++ b/internal/query/project_member_test.go @@ -19,25 +19,25 @@ var ( ", members.resource_owner" + ", members.user_id" + ", members.roles" + - ", projections.login_names.login_name" + - ", projections.users5_humans.email" + - ", projections.users5_humans.first_name" + - ", projections.users5_humans.last_name" + - ", projections.users5_humans.display_name" + - ", projections.users5_machines.name" + - ", projections.users5_humans.avatar_key" + + ", projections.login_names2.login_name" + + ", projections.users6_humans.email" + + ", projections.users6_humans.first_name" + + ", projections.users6_humans.last_name" + + ", projections.users6_humans.display_name" + + ", projections.users6_machines.name" + + ", projections.users6_humans.avatar_key" + ", COUNT(*) OVER () " + - "FROM projections.project_members2 AS members " + - "LEFT JOIN projections.users5_humans " + - "ON members.user_id = projections.users5_humans.user_id " + - "AND members.instance_id = projections.users5_humans.instance_id " + - "LEFT JOIN projections.users5_machines " + - "ON members.user_id = projections.users5_machines.user_id " + - "AND members.instance_id = projections.users5_machines.instance_id " + - "LEFT JOIN projections.login_names " + - "ON members.user_id = projections.login_names.user_id " + - "AND members.instance_id = projections.login_names.instance_id " + - "WHERE projections.login_names.is_primary = $1") + "FROM projections.project_members3 AS members " + + "LEFT JOIN projections.users6_humans " + + "ON members.user_id = projections.users6_humans.user_id " + + "AND members.instance_id = projections.users6_humans.instance_id " + + "LEFT JOIN projections.users6_machines " + + "ON members.user_id = projections.users6_machines.user_id " + + "AND members.instance_id = projections.users6_machines.instance_id " + + "LEFT JOIN projections.login_names2 " + + "ON members.user_id = projections.login_names2.user_id " + + "AND members.instance_id = projections.login_names2.instance_id " + + "WHERE projections.login_names2.is_primary = $1") projectMembersColumns = []string{ "creation_date", "change_date", diff --git a/internal/query/project_role.go b/internal/query/project_role.go index 7f4c87ff53..a40fabd10c 100644 --- a/internal/query/project_role.go +++ b/internal/query/project_role.go @@ -53,6 +53,10 @@ var ( name: projection.ProjectRoleColumnGroupName, table: projectRolesTable, } + ProjectRoleColumnOwnerRemoved = Column{ + name: projection.ProjectRoleColumnOwnerRemoved, + table: projectRolesTable, + } ) type ProjectRoles struct { @@ -77,16 +81,18 @@ type ProjectRoleSearchQueries struct { Queries []SearchQuery } -func (q *Queries) SearchProjectRoles(ctx context.Context, shouldTriggerBulk bool, queries *ProjectRoleSearchQueries) (projects *ProjectRoles, err error) { +func (q *Queries) SearchProjectRoles(ctx context.Context, shouldTriggerBulk bool, queries *ProjectRoleSearchQueries, withOwnerRemoved bool) (projects *ProjectRoles, err error) { if shouldTriggerBulk { projection.ProjectRoleProjection.Trigger(ctx) } + eq := sq.Eq{ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[ProjectRoleColumnOwnerRemoved.identifier()] = false + } + query, scan := prepareProjectRolesQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-3N9ff", "Errors.Query.InvalidRequest") } @@ -103,8 +109,8 @@ func (q *Queries) SearchProjectRoles(ctx context.Context, shouldTriggerBulk bool return projects, err } -func (q *Queries) SearchGrantedProjectRoles(ctx context.Context, grantID, grantedOrg string, queries *ProjectRoleSearchQueries) (projects *ProjectRoles, err error) { - grant, err := q.ProjectGrantByIDAndGrantedOrg(ctx, grantID, grantedOrg) +func (q *Queries) SearchGrantedProjectRoles(ctx context.Context, grantID, grantedOrg string, queries *ProjectRoleSearchQueries, withOwnerRemoved bool) (projects *ProjectRoles, err error) { + grant, err := q.ProjectGrantByIDAndGrantedOrg(ctx, grantID, grantedOrg, withOwnerRemoved) if err != nil { return nil, err } @@ -112,11 +118,14 @@ func (q *Queries) SearchGrantedProjectRoles(ctx context.Context, grantID, grante if err != nil { return nil, err } + + eq := sq.Eq{ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[ProjectRoleColumnOwnerRemoved.identifier()] = false + } + query, scan := prepareProjectRolesQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - ProjectRoleColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-3N9ff", "Errors.Query.InvalidRequest") } diff --git a/internal/query/project_role_test.go b/internal/query/project_role_test.go index 7059e6027f..c76a8bd591 100644 --- a/internal/query/project_role_test.go +++ b/internal/query/project_role_test.go @@ -25,16 +25,16 @@ func Test_ProjectRolePrepares(t *testing.T) { prepare: prepareProjectRolesQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.project_roles.project_id,`+ - ` projections.project_roles.creation_date,`+ - ` projections.project_roles.change_date,`+ - ` projections.project_roles.resource_owner,`+ - ` projections.project_roles.sequence,`+ - ` projections.project_roles.role_key,`+ - ` projections.project_roles.display_name,`+ - ` projections.project_roles.group_name,`+ + regexp.QuoteMeta(`SELECT projections.project_roles3.project_id,`+ + ` projections.project_roles3.creation_date,`+ + ` projections.project_roles3.change_date,`+ + ` projections.project_roles3.resource_owner,`+ + ` projections.project_roles3.sequence,`+ + ` projections.project_roles3.role_key,`+ + ` projections.project_roles3.display_name,`+ + ` projections.project_roles3.group_name,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.project_roles`), + ` FROM projections.project_roles3`), nil, nil, ), @@ -46,16 +46,16 @@ func Test_ProjectRolePrepares(t *testing.T) { prepare: prepareProjectRolesQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.project_roles.project_id,`+ - ` projections.project_roles.creation_date,`+ - ` projections.project_roles.change_date,`+ - ` projections.project_roles.resource_owner,`+ - ` projections.project_roles.sequence,`+ - ` projections.project_roles.role_key,`+ - ` projections.project_roles.display_name,`+ - ` projections.project_roles.group_name,`+ + regexp.QuoteMeta(`SELECT projections.project_roles3.project_id,`+ + ` projections.project_roles3.creation_date,`+ + ` projections.project_roles3.change_date,`+ + ` projections.project_roles3.resource_owner,`+ + ` projections.project_roles3.sequence,`+ + ` projections.project_roles3.role_key,`+ + ` projections.project_roles3.display_name,`+ + ` projections.project_roles3.group_name,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.project_roles`), + ` FROM projections.project_roles3`), []string{ "project_id", "creation_date", @@ -104,16 +104,16 @@ func Test_ProjectRolePrepares(t *testing.T) { prepare: prepareProjectRolesQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.project_roles.project_id,`+ - ` projections.project_roles.creation_date,`+ - ` projections.project_roles.change_date,`+ - ` projections.project_roles.resource_owner,`+ - ` projections.project_roles.sequence,`+ - ` projections.project_roles.role_key,`+ - ` projections.project_roles.display_name,`+ - ` projections.project_roles.group_name,`+ + regexp.QuoteMeta(`SELECT projections.project_roles3.project_id,`+ + ` projections.project_roles3.creation_date,`+ + ` projections.project_roles3.change_date,`+ + ` projections.project_roles3.resource_owner,`+ + ` projections.project_roles3.sequence,`+ + ` projections.project_roles3.role_key,`+ + ` projections.project_roles3.display_name,`+ + ` projections.project_roles3.group_name,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.project_roles`), + ` FROM projections.project_roles3`), []string{ "project_id", "creation_date", @@ -182,16 +182,16 @@ func Test_ProjectRolePrepares(t *testing.T) { prepare: prepareProjectRolesQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.project_roles.project_id,`+ - ` projections.project_roles.creation_date,`+ - ` projections.project_roles.change_date,`+ - ` projections.project_roles.resource_owner,`+ - ` projections.project_roles.sequence,`+ - ` projections.project_roles.role_key,`+ - ` projections.project_roles.display_name,`+ - ` projections.project_roles.group_name,`+ + regexp.QuoteMeta(`SELECT projections.project_roles3.project_id,`+ + ` projections.project_roles3.creation_date,`+ + ` projections.project_roles3.change_date,`+ + ` projections.project_roles3.resource_owner,`+ + ` projections.project_roles3.sequence,`+ + ` projections.project_roles3.role_key,`+ + ` projections.project_roles3.display_name,`+ + ` projections.project_roles3.group_name,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.project_roles`), + ` FROM projections.project_roles3`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/project_test.go b/internal/query/project_test.go index 3a55a29ad9..1e9884fdcc 100644 --- a/internal/query/project_test.go +++ b/internal/query/project_test.go @@ -44,19 +44,19 @@ func Test_ProjectPrepares(t *testing.T) { prepare: prepareProjectsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.projects2.id,`+ - ` projections.projects2.creation_date,`+ - ` projections.projects2.change_date,`+ - ` projections.projects2.resource_owner,`+ - ` projections.projects2.state,`+ - ` projections.projects2.sequence,`+ - ` projections.projects2.name,`+ - ` projections.projects2.project_role_assertion,`+ - ` projections.projects2.project_role_check,`+ - ` projections.projects2.has_project_check,`+ - ` projections.projects2.private_labeling_setting,`+ + regexp.QuoteMeta(`SELECT projections.projects3.id,`+ + ` projections.projects3.creation_date,`+ + ` projections.projects3.change_date,`+ + ` projections.projects3.resource_owner,`+ + ` projections.projects3.state,`+ + ` projections.projects3.sequence,`+ + ` projections.projects3.name,`+ + ` projections.projects3.project_role_assertion,`+ + ` projections.projects3.project_role_check,`+ + ` projections.projects3.has_project_check,`+ + ` projections.projects3.private_labeling_setting,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.projects2`), + ` FROM projections.projects3`), nil, nil, ), @@ -68,19 +68,19 @@ func Test_ProjectPrepares(t *testing.T) { prepare: prepareProjectsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.projects2.id,`+ - ` projections.projects2.creation_date,`+ - ` projections.projects2.change_date,`+ - ` projections.projects2.resource_owner,`+ - ` projections.projects2.state,`+ - ` projections.projects2.sequence,`+ - ` projections.projects2.name,`+ - ` projections.projects2.project_role_assertion,`+ - ` projections.projects2.project_role_check,`+ - ` projections.projects2.has_project_check,`+ - ` projections.projects2.private_labeling_setting,`+ + regexp.QuoteMeta(`SELECT projections.projects3.id,`+ + ` projections.projects3.creation_date,`+ + ` projections.projects3.change_date,`+ + ` projections.projects3.resource_owner,`+ + ` projections.projects3.state,`+ + ` projections.projects3.sequence,`+ + ` projections.projects3.name,`+ + ` projections.projects3.project_role_assertion,`+ + ` projections.projects3.project_role_check,`+ + ` projections.projects3.has_project_check,`+ + ` projections.projects3.private_labeling_setting,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.projects2`), + ` FROM projections.projects3`), []string{ "id", "creation_date", @@ -138,19 +138,19 @@ func Test_ProjectPrepares(t *testing.T) { prepare: prepareProjectsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.projects2.id,`+ - ` projections.projects2.creation_date,`+ - ` projections.projects2.change_date,`+ - ` projections.projects2.resource_owner,`+ - ` projections.projects2.state,`+ - ` projections.projects2.sequence,`+ - ` projections.projects2.name,`+ - ` projections.projects2.project_role_assertion,`+ - ` projections.projects2.project_role_check,`+ - ` projections.projects2.has_project_check,`+ - ` projections.projects2.private_labeling_setting,`+ + regexp.QuoteMeta(`SELECT projections.projects3.id,`+ + ` projections.projects3.creation_date,`+ + ` projections.projects3.change_date,`+ + ` projections.projects3.resource_owner,`+ + ` projections.projects3.state,`+ + ` projections.projects3.sequence,`+ + ` projections.projects3.name,`+ + ` projections.projects3.project_role_assertion,`+ + ` projections.projects3.project_role_check,`+ + ` projections.projects3.has_project_check,`+ + ` projections.projects3.private_labeling_setting,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.projects2`), + ` FROM projections.projects3`), []string{ "id", "creation_date", @@ -234,19 +234,19 @@ func Test_ProjectPrepares(t *testing.T) { prepare: prepareProjectsQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.projects2.id,`+ - ` projections.projects2.creation_date,`+ - ` projections.projects2.change_date,`+ - ` projections.projects2.resource_owner,`+ - ` projections.projects2.state,`+ - ` projections.projects2.sequence,`+ - ` projections.projects2.name,`+ - ` projections.projects2.project_role_assertion,`+ - ` projections.projects2.project_role_check,`+ - ` projections.projects2.has_project_check,`+ - ` projections.projects2.private_labeling_setting,`+ + regexp.QuoteMeta(`SELECT projections.projects3.id,`+ + ` projections.projects3.creation_date,`+ + ` projections.projects3.change_date,`+ + ` projections.projects3.resource_owner,`+ + ` projections.projects3.state,`+ + ` projections.projects3.sequence,`+ + ` projections.projects3.name,`+ + ` projections.projects3.project_role_assertion,`+ + ` projections.projects3.project_role_check,`+ + ` projections.projects3.has_project_check,`+ + ` projections.projects3.private_labeling_setting,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.projects2`), + ` FROM projections.projects3`), sql.ErrConnDone, ), err: func(err error) (error, bool) { @@ -263,18 +263,18 @@ func Test_ProjectPrepares(t *testing.T) { prepare: prepareProjectQuery, want: want{ sqlExpectations: mockQueries( - `SELECT projections.projects2.id,`+ - ` projections.projects2.creation_date,`+ - ` projections.projects2.change_date,`+ - ` projections.projects2.resource_owner,`+ - ` projections.projects2.state,`+ - ` projections.projects2.sequence,`+ - ` projections.projects2.name,`+ - ` projections.projects2.project_role_assertion,`+ - ` projections.projects2.project_role_check,`+ - ` projections.projects2.has_project_check,`+ - ` projections.projects2.private_labeling_setting`+ - ` FROM projections.projects2`, + `SELECT projections.projects3.id,`+ + ` projections.projects3.creation_date,`+ + ` projections.projects3.change_date,`+ + ` projections.projects3.resource_owner,`+ + ` projections.projects3.state,`+ + ` projections.projects3.sequence,`+ + ` projections.projects3.name,`+ + ` projections.projects3.project_role_assertion,`+ + ` projections.projects3.project_role_check,`+ + ` projections.projects3.has_project_check,`+ + ` projections.projects3.private_labeling_setting`+ + ` FROM projections.projects3`, nil, nil, ), @@ -292,18 +292,18 @@ func Test_ProjectPrepares(t *testing.T) { prepare: prepareProjectQuery, want: want{ sqlExpectations: mockQuery( - regexp.QuoteMeta(`SELECT projections.projects2.id,`+ - ` projections.projects2.creation_date,`+ - ` projections.projects2.change_date,`+ - ` projections.projects2.resource_owner,`+ - ` projections.projects2.state,`+ - ` projections.projects2.sequence,`+ - ` projections.projects2.name,`+ - ` projections.projects2.project_role_assertion,`+ - ` projections.projects2.project_role_check,`+ - ` projections.projects2.has_project_check,`+ - ` projections.projects2.private_labeling_setting`+ - ` FROM projections.projects2`), + regexp.QuoteMeta(`SELECT projections.projects3.id,`+ + ` projections.projects3.creation_date,`+ + ` projections.projects3.change_date,`+ + ` projections.projects3.resource_owner,`+ + ` projections.projects3.state,`+ + ` projections.projects3.sequence,`+ + ` projections.projects3.name,`+ + ` projections.projects3.project_role_assertion,`+ + ` projections.projects3.project_role_check,`+ + ` projections.projects3.has_project_check,`+ + ` projections.projects3.private_labeling_setting`+ + ` FROM projections.projects3`), []string{ "id", "creation_date", @@ -351,18 +351,18 @@ func Test_ProjectPrepares(t *testing.T) { prepare: prepareProjectQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.projects2.id,`+ - ` projections.projects2.creation_date,`+ - ` projections.projects2.change_date,`+ - ` projections.projects2.resource_owner,`+ - ` projections.projects2.state,`+ - ` projections.projects2.sequence,`+ - ` projections.projects2.name,`+ - ` projections.projects2.project_role_assertion,`+ - ` projections.projects2.project_role_check,`+ - ` projections.projects2.has_project_check,`+ - ` projections.projects2.private_labeling_setting`+ - ` FROM projections.projects2`), + regexp.QuoteMeta(`SELECT projections.projects3.id,`+ + ` projections.projects3.creation_date,`+ + ` projections.projects3.change_date,`+ + ` projections.projects3.resource_owner,`+ + ` projections.projects3.state,`+ + ` projections.projects3.sequence,`+ + ` projections.projects3.name,`+ + ` projections.projects3.project_role_assertion,`+ + ` projections.projects3.project_role_check,`+ + ` projections.projects3.has_project_check,`+ + ` projections.projects3.private_labeling_setting`+ + ` FROM projections.projects3`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/projection/action.go b/internal/query/projection/action.go index 6d706511a6..a687bad50f 100644 --- a/internal/query/projection/action.go +++ b/internal/query/projection/action.go @@ -10,10 +10,11 @@ import ( "github.com/zitadel/zitadel/internal/eventstore/handler/crdb" "github.com/zitadel/zitadel/internal/repository/action" "github.com/zitadel/zitadel/internal/repository/instance" + "github.com/zitadel/zitadel/internal/repository/org" ) const ( - ActionTable = "projections.actions2" + ActionTable = "projections.actions3" ActionIDCol = "id" ActionCreationDateCol = "creation_date" ActionChangeDateCol = "change_date" @@ -25,6 +26,7 @@ const ( ActionScriptCol = "script" ActionTimeoutCol = "timeout" ActionAllowedToFailCol = "allowed_to_fail" + ActionOwnerRemovedCol = "owner_removed" ) type actionProjection struct { @@ -48,9 +50,11 @@ func newActionProjection(ctx context.Context, config crdb.StatementHandlerConfig crdb.NewColumn(ActionScriptCol, crdb.ColumnTypeText, crdb.Default("")), crdb.NewColumn(ActionTimeoutCol, crdb.ColumnTypeInt64, crdb.Default(0)), crdb.NewColumn(ActionAllowedToFailCol, crdb.ColumnTypeBool, crdb.Default(false)), + crdb.NewColumn(ActionOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(ActionInstanceIDCol, ActionIDCol), - crdb.WithIndex(crdb.NewIndex("actions_ro_idx", []string{ActionResourceOwnerCol})), + crdb.WithIndex(crdb.NewIndex("resource_owner", []string{ActionResourceOwnerCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{ActionOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -84,6 +88,15 @@ func (p *actionProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, + }, + }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ @@ -172,7 +185,7 @@ func (p *actionProjection) reduceActionDeactivated(event eventstore.Event) (*han func (p *actionProjection) reduceActionReactivated(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*action.ReactivatedEvent) if !ok { - return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-hwdqa", "reduce.wrong.event.type% s", action.ReactivatedEventType) + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-hwdqa", "reduce.wrong.event.type %s", action.ReactivatedEventType) } return crdb.NewUpdateStatement( e, @@ -201,3 +214,22 @@ func (p *actionProjection) reduceActionRemoved(event eventstore.Event) (*handler }, ), nil } + +func (p *actionProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-mSmWM", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(ActionChangeDateCol, e.CreationDate()), + handler.NewCol(ActionSequenceCol, e.Sequence()), + handler.NewCol(ActionOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(ActionInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(ActionResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/action_test.go b/internal/query/projection/action_test.go index a6a702cccf..b93875b4bb 100644 --- a/internal/query/projection/action_test.go +++ b/internal/query/projection/action_test.go @@ -11,6 +11,7 @@ import ( "github.com/zitadel/zitadel/internal/eventstore/repository" "github.com/zitadel/zitadel/internal/repository/action" "github.com/zitadel/zitadel/internal/repository/instance" + "github.com/zitadel/zitadel/internal/repository/org" ) func TestActionProjection_reduces(t *testing.T) { @@ -40,7 +41,7 @@ func TestActionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.actions2 (id, creation_date, change_date, resource_owner, instance_id, sequence, name, script, timeout, allowed_to_fail, action_state) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", + expectedStmt: "INSERT INTO projections.actions3 (id, creation_date, change_date, resource_owner, instance_id, sequence, name, script, timeout, allowed_to_fail, action_state) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "agg-id", anyArg{}, @@ -76,7 +77,7 @@ func TestActionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.actions2 SET (change_date, sequence, name, script) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.actions3 SET (change_date, sequence, name, script) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -107,7 +108,7 @@ func TestActionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.actions2 SET (change_date, sequence, action_state) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.actions3 SET (change_date, sequence, action_state) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -137,7 +138,7 @@ func TestActionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.actions2 SET (change_date, sequence, action_state) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.actions3 SET (change_date, sequence, action_state) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -167,7 +168,7 @@ func TestActionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.actions2 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.actions3 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -177,6 +178,36 @@ func TestActionProjection_reduces(t *testing.T) { }, }, }, + { + name: "reduceOwnerRemoved", + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + reduce: (&actionProjection{}).reduceOwnerRemoved, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.actions3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, { name: "reduceInstanceRemoved", args: args{ @@ -194,7 +225,7 @@ func TestActionProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.actions2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.actions3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/app.go b/internal/query/projection/app.go index 7d6e3bebc9..ee5b34fbca 100644 --- a/internal/query/projection/app.go +++ b/internal/query/projection/app.go @@ -10,11 +10,12 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/project" ) const ( - AppProjectionTable = "projections.apps3" + AppProjectionTable = "projections.apps4" AppAPITable = AppProjectionTable + "_" + appAPITableSuffix AppOIDCTable = AppProjectionTable + "_" + appOIDCTableSuffix AppSAMLTable = AppProjectionTable + "_" + appSAMLTableSuffix @@ -28,6 +29,7 @@ const ( AppColumnInstanceID = "instance_id" AppColumnState = "state" AppColumnSequence = "sequence" + AppColumnOwnerRemoved = "owner_removed" appAPITableSuffix = "api_configs" AppAPIConfigColumnAppID = "app_id" @@ -83,10 +85,11 @@ func newAppProjection(ctx context.Context, config crdb.StatementHandlerConfig) * crdb.NewColumn(AppColumnInstanceID, crdb.ColumnTypeText), crdb.NewColumn(AppColumnState, crdb.ColumnTypeEnum), crdb.NewColumn(AppColumnSequence, crdb.ColumnTypeInt64), + crdb.NewColumn(AppColumnOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(AppColumnInstanceID, AppColumnID), - crdb.WithIndex(crdb.NewIndex("app3_project_id_idx", []string{AppColumnProjectID})), - crdb.WithConstraint(crdb.NewConstraint("app3_id_unique", []string{AppColumnID})), + crdb.WithIndex(crdb.NewIndex("project_id", []string{AppColumnProjectID})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{AppColumnOwnerRemoved})), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(AppAPIConfigColumnAppID, crdb.ColumnTypeText), @@ -97,8 +100,8 @@ func newAppProjection(ctx context.Context, config crdb.StatementHandlerConfig) * }, crdb.NewPrimaryKey(AppAPIConfigColumnInstanceID, AppAPIConfigColumnAppID), appAPITableSuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_api_ref_apps3")), - crdb.WithIndex(crdb.NewIndex("api_client_id3_idx", []string{AppAPIConfigColumnClientID})), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), + crdb.WithIndex(crdb.NewIndex("client_id", []string{AppAPIConfigColumnClientID})), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(AppOIDCConfigColumnAppID, crdb.ColumnTypeText), @@ -122,8 +125,8 @@ func newAppProjection(ctx context.Context, config crdb.StatementHandlerConfig) * }, crdb.NewPrimaryKey(AppOIDCConfigColumnInstanceID, AppOIDCConfigColumnAppID), appOIDCTableSuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_oidc_ref_apps3")), - crdb.WithIndex(crdb.NewIndex("oidc_client_id_idx3", []string{AppOIDCConfigColumnClientID})), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), + crdb.WithIndex(crdb.NewIndex("client_id", []string{AppOIDCConfigColumnClientID})), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(AppSAMLConfigColumnAppID, crdb.ColumnTypeText), @@ -134,8 +137,8 @@ func newAppProjection(ctx context.Context, config crdb.StatementHandlerConfig) * }, crdb.NewPrimaryKey(AppSAMLConfigColumnInstanceID, AppSAMLConfigColumnAppID), appSAMLTableSuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_saml_ref_apps3")), - crdb.WithIndex(crdb.NewIndex("saml_entity_id_idx3", []string{AppSAMLConfigColumnEntityID})), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), + crdb.WithIndex(crdb.NewIndex("entity_id", []string{AppSAMLConfigColumnEntityID})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -205,6 +208,15 @@ func (p *appProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, + }, + }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ @@ -574,6 +586,26 @@ func (p *appProjection) reduceOIDCConfigSecretChanged(event eventstore.Event) (* ), nil } +func (p *appProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-Hyd1f", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(AppColumnChangeDate, e.CreationDate()), + handler.NewCol(AppColumnSequence, e.Sequence()), + handler.NewCol(AppColumnOwnerRemoved, true), + }, + []handler.Condition{ + handler.NewCond(AppColumnInstanceID, e.Aggregate().InstanceID), + handler.NewCond(AppColumnResourceOwner, e.Aggregate().ID), + }, + ), nil +} + func (p *appProjection) reduceSAMLConfigAdded(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*project.SAMLConfigAddedEvent) if !ok { diff --git a/internal/query/projection/app_test.go b/internal/query/projection/app_test.go index 0bfa9edfe3..9320b62ad3 100644 --- a/internal/query/projection/app_test.go +++ b/internal/query/projection/app_test.go @@ -11,6 +11,7 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/project" ) @@ -44,7 +45,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.apps3 (id, name, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.apps4 (id, name, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "app-id", "my-app", @@ -81,7 +82,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.apps3 SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.apps4 SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ "my-app", anyArg{}, @@ -113,7 +114,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.apps3 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.apps4 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ domain.AppStateInactive, anyArg{}, @@ -145,7 +146,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.apps3 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.apps4 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ domain.AppStateActive, anyArg{}, @@ -177,7 +178,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.apps3 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.apps4 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "app-id", "instance-id", @@ -204,7 +205,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.apps3 WHERE (project_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.apps4 WHERE (project_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -231,7 +232,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.apps3 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.apps4 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -262,7 +263,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.apps3_api_configs (app_id, instance_id, client_id, client_secret, auth_method) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.apps4_api_configs (app_id, instance_id, client_id, client_secret, auth_method) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "app-id", "instance-id", @@ -272,7 +273,7 @@ func TestAppProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.apps4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -306,7 +307,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.apps3_api_configs SET (client_secret, auth_method) = ($1, $2) WHERE (app_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.apps4_api_configs SET (client_secret, auth_method) = ($1, $2) WHERE (app_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, domain.APIAuthMethodTypePrivateKeyJWT, @@ -315,7 +316,7 @@ func TestAppProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.apps4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -368,7 +369,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.apps3_api_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.apps4_api_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ anyArg{}, "app-id", @@ -376,7 +377,7 @@ func TestAppProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.apps4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -423,7 +424,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.apps3_oidc_configs (app_id, instance_id, version, client_id, client_secret, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)", + expectedStmt: "INSERT INTO projections.apps4_oidc_configs (app_id, instance_id, version, client_id, client_secret, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)", expectedArgs: []interface{}{ "app-id", "instance-id", @@ -446,7 +447,7 @@ func TestAppProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.apps4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -491,7 +492,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.apps3_oidc_configs SET (version, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) WHERE (app_id = $15) AND (instance_id = $16)", + expectedStmt: "UPDATE projections.apps4_oidc_configs SET (version, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) WHERE (app_id = $15) AND (instance_id = $16)", expectedArgs: []interface{}{ domain.OIDCVersionV1, database.StringArray{"redirect.one.ch", "redirect.two.ch"}, @@ -512,7 +513,7 @@ func TestAppProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.apps4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -565,7 +566,7 @@ func TestAppProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.apps3_oidc_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.apps4_oidc_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ anyArg{}, "app-id", @@ -573,7 +574,7 @@ func TestAppProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.apps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.apps4 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -585,6 +586,36 @@ func TestAppProjection_reduces(t *testing.T) { }, }, }, + { + name: "project.reduceOwnerRemoved", + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + reduce: (&appProjection{}).reduceOwnerRemoved, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.apps4 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/authn_key.go b/internal/query/projection/authn_key.go index 305d391142..8288756612 100644 --- a/internal/query/projection/authn_key.go +++ b/internal/query/projection/authn_key.go @@ -10,14 +10,16 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/user" ) const ( - AuthNKeyTable = "projections.authn_keys" + AuthNKeyTable = "projections.authn_keys2" AuthNKeyIDCol = "id" AuthNKeyCreationDateCol = "creation_date" + AuthNKeyChangeDateCol = "change_date" AuthNKeyResourceOwnerCol = "resource_owner" AuthNKeyInstanceIDCol = "instance_id" AuthNKeyAggregateIDCol = "aggregate_id" @@ -28,6 +30,7 @@ const ( AuthNKeyPublicKeyCol = "public_key" AuthNKeyTypeCol = "type" AuthNKeyEnabledCol = "enabled" + AuthNKeyOwnerRemovedCol = "owner_removed" ) type authNKeyProjection struct { @@ -42,6 +45,7 @@ func newAuthNKeyProjection(ctx context.Context, config crdb.StatementHandlerConf crdb.NewTable([]*crdb.Column{ crdb.NewColumn(AuthNKeyIDCol, crdb.ColumnTypeText), crdb.NewColumn(AuthNKeyCreationDateCol, crdb.ColumnTypeTimestamp), + crdb.NewColumn(AuthNKeyChangeDateCol, crdb.ColumnTypeTimestamp), crdb.NewColumn(AuthNKeyResourceOwnerCol, crdb.ColumnTypeText), crdb.NewColumn(AuthNKeyInstanceIDCol, crdb.ColumnTypeText), crdb.NewColumn(AuthNKeyAggregateIDCol, crdb.ColumnTypeText), @@ -52,10 +56,12 @@ func newAuthNKeyProjection(ctx context.Context, config crdb.StatementHandlerConf crdb.NewColumn(AuthNKeyPublicKeyCol, crdb.ColumnTypeBytes), crdb.NewColumn(AuthNKeyEnabledCol, crdb.ColumnTypeBool, crdb.Default(true)), crdb.NewColumn(AuthNKeyTypeCol, crdb.ColumnTypeEnum, crdb.Default(0)), + crdb.NewColumn(AuthNKeyOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(AuthNKeyInstanceIDCol, AuthNKeyIDCol), - crdb.WithIndex(crdb.NewIndex("enabled_idx", []string{AuthNKeyEnabledCol})), - crdb.WithIndex(crdb.NewIndex("identifier_idx", []string{AuthNKeyIdentifierCol})), + crdb.WithIndex(crdb.NewIndex("enabled", []string{AuthNKeyEnabledCol})), + crdb.WithIndex(crdb.NewIndex("identifier", []string{AuthNKeyIdentifierCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{AuthNKeyOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -110,6 +116,15 @@ func (p *authNKeyProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, + }, + }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ @@ -152,29 +167,30 @@ func (p *authNKeyProjection) reduceAuthNKeyAdded(event eventstore.Event) (*handl default: return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-Dgb32", "reduce.wrong.event.type %v", []eventstore.EventType{project.ApplicationKeyAddedEventType, user.MachineKeyAddedEventType}) } - return crdb.NewMultiStatement( + return crdb.NewCreateStatement( &authNKeyEvent, - crdb.AddCreateStatement( - []handler.Column{ - handler.NewCol(AuthNKeyIDCol, authNKeyEvent.keyID), - handler.NewCol(AuthNKeyCreationDateCol, authNKeyEvent.CreationDate()), - handler.NewCol(AuthNKeyResourceOwnerCol, authNKeyEvent.Aggregate().ResourceOwner), - handler.NewCol(AuthNKeyInstanceIDCol, authNKeyEvent.Aggregate().InstanceID), - handler.NewCol(AuthNKeyAggregateIDCol, authNKeyEvent.Aggregate().ID), - handler.NewCol(AuthNKeySequenceCol, authNKeyEvent.Sequence()), - handler.NewCol(AuthNKeyObjectIDCol, authNKeyEvent.objectID), - handler.NewCol(AuthNKeyExpirationCol, authNKeyEvent.expiration), - handler.NewCol(AuthNKeyIdentifierCol, authNKeyEvent.identifier), - handler.NewCol(AuthNKeyPublicKeyCol, authNKeyEvent.publicKey), - handler.NewCol(AuthNKeyTypeCol, authNKeyEvent.keyType), - }, - ), + []handler.Column{ + handler.NewCol(AuthNKeyIDCol, authNKeyEvent.keyID), + handler.NewCol(AuthNKeyCreationDateCol, authNKeyEvent.CreationDate()), + handler.NewCol(AuthNKeyChangeDateCol, authNKeyEvent.CreationDate()), + handler.NewCol(AuthNKeyResourceOwnerCol, authNKeyEvent.Aggregate().ResourceOwner), + handler.NewCol(AuthNKeyInstanceIDCol, authNKeyEvent.Aggregate().InstanceID), + handler.NewCol(AuthNKeyAggregateIDCol, authNKeyEvent.Aggregate().ID), + handler.NewCol(AuthNKeySequenceCol, authNKeyEvent.Sequence()), + handler.NewCol(AuthNKeyObjectIDCol, authNKeyEvent.objectID), + handler.NewCol(AuthNKeyExpirationCol, authNKeyEvent.expiration), + handler.NewCol(AuthNKeyIdentifierCol, authNKeyEvent.identifier), + handler.NewCol(AuthNKeyPublicKeyCol, authNKeyEvent.publicKey), + handler.NewCol(AuthNKeyTypeCol, authNKeyEvent.keyType), + }, ), nil } func (p *authNKeyProjection) reduceAuthNKeyEnabledChanged(event eventstore.Event) (*handler.Statement, error) { var appID string var enabled bool + var changeDate time.Time + var sequence uint64 switch e := event.(type) { case *project.APIConfigChangedEvent: if e.AuthMethodType == nil { @@ -182,18 +198,26 @@ func (p *authNKeyProjection) reduceAuthNKeyEnabledChanged(event eventstore.Event } appID = e.AppID enabled = *e.AuthMethodType == domain.APIAuthMethodTypePrivateKeyJWT + changeDate = e.CreationDate() + sequence = e.Sequence() case *project.OIDCConfigChangedEvent: if e.AuthMethodType == nil { return crdb.NewNoOpStatement(event), nil } appID = e.AppID enabled = *e.AuthMethodType == domain.OIDCAuthMethodTypePrivateKeyJWT + changeDate = e.CreationDate() + sequence = e.Sequence() default: return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-Dbrt1", "reduce.wrong.event.type %v", []eventstore.EventType{project.APIConfigChangedType, project.OIDCConfigChangedType}) } return crdb.NewUpdateStatement( event, - []handler.Column{handler.NewCol(AuthNKeyEnabledCol, enabled)}, + []handler.Column{ + handler.NewCol(AuthNKeyChangeDateCol, changeDate), + handler.NewCol(AuthNKeySequenceCol, sequence), + handler.NewCol(AuthNKeyEnabledCol, enabled), + }, []handler.Condition{ handler.NewCond(AuthNKeyObjectIDCol, appID), handler.NewCond(AuthNKeyInstanceIDCol, event.Aggregate().InstanceID), @@ -225,3 +249,23 @@ func (p *authNKeyProjection) reduceAuthNKeyRemoved(event eventstore.Event) (*han }, ), nil } + +func (p *authNKeyProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-Hyd1f", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(AuthNKeyChangeDateCol, e.CreationDate()), + handler.NewCol(AuthNKeySequenceCol, e.Sequence()), + handler.NewCol(AuthNKeyOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(AuthNKeyInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(AuthNKeyResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/authn_key_test.go b/internal/query/projection/authn_key_test.go index d4912fbe4e..f75b2590bb 100644 --- a/internal/query/projection/authn_key_test.go +++ b/internal/query/projection/authn_key_test.go @@ -9,6 +9,7 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/user" ) @@ -40,10 +41,11 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.authn_keys (id, creation_date, resource_owner, instance_id, aggregate_id, sequence, object_id, expiration, identifier, public_key, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", + expectedStmt: "INSERT INTO projections.authn_keys2 (id, creation_date, change_date, resource_owner, instance_id, aggregate_id, sequence, object_id, expiration, identifier, public_key, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)", expectedArgs: []interface{}{ "keyId", anyArg{}, + anyArg{}, "ro-id", "instance-id", "agg-id", @@ -76,10 +78,11 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.authn_keys (id, creation_date, resource_owner, instance_id, aggregate_id, sequence, object_id, expiration, identifier, public_key, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", + expectedStmt: "INSERT INTO projections.authn_keys2 (id, creation_date, change_date, resource_owner, instance_id, aggregate_id, sequence, object_id, expiration, identifier, public_key, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)", expectedArgs: []interface{}{ "keyId", anyArg{}, + anyArg{}, "ro-id", "instance-id", "agg-id", @@ -112,7 +115,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.authn_keys WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.authn_keys2 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "keyId", "instance-id", @@ -158,8 +161,10 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.authn_keys SET enabled = $1 WHERE (object_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.authn_keys2 SET (change_date, sequence, enabled) = ($1, $2, $3) WHERE (object_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ + anyArg{}, + uint64(15), false, "appId", "instance-id", @@ -186,8 +191,10 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.authn_keys SET enabled = $1 WHERE (object_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.authn_keys2 SET (change_date, sequence, enabled) = ($1, $2, $3) WHERE (object_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ + anyArg{}, + uint64(15), true, "appId", "instance-id", @@ -214,7 +221,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.authn_keys WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.authn_keys2 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "keyId", "instance-id", @@ -241,7 +248,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.authn_keys WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.authn_keys2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -286,8 +293,10 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.authn_keys SET enabled = $1 WHERE (object_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.authn_keys2 SET (change_date, sequence, enabled) = ($1, $2, $3) WHERE (object_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ + anyArg{}, + uint64(15), false, "appId", "instance-id", @@ -314,8 +323,10 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.authn_keys SET enabled = $1 WHERE (object_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.authn_keys2 SET (change_date, sequence, enabled) = ($1, $2, $3) WHERE (object_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ + anyArg{}, + uint64(15), true, "appId", "instance-id", @@ -342,7 +353,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.authn_keys WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.authn_keys2 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "keyId", "instance-id", @@ -369,7 +380,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.authn_keys WHERE (object_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.authn_keys2 WHERE (object_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "appId", "instance-id", @@ -396,7 +407,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.authn_keys WHERE (aggregate_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.authn_keys2 WHERE (aggregate_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -423,7 +434,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.authn_keys WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.authn_keys2 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "keyId", "instance-id", @@ -450,7 +461,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.authn_keys WHERE (aggregate_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.authn_keys2 WHERE (aggregate_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -460,6 +471,36 @@ func TestAuthNKeyProjection_reduces(t *testing.T) { }, }, }, + { + name: "reduceOwnerRemoved", + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + reduce: (&authNKeyProjection{}).reduceOwnerRemoved, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.authn_keys2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/custom_text.go b/internal/query/projection/custom_text.go index 0ec0096fcc..56e21e2b3f 100644 --- a/internal/query/projection/custom_text.go +++ b/internal/query/projection/custom_text.go @@ -13,7 +13,7 @@ import ( ) const ( - CustomTextTable = "projections.custom_texts" + CustomTextTable = "projections.custom_texts2" CustomTextAggregateIDCol = "aggregate_id" CustomTextInstanceIDCol = "instance_id" @@ -25,6 +25,7 @@ const ( CustomTextLanguageCol = "language" CustomTextKeyCol = "key" CustomTextTextCol = "text" + CustomTextOwnerRemovedCol = "owner_removed" ) type customTextProjection struct { @@ -47,8 +48,10 @@ func newCustomTextProjection(ctx context.Context, config crdb.StatementHandlerCo crdb.NewColumn(CustomTextLanguageCol, crdb.ColumnTypeText), crdb.NewColumn(CustomTextKeyCol, crdb.ColumnTypeText), crdb.NewColumn(CustomTextTextCol, crdb.ColumnTypeText), + crdb.NewColumn(CustomTextOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(CustomTextInstanceIDCol, CustomTextAggregateIDCol, CustomTextTemplateCol, CustomTextKeyCol, CustomTextLanguageCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{CustomTextOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -72,6 +75,10 @@ func (p *customTextProjection) reducers() []handler.AggregateReducer { Event: org.CustomTextTemplateRemovedEventType, Reduce: p.reduceTemplateRemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -174,3 +181,23 @@ func (p *customTextProjection) reduceTemplateRemoved(event eventstore.Event) (*h handler.NewCond(CustomTextInstanceIDCol, customTextEvent.Aggregate().InstanceID), }), nil } + +func (p *customTextProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-V2T3z", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(CustomTextChangeDateCol, e.CreationDate()), + handler.NewCol(CustomTextSequenceCol, e.Sequence()), + handler.NewCol(CustomTextOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(CustomTextInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(CustomTextAggregateIDCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/custom_text_test.go b/internal/query/projection/custom_text_test.go index 577132fd01..2b17cb86bf 100644 --- a/internal/query/projection/custom_text_test.go +++ b/internal/query/projection/custom_text_test.go @@ -43,7 +43,7 @@ func TestCustomTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.custom_texts (aggregate_id, instance_id, creation_date, change_date, sequence, is_default, template, language, key, text) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (instance_id, aggregate_id, template, key, language) DO UPDATE SET (creation_date, change_date, sequence, is_default, text) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.is_default, EXCLUDED.text)", + expectedStmt: "INSERT INTO projections.custom_texts2 (aggregate_id, instance_id, creation_date, change_date, sequence, is_default, template, language, key, text) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (instance_id, aggregate_id, template, key, language) DO UPDATE SET (creation_date, change_date, sequence, is_default, text) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.is_default, EXCLUDED.text)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -82,7 +82,7 @@ func TestCustomTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.custom_texts WHERE (aggregate_id = $1) AND (template = $2) AND (key = $3) AND (language = $4) AND (instance_id = $5)", + expectedStmt: "DELETE FROM projections.custom_texts2 WHERE (aggregate_id = $1) AND (template = $2) AND (key = $3) AND (language = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ "agg-id", "InitCode", @@ -116,7 +116,7 @@ func TestCustomTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.custom_texts WHERE (aggregate_id = $1) AND (template = $2) AND (language = $3) AND (instance_id = $4)", + expectedStmt: "DELETE FROM projections.custom_texts2 WHERE (aggregate_id = $1) AND (template = $2) AND (language = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "agg-id", "InitCode", @@ -145,7 +145,7 @@ func TestCustomTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.custom_texts WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.custom_texts2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -176,7 +176,7 @@ func TestCustomTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.custom_texts (aggregate_id, instance_id, creation_date, change_date, sequence, is_default, template, language, key, text) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (instance_id, aggregate_id, template, key, language) DO UPDATE SET (creation_date, change_date, sequence, is_default, text) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.is_default, EXCLUDED.text)", + expectedStmt: "INSERT INTO projections.custom_texts2 (aggregate_id, instance_id, creation_date, change_date, sequence, is_default, template, language, key, text) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (instance_id, aggregate_id, template, key, language) DO UPDATE SET (creation_date, change_date, sequence, is_default, text) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.is_default, EXCLUDED.text)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -215,7 +215,7 @@ func TestCustomTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.custom_texts WHERE (aggregate_id = $1) AND (template = $2) AND (key = $3) AND (language = $4) AND (instance_id = $5)", + expectedStmt: "DELETE FROM projections.custom_texts2 WHERE (aggregate_id = $1) AND (template = $2) AND (key = $3) AND (language = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ "agg-id", "InitCode", @@ -249,7 +249,7 @@ func TestCustomTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.custom_texts WHERE (aggregate_id = $1) AND (template = $2) AND (language = $3) AND (instance_id = $4)", + expectedStmt: "DELETE FROM projections.custom_texts2 WHERE (aggregate_id = $1) AND (template = $2) AND (language = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "agg-id", "InitCode", @@ -261,6 +261,36 @@ func TestCustomTextProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&customTextProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.custom_texts2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (aggregate_id = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/domain_policy.go b/internal/query/projection/domain_policy.go index 54053317d5..dc192c58f5 100644 --- a/internal/query/projection/domain_policy.go +++ b/internal/query/projection/domain_policy.go @@ -14,7 +14,7 @@ import ( ) const ( - DomainPolicyTable = "projections.domain_policies" + DomainPolicyTable = "projections.domain_policies2" DomainPolicyIDCol = "id" DomainPolicyCreationDateCol = "creation_date" @@ -27,6 +27,7 @@ const ( DomainPolicyIsDefaultCol = "is_default" DomainPolicyResourceOwnerCol = "resource_owner" DomainPolicyInstanceIDCol = "instance_id" + DomainPolicyOwnerRemovedCol = "owner_removed" ) type domainPolicyProjection struct { @@ -50,8 +51,10 @@ func newDomainPolicyProjection(ctx context.Context, config crdb.StatementHandler crdb.NewColumn(DomainPolicyIsDefaultCol, crdb.ColumnTypeBool, crdb.Default(false)), crdb.NewColumn(DomainPolicyResourceOwnerCol, crdb.ColumnTypeText), crdb.NewColumn(DomainPolicyInstanceIDCol, crdb.ColumnTypeText), + crdb.NewColumn(DomainPolicyOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(DomainPolicyInstanceIDCol, DomainPolicyIDCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{DomainPolicyOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -75,6 +78,10 @@ func (p *domainPolicyProjection) reducers() []handler.AggregateReducer { Event: org.DomainPolicyRemovedEventType, Reduce: p.reduceRemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -171,3 +178,23 @@ func (p *domainPolicyProjection) reduceRemoved(event eventstore.Event) (*handler handler.NewCond(DomainPolicyInstanceIDCol, policyEvent.Aggregate().InstanceID), }), nil } + +func (p *domainPolicyProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-JYD2K", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(DomainPolicyChangeDateCol, e.CreationDate()), + handler.NewCol(DomainPolicySequenceCol, e.Sequence()), + handler.NewCol(DomainPolicyOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(DomainPolicyInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(DomainPolicyResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/domain_policy_test.go b/internal/query/projection/domain_policy_test.go index eada1a6f19..4823ff0f4b 100644 --- a/internal/query/projection/domain_policy_test.go +++ b/internal/query/projection/domain_policy_test.go @@ -43,7 +43,7 @@ func TestDomainPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.domain_policies (creation_date, change_date, sequence, id, state, user_login_must_be_domain, validate_org_domains, smtp_sender_address_matches_instance_domain, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", + expectedStmt: "INSERT INTO projections.domain_policies2 (creation_date, change_date, sequence, id, state, user_login_must_be_domain, validate_org_domains, smtp_sender_address_matches_instance_domain, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -83,7 +83,7 @@ func TestDomainPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.domain_policies SET (change_date, sequence, user_login_must_be_domain, validate_org_domains, smtp_sender_address_matches_instance_domain) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.domain_policies2 SET (change_date, sequence, user_login_must_be_domain, validate_org_domains, smtp_sender_address_matches_instance_domain) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -115,7 +115,7 @@ func TestDomainPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.domain_policies WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.domain_policies2 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -142,7 +142,7 @@ func TestDomainPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.domain_policies WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.domain_policies2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -172,7 +172,7 @@ func TestDomainPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.domain_policies (creation_date, change_date, sequence, id, state, user_login_must_be_domain, validate_org_domains, smtp_sender_address_matches_instance_domain, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", + expectedStmt: "INSERT INTO projections.domain_policies2 (creation_date, change_date, sequence, id, state, user_login_must_be_domain, validate_org_domains, smtp_sender_address_matches_instance_domain, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -212,7 +212,7 @@ func TestDomainPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.domain_policies SET (change_date, sequence, user_login_must_be_domain, validate_org_domains, smtp_sender_address_matches_instance_domain) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.domain_policies2 SET (change_date, sequence, user_login_must_be_domain, validate_org_domains, smtp_sender_address_matches_instance_domain) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -227,6 +227,36 @@ func TestDomainPolicyProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&domainPolicyProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.domain_policies2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/flow.go b/internal/query/projection/flow.go index 08750e588a..4b03d74515 100644 --- a/internal/query/projection/flow.go +++ b/internal/query/projection/flow.go @@ -12,7 +12,7 @@ import ( ) const ( - FlowTriggerTable = "projections.flows_triggers" + FlowTriggerTable = "projections.flow_triggers2" FlowTypeCol = "flow_type" FlowChangeDateCol = "change_date" FlowSequenceCol = "sequence" @@ -21,6 +21,7 @@ const ( FlowInstanceIDCol = "instance_id" FlowActionTriggerSequenceCol = "trigger_sequence" FlowActionIDCol = "action_id" + FlowOwnerRemovedCol = "owner_removed" ) type flowProjection struct { @@ -41,8 +42,10 @@ func newFlowProjection(ctx context.Context, config crdb.StatementHandlerConfig) crdb.NewColumn(FlowInstanceIDCol, crdb.ColumnTypeText), crdb.NewColumn(FlowActionTriggerSequenceCol, crdb.ColumnTypeInt64), crdb.NewColumn(FlowActionIDCol, crdb.ColumnTypeText), + crdb.NewColumn(FlowOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(FlowInstanceIDCol, FlowTypeCol, FlowTriggerTypeCol, FlowResourceOwnerCol, FlowActionIDCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{FlowOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -62,6 +65,10 @@ func (p *flowProjection) reducers() []handler.AggregateReducer { Event: org.FlowClearedEventType, Reduce: p.reduceFlowClearedEventType, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -121,3 +128,23 @@ func (p *flowProjection) reduceFlowClearedEventType(event eventstore.Event) (*ha }, ), nil } + +func (p *flowProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-Yd7WC", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(FlowChangeDateCol, e.CreationDate()), + handler.NewCol(FlowSequenceCol, e.Sequence()), + handler.NewCol(FlowOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(FlowInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(FlowResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/flow_test.go b/internal/query/projection/flow_test.go index e7834c5d94..3ebfb8de75 100644 --- a/internal/query/projection/flow_test.go +++ b/internal/query/projection/flow_test.go @@ -39,7 +39,7 @@ func TestFlowProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.flows_triggers WHERE (flow_type = $1) AND (trigger_type = $2) AND (resource_owner = $3) AND (instance_id = $4)", + expectedStmt: "DELETE FROM projections.flow_triggers2 WHERE (flow_type = $1) AND (trigger_type = $2) AND (resource_owner = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ domain.FlowTypeExternalAuthentication, domain.TriggerTypePostAuthentication, @@ -48,7 +48,7 @@ func TestFlowProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.flows_triggers (resource_owner, instance_id, flow_type, change_date, sequence, trigger_type, action_id, trigger_sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.flow_triggers2 (resource_owner, instance_id, flow_type, change_date, sequence, trigger_type, action_id, trigger_sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "ro-id", "instance-id", @@ -61,7 +61,7 @@ func TestFlowProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.flows_triggers (resource_owner, instance_id, flow_type, change_date, sequence, trigger_type, action_id, trigger_sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.flow_triggers2 (resource_owner, instance_id, flow_type, change_date, sequence, trigger_type, action_id, trigger_sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "ro-id", "instance-id", @@ -94,7 +94,7 @@ func TestFlowProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.flows_triggers WHERE (flow_type = $1) AND (resource_owner = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.flow_triggers2 WHERE (flow_type = $1) AND (resource_owner = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ domain.FlowTypeExternalAuthentication, "ro-id", @@ -105,6 +105,36 @@ func TestFlowProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&flowProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.flow_triggers2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, { name: "instance reduceInstanceRemoved", args: args{ @@ -122,7 +152,7 @@ func TestFlowProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.flows_triggers WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.flow_triggers2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/idp.go b/internal/query/projection/idp.go index 2faddc9429..94c1c9798b 100644 --- a/internal/query/projection/idp.go +++ b/internal/query/projection/idp.go @@ -15,7 +15,7 @@ import ( ) const ( - IDPTable = "projections.idps2" + IDPTable = "projections.idps3" IDPOIDCTable = IDPTable + "_" + IDPOIDCSuffix IDPJWTTable = IDPTable + "_" + IDPJWTSuffix @@ -34,6 +34,7 @@ const ( IDPOwnerTypeCol = "owner_type" IDPAutoRegisterCol = "auto_register" IDPTypeCol = "type" + IDPOwnerRemovedCol = "owner_removed" OIDCConfigIDPIDCol = "idp_id" OIDCConfigInstanceIDCol = "instance_id" @@ -76,10 +77,11 @@ func newIDPProjection(ctx context.Context, config crdb.StatementHandlerConfig) * crdb.NewColumn(IDPOwnerTypeCol, crdb.ColumnTypeEnum), crdb.NewColumn(IDPAutoRegisterCol, crdb.ColumnTypeBool, crdb.Default(false)), crdb.NewColumn(IDPTypeCol, crdb.ColumnTypeEnum, crdb.Nullable()), + crdb.NewColumn(IDPOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(IDPInstanceIDCol, IDPIDCol), - crdb.WithIndex(crdb.NewIndex("idp_ro_idx", []string{IDPResourceOwnerCol})), - crdb.WithConstraint(crdb.NewConstraint("idp_id_unique", []string{IDPIDCol})), + crdb.WithIndex(crdb.NewIndex("resource_owner", []string{IDPResourceOwnerCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{IDPOwnerRemovedCol})), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(OIDCConfigIDPIDCol, crdb.ColumnTypeText), @@ -95,7 +97,7 @@ func newIDPProjection(ctx context.Context, config crdb.StatementHandlerConfig) * }, crdb.NewPrimaryKey(OIDCConfigInstanceIDCol, OIDCConfigIDPIDCol), IDPOIDCSuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_oidc_ref_idp")), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(JWTConfigIDPIDCol, crdb.ColumnTypeText), @@ -107,7 +109,7 @@ func newIDPProjection(ctx context.Context, config crdb.StatementHandlerConfig) * }, crdb.NewPrimaryKey(JWTConfigInstanceIDCol, JWTConfigIDPIDCol), IDPJWTSuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_jwt_ref_idp")), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -200,6 +202,10 @@ func (p *idpProjection) reducers() []handler.AggregateReducer { Event: org.IDPJWTConfigChangedEventType, Reduce: p.reduceJWTConfigChanged, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, } @@ -541,3 +547,23 @@ func (p *idpProjection) reduceJWTConfigChanged(event eventstore.Event) (*handler ), ), nil } + +func (p *idpProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-YsbQC", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(IDPChangeDateCol, e.CreationDate()), + handler.NewCol(IDPSequenceCol, e.Sequence()), + handler.NewCol(IDPOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(IDPInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(IDPResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/idp_login_policy_link.go b/internal/query/projection/idp_login_policy_link.go index 8f33f90d21..ced104f4bf 100644 --- a/internal/query/projection/idp_login_policy_link.go +++ b/internal/query/projection/idp_login_policy_link.go @@ -14,7 +14,7 @@ import ( ) const ( - IDPLoginPolicyLinkTable = "projections.idp_login_policy_links3" + IDPLoginPolicyLinkTable = "projections.idp_login_policy_links4" IDPLoginPolicyLinkIDPIDCol = "idp_id" IDPLoginPolicyLinkAggregateIDCol = "aggregate_id" @@ -24,6 +24,7 @@ const ( IDPLoginPolicyLinkResourceOwnerCol = "resource_owner" IDPLoginPolicyLinkInstanceIDCol = "instance_id" IDPLoginPolicyLinkProviderTypeCol = "provider_type" + IDPLoginPolicyLinkOwnerRemovedCol = "owner_removed" ) type idpLoginPolicyLinkProjection struct { @@ -44,9 +45,11 @@ func newIDPLoginPolicyLinkProjection(ctx context.Context, config crdb.StatementH crdb.NewColumn(IDPLoginPolicyLinkResourceOwnerCol, crdb.ColumnTypeText), crdb.NewColumn(IDPLoginPolicyLinkInstanceIDCol, crdb.ColumnTypeText), crdb.NewColumn(IDPLoginPolicyLinkProviderTypeCol, crdb.ColumnTypeEnum), + crdb.NewColumn(IDPLoginPolicyLinkOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(IDPLoginPolicyLinkInstanceIDCol, IDPLoginPolicyLinkAggregateIDCol, IDPLoginPolicyLinkIDPIDCol), - crdb.WithIndex(crdb.NewIndex("link_ro_idx", []string{IDPLoginPolicyLinkResourceOwnerCol})), + crdb.WithIndex(crdb.NewIndex("resource_owner", []string{IDPLoginPolicyLinkResourceOwnerCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{IDPLoginPolicyLinkOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -74,14 +77,14 @@ func (p *idpLoginPolicyLinkProjection) reducers() []handler.AggregateReducer { Event: org.LoginPolicyRemovedEventType, Reduce: p.reducePolicyRemoved, }, - { - Event: org.OrgRemovedEventType, - Reduce: p.reduceOrgRemoved, - }, { Event: org.IDPConfigRemovedEventType, Reduce: p.reduceIDPConfigRemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -206,19 +209,6 @@ func (p *idpLoginPolicyLinkProjection) reduceIDPConfigRemoved(event eventstore.E ), nil } -func (p *idpLoginPolicyLinkProjection) reduceOrgRemoved(event eventstore.Event) (*handler.Statement, error) { - e, ok := event.(*org.OrgRemovedEvent) - if !ok { - return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-QSoSe", "reduce.wrong.event.type %s", org.OrgRemovedEventType) - } - return crdb.NewDeleteStatement(e, - []handler.Condition{ - handler.NewCond(IDPLoginPolicyLinkResourceOwnerCol, e.Aggregate().ID), - handler.NewCond(IDPLoginPolicyLinkInstanceIDCol, event.Aggregate().InstanceID), - }, - ), nil -} - func (p *idpLoginPolicyLinkProjection) reducePolicyRemoved(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*org.LoginPolicyRemovedEvent) if !ok { @@ -231,3 +221,23 @@ func (p *idpLoginPolicyLinkProjection) reducePolicyRemoved(event eventstore.Even }, ), nil } + +func (p *idpLoginPolicyLinkProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-YbhOv", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(IDPLoginPolicyLinkChangeDateCol, e.CreationDate()), + handler.NewCol(IDPLoginPolicyLinkSequenceCol, e.Sequence()), + handler.NewCol(IDPLoginPolicyLinkOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(IDPLoginPolicyLinkInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(IDPLoginPolicyLinkResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/idp_login_policy_link_test.go b/internal/query/projection/idp_login_policy_link_test.go index 1c963e7077..c85fa3d30c 100644 --- a/internal/query/projection/idp_login_policy_link_test.go +++ b/internal/query/projection/idp_login_policy_link_test.go @@ -42,7 +42,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.idp_login_policy_links3 (idp_id, aggregate_id, creation_date, change_date, sequence, resource_owner, instance_id, provider_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.idp_login_policy_links4 (idp_id, aggregate_id, creation_date, change_date, sequence, resource_owner, instance_id, provider_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "idp-config-id", "agg-id", @@ -78,7 +78,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_login_policy_links3 WHERE (idp_id = $1) AND (aggregate_id = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.idp_login_policy_links4 WHERE (idp_id = $1) AND (aggregate_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "idp-config-id", "agg-id", @@ -109,7 +109,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_login_policy_links3 WHERE (idp_id = $1) AND (aggregate_id = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.idp_login_policy_links4 WHERE (idp_id = $1) AND (aggregate_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "idp-config-id", "agg-id", @@ -140,7 +140,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.idp_login_policy_links3 (idp_id, aggregate_id, creation_date, change_date, sequence, resource_owner, instance_id, provider_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.idp_login_policy_links4 (idp_id, aggregate_id, creation_date, change_date, sequence, resource_owner, instance_id, provider_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "idp-config-id", "agg-id", @@ -176,7 +176,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_login_policy_links3 WHERE (idp_id = $1) AND (aggregate_id = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.idp_login_policy_links4 WHERE (idp_id = $1) AND (aggregate_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "idp-config-id", "agg-id", @@ -204,7 +204,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_login_policy_links3 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.idp_login_policy_links4 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -233,7 +233,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_login_policy_links3 WHERE (idp_id = $1) AND (aggregate_id = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.idp_login_policy_links4 WHERE (idp_id = $1) AND (aggregate_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "idp-config-id", "agg-id", @@ -244,33 +244,6 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { }, }, }, - { - name: "reduceOrgRemoved", - args: args{ - event: getEvent(testEvent( - repository.EventType(org.OrgRemovedEventType), - org.AggregateType, - []byte(`{}`), - ), org.OrgRemovedEventMapper), - }, - reduce: (&idpLoginPolicyLinkProjection{}).reduceOrgRemoved, - want: wantReduce{ - aggregateType: org.AggregateType, - sequence: 15, - previousSequence: 10, - executer: &testExecuter{ - executions: []execution{ - { - expectedStmt: "DELETE FROM projections.idp_login_policy_links3 WHERE (resource_owner = $1) AND (instance_id = $2)", - expectedArgs: []interface{}{ - "agg-id", - "instance-id", - }, - }, - }, - }, - }, - }, { name: "reducePolicyRemoved", args: args{ @@ -288,7 +261,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_login_policy_links3 WHERE (aggregate_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.idp_login_policy_links4 WHERE (aggregate_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -317,7 +290,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_login_policy_links3 WHERE (idp_id = $1) AND (resource_owner = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.idp_login_policy_links4 WHERE (idp_id = $1) AND (resource_owner = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "idp-config-id", "ro-id", @@ -347,7 +320,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_login_policy_links3 WHERE (idp_id = $1) AND (resource_owner = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.idp_login_policy_links4 WHERE (idp_id = $1) AND (resource_owner = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "idp-config-id", "ro-id", @@ -358,6 +331,36 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&idpLoginPolicyLinkProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.idp_login_policy_links4 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/idp_test.go b/internal/query/projection/idp_test.go index f19b268388..10bbe76164 100644 --- a/internal/query/projection/idp_test.go +++ b/internal/query/projection/idp_test.go @@ -46,7 +46,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.idps2 (id, creation_date, change_date, sequence, resource_owner, instance_id, state, name, styling_type, auto_register, owner_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", + expectedStmt: "INSERT INTO projections.idps3 (id, creation_date, change_date, sequence, resource_owner, instance_id, state, name, styling_type, auto_register, owner_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "idp-config-id", anyArg{}, @@ -87,7 +87,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (name, styling_type, auto_register, change_date, sequence) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.idps3 SET (name, styling_type, auto_register, change_date, sequence) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ "custom-zitadel-instance", domain.IDPConfigStylingTypeGoogle, @@ -121,7 +121,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idps3 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ domain.IDPConfigStateInactive, anyArg{}, @@ -153,7 +153,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idps3 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ domain.IDPConfigStateActive, anyArg{}, @@ -185,7 +185,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idps2 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.idps3 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "idp-config-id", "instance-id", @@ -212,7 +212,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idps2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.idps3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -252,7 +252,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idps3 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -262,7 +262,7 @@ func TestIDPProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idps2_oidc_config (idp_id, instance_id, client_id, client_secret, issuer, scopes, display_name_mapping, username_mapping, authorization_endpoint, token_endpoint) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.idps3_oidc_config (idp_id, instance_id, client_id, client_secret, issuer, scopes, display_name_mapping, username_mapping, authorization_endpoint, token_endpoint) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ "idp-config-id", "instance-id", @@ -311,7 +311,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.idps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -320,7 +320,7 @@ func TestIDPProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idps2_oidc_config SET (client_id, client_secret, issuer, authorization_endpoint, token_endpoint, scopes, display_name_mapping, username_mapping) = ($1, $2, $3, $4, $5, $6, $7, $8) WHERE (idp_id = $9) AND (instance_id = $10)", + expectedStmt: "UPDATE projections.idps3_oidc_config SET (client_id, client_secret, issuer, authorization_endpoint, token_endpoint, scopes, display_name_mapping, username_mapping) = ($1, $2, $3, $4, $5, $6, $7, $8) WHERE (idp_id = $9) AND (instance_id = $10)", expectedArgs: []interface{}{ "client-id", anyArg{}, @@ -380,7 +380,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idps3 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -390,7 +390,7 @@ func TestIDPProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idps2_jwt_config (idp_id, instance_id, endpoint, issuer, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idps3_jwt_config (idp_id, instance_id, endpoint, issuer, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", expectedArgs: []interface{}{ "idp-config-id", "instance-id", @@ -427,7 +427,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.idps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -436,7 +436,7 @@ func TestIDPProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idps2_jwt_config SET (endpoint, issuer, keys_endpoint, header_name) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.idps3_jwt_config SET (endpoint, issuer, keys_endpoint, header_name) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ "https://api.zitadel.ch/jwt", "issuer", @@ -492,7 +492,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.idps2 (id, creation_date, change_date, sequence, resource_owner, instance_id, state, name, styling_type, auto_register, owner_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", + expectedStmt: "INSERT INTO projections.idps3 (id, creation_date, change_date, sequence, resource_owner, instance_id, state, name, styling_type, auto_register, owner_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "idp-config-id", anyArg{}, @@ -533,7 +533,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (name, styling_type, auto_register, change_date, sequence) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.idps3 SET (name, styling_type, auto_register, change_date, sequence) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ "custom-zitadel-instance", domain.IDPConfigStylingTypeGoogle, @@ -567,7 +567,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idps3 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ domain.IDPConfigStateInactive, anyArg{}, @@ -599,7 +599,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idps3 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ domain.IDPConfigStateActive, anyArg{}, @@ -631,7 +631,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idps2 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.idps3 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "idp-config-id", "instance-id", @@ -672,7 +672,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idps3 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -682,7 +682,7 @@ func TestIDPProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idps2_oidc_config (idp_id, instance_id, client_id, client_secret, issuer, scopes, display_name_mapping, username_mapping, authorization_endpoint, token_endpoint) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.idps3_oidc_config (idp_id, instance_id, client_id, client_secret, issuer, scopes, display_name_mapping, username_mapping, authorization_endpoint, token_endpoint) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ "idp-config-id", "instance-id", @@ -731,7 +731,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.idps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -740,7 +740,7 @@ func TestIDPProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idps2_oidc_config SET (client_id, client_secret, issuer, authorization_endpoint, token_endpoint, scopes, display_name_mapping, username_mapping) = ($1, $2, $3, $4, $5, $6, $7, $8) WHERE (idp_id = $9) AND (instance_id = $10)", + expectedStmt: "UPDATE projections.idps3_oidc_config SET (client_id, client_secret, issuer, authorization_endpoint, token_endpoint, scopes, display_name_mapping, username_mapping) = ($1, $2, $3, $4, $5, $6, $7, $8) WHERE (idp_id = $9) AND (instance_id = $10)", expectedArgs: []interface{}{ "client-id", anyArg{}, @@ -800,7 +800,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.idps3 SET (change_date, sequence, type) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -810,7 +810,7 @@ func TestIDPProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.idps2_jwt_config (idp_id, instance_id, endpoint, issuer, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", + expectedStmt: "INSERT INTO projections.idps3_jwt_config (idp_id, instance_id, endpoint, issuer, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)", expectedArgs: []interface{}{ "idp-config-id", "instance-id", @@ -847,7 +847,7 @@ func TestIDPProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.idps2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.idps3 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -856,7 +856,7 @@ func TestIDPProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.idps2_jwt_config SET (endpoint, issuer, keys_endpoint, header_name) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.idps3_jwt_config SET (endpoint, issuer, keys_endpoint, header_name) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ "https://api.zitadel.ch/jwt", "issuer", @@ -889,6 +889,36 @@ func TestIDPProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&idpProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.idps3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/idp_user_link.go b/internal/query/projection/idp_user_link.go index f4ccfe266a..d4d3fb2284 100644 --- a/internal/query/projection/idp_user_link.go +++ b/internal/query/projection/idp_user_link.go @@ -13,7 +13,7 @@ import ( ) const ( - IDPUserLinkTable = "projections.idp_user_links2" + IDPUserLinkTable = "projections.idp_user_links3" IDPUserLinkIDPIDCol = "idp_id" IDPUserLinkUserIDCol = "user_id" IDPUserLinkExternalUserIDCol = "external_user_id" @@ -23,6 +23,7 @@ const ( IDPUserLinkResourceOwnerCol = "resource_owner" IDPUserLinkInstanceIDCol = "instance_id" IDPUserLinkDisplayNameCol = "display_name" + IDPUserLinkOwnerRemovedCol = "owner_removed" ) type idpUserLinkProjection struct { @@ -44,9 +45,11 @@ func newIDPUserLinkProjection(ctx context.Context, config crdb.StatementHandlerC crdb.NewColumn(IDPUserLinkResourceOwnerCol, crdb.ColumnTypeText), crdb.NewColumn(IDPUserLinkInstanceIDCol, crdb.ColumnTypeText), crdb.NewColumn(IDPUserLinkDisplayNameCol, crdb.ColumnTypeText), + crdb.NewColumn(IDPUserLinkOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(IDPUserLinkInstanceIDCol, IDPUserLinkIDPIDCol, IDPUserLinkExternalUserIDCol), - crdb.WithIndex(crdb.NewIndex("idp_user_idx", []string{IDPUserLinkUserIDCol})), + crdb.WithIndex(crdb.NewIndex("user_id", []string{IDPUserLinkUserIDCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{IDPUserLinkOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -85,7 +88,7 @@ func (p *idpUserLinkProjection) reducers() []handler.AggregateReducer { }, { Event: org.OrgRemovedEventType, - Reduce: p.reduceOrgRemoved, + Reduce: p.reduceOwnerRemoved, }, }, }, @@ -158,13 +161,19 @@ func (p *idpUserLinkProjection) reduceCascadeRemoved(event eventstore.Event) (*h ), nil } -func (p *idpUserLinkProjection) reduceOrgRemoved(event eventstore.Event) (*handler.Statement, error) { +func (p *idpUserLinkProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { e, ok := event.(*org.OrgRemovedEvent) if !ok { - return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-AZmfJ", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-PGiAY", "reduce.wrong.event.type %s", org.OrgRemovedEventType) } - return crdb.NewDeleteStatement(e, + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(IDPUserLinkChangeDateCol, e.CreationDate()), + handler.NewCol(IDPUserLinkSequenceCol, e.Sequence()), + handler.NewCol(IDPUserLinkOwnerRemovedCol, true), + }, []handler.Condition{ handler.NewCond(IDPUserLinkResourceOwnerCol, e.Aggregate().ID), handler.NewCond(IDPUserLinkInstanceIDCol, e.Aggregate().InstanceID), diff --git a/internal/query/projection/idp_user_link_test.go b/internal/query/projection/idp_user_link_test.go index 925352bb79..cc6548a980 100644 --- a/internal/query/projection/idp_user_link_test.go +++ b/internal/query/projection/idp_user_link_test.go @@ -43,7 +43,7 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.idp_user_links2 (idp_id, user_id, external_user_id, creation_date, change_date, sequence, resource_owner, instance_id, display_name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.idp_user_links3 (idp_id, user_id, external_user_id, creation_date, change_date, sequence, resource_owner, instance_id, display_name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "idp-config-id", "agg-id", @@ -80,7 +80,7 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_user_links2 WHERE (idp_id = $1) AND (user_id = $2) AND (external_user_id = $3) AND (instance_id = $4)", + expectedStmt: "DELETE FROM projections.idp_user_links3 WHERE (idp_id = $1) AND (user_id = $2) AND (external_user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "idp-config-id", "agg-id", @@ -112,7 +112,7 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_user_links2 WHERE (idp_id = $1) AND (user_id = $2) AND (external_user_id = $3) AND (instance_id = $4)", + expectedStmt: "DELETE FROM projections.idp_user_links3 WHERE (idp_id = $1) AND (user_id = $2) AND (external_user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "idp-config-id", "agg-id", @@ -125,7 +125,7 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) { }, }, { - name: "reduceOrgRemoved", + name: "reduceOwnerRemoved", args: args{ event: getEvent(testEvent( repository.EventType(org.OrgRemovedEventType), @@ -133,7 +133,7 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) { []byte(`{}`), ), org.OrgRemovedEventMapper), }, - reduce: (&idpUserLinkProjection{}).reduceOrgRemoved, + reduce: (&idpUserLinkProjection{}).reduceOwnerRemoved, want: wantReduce{ aggregateType: org.AggregateType, sequence: 15, @@ -141,8 +141,11 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_user_links2 WHERE (resource_owner = $1) AND (instance_id = $2)", + expectedStmt: "UPDATE projections.idp_user_links3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (resource_owner = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, "agg-id", "instance-id", }, @@ -168,7 +171,7 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_user_links2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.idp_user_links3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -194,7 +197,7 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_user_links2 WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.idp_user_links3 WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -223,7 +226,7 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_user_links2 WHERE (idp_id = $1) AND (resource_owner = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.idp_user_links3 WHERE (idp_id = $1) AND (resource_owner = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "idp-config-id", "ro-id", @@ -253,7 +256,7 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.idp_user_links2 WHERE (idp_id = $1) AND (resource_owner = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.idp_user_links3 WHERE (idp_id = $1) AND (resource_owner = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "idp-config-id", "ro-id", diff --git a/internal/query/projection/instance_member.go b/internal/query/projection/instance_member.go index d665768a4c..950327f2d2 100644 --- a/internal/query/projection/instance_member.go +++ b/internal/query/projection/instance_member.go @@ -8,11 +8,12 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/user" ) const ( - InstanceMemberProjectionTable = "projections.instance_members2" + InstanceMemberProjectionTable = "projections.instance_members3" InstanceMemberIAMIDCol = "id" ) @@ -29,7 +30,8 @@ func newInstanceMemberProjection(ctx context.Context, config crdb.StatementHandl crdb.NewTable( append(memberColumns, crdb.NewColumn(InstanceColumnID, crdb.ColumnTypeText)), crdb.NewPrimaryKey(MemberInstanceID, InstanceColumnID, MemberUserIDCol), - crdb.WithIndex(crdb.NewIndex("inst_memb_user_idx", []string{MemberUserIDCol})), + crdb.WithIndex(crdb.NewIndex("user_id", []string{MemberUserIDCol})), + crdb.WithIndex(crdb.NewIndex("user_owner_removed", []string{MemberUserOwnerRemoved})), ), ) @@ -64,6 +66,15 @@ func (p *instanceMemberProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceUserOwnerRemoved, + }, + }, + }, { Aggregate: user.AggregateType, EventRedusers: []handler.EventReducer{ @@ -81,7 +92,12 @@ func (p *instanceMemberProjection) reduceAdded(event eventstore.Event) (*handler if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-pGNCu", "reduce.wrong.event.type %s", instance.MemberAddedEventType) } - return reduceMemberAdded(e.MemberAddedEvent, withMemberCol(InstanceMemberIAMIDCol, e.Aggregate().ID)) + ctx := setMemberContext(e.Aggregate()) + userOwner, err := getResourceOwnerOfUser(ctx, p.Eventstore, e.Aggregate().InstanceID, e.UserID) + if err != nil { + return nil, err + } + return reduceMemberAdded(e.MemberAddedEvent, userOwner, withMemberCol(InstanceMemberIAMIDCol, e.Aggregate().ID)) } func (p *instanceMemberProjection) reduceChanged(event eventstore.Event) (*handler.Statement, error) { @@ -115,3 +131,11 @@ func (p *instanceMemberProjection) reduceUserRemoved(event eventstore.Event) (*h } return reduceMemberRemoved(e, withMemberCond(MemberUserIDCol, e.Aggregate().ID)) } + +func (p *instanceMemberProjection) reduceUserOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-mkDHa", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + return reduceMemberUserOwnerRemoved(e) +} diff --git a/internal/query/projection/instance_member_test.go b/internal/query/projection/instance_member_test.go index d8cf81c760..5f56c64fe2 100644 --- a/internal/query/projection/instance_member_test.go +++ b/internal/query/projection/instance_member_test.go @@ -1,14 +1,19 @@ package projection import ( + "context" "testing" + "golang.org/x/text/language" + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "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" "github.com/zitadel/zitadel/internal/repository/user" ) @@ -34,7 +39,21 @@ func TestInstanceMemberProjection_reduces(t *testing.T) { }`), ), instance.MemberAddedEventMapper), }, - reduce: (&instanceMemberProjection{}).reduceAdded, + reduce: (&instanceMemberProjection{ + StatementHandler: getStatementHandlerWithFilters( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user-id", "org1").Aggregate, + "username1", + "firstname1", + "lastname1", + "nickname1", + "displayname1", + language.German, + domain.GenderMale, + "email1", + true, + ), + )(t)}).reduceAdded, want: wantReduce{ aggregateType: instance.AggregateType, sequence: 15, @@ -42,15 +61,18 @@ func TestInstanceMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.instance_members2 (user_id, roles, creation_date, change_date, sequence, resource_owner, instance_id, id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.instance_members3 (user_id, user_resource_owner, user_owner_removed, roles, creation_date, change_date, sequence, resource_owner, instance_id, owner_removed, id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "user-id", + "org1", + false, database.StringArray{"role"}, anyArg{}, anyArg{}, uint64(15), "ro-id", "instance-id", + false, "agg-id", }, }, @@ -78,7 +100,7 @@ func TestInstanceMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.instance_members2 SET (roles, change_date, sequence) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_id = $5)", + expectedStmt: "UPDATE projections.instance_members3 SET (roles, change_date, sequence) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_id = $5)", expectedArgs: []interface{}{ database.StringArray{"role", "changed"}, anyArg{}, @@ -110,7 +132,7 @@ func TestInstanceMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.instance_members2 WHERE (instance_id = $1) AND (user_id = $2)", + expectedStmt: "DELETE FROM projections.instance_members3 WHERE (instance_id = $1) AND (user_id = $2)", expectedArgs: []interface{}{ "instance-id", "user-id", @@ -139,7 +161,7 @@ func TestInstanceMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.instance_members2 WHERE (instance_id = $1) AND (user_id = $2)", + expectedStmt: "DELETE FROM projections.instance_members3 WHERE (instance_id = $1) AND (user_id = $2)", expectedArgs: []interface{}{ "instance-id", "user-id", @@ -166,7 +188,7 @@ func TestInstanceMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.instance_members2 WHERE (instance_id = $1) AND (user_id = $2)", + expectedStmt: "DELETE FROM projections.instance_members3 WHERE (instance_id = $1) AND (user_id = $2)", expectedArgs: []interface{}{ "instance-id", "agg-id", @@ -176,6 +198,36 @@ func TestInstanceMemberProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.OrgRemoved", + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + reduce: (&instanceMemberProjection{}).reduceUserOwnerRemoved, + want: wantReduce{ + aggregateType: org.AggregateType, + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.instance_members3 SET (change_date, sequence, user_owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, { name: "instance reduceInstanceRemoved", args: args{ @@ -193,7 +245,7 @@ func TestInstanceMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.instance_members2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.instance_members3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/key.go b/internal/query/projection/key.go index d2b2fab304..fabc768121 100644 --- a/internal/query/projection/key.go +++ b/internal/query/projection/key.go @@ -14,7 +14,7 @@ import ( ) const ( - KeyProjectionTable = "projections.keys3" + KeyProjectionTable = "projections.keys4" KeyPrivateTable = KeyProjectionTable + "_" + privateKeyTableSuffix KeyPublicTable = KeyProjectionTable + "_" + publicKeyTableSuffix CertificateTable = KeyProjectionTable + "_" + certificateTableSuffix @@ -69,7 +69,6 @@ func newKeyProjection(ctx context.Context, config crdb.StatementHandlerConfig, k crdb.NewColumn(KeyColumnUse, crdb.ColumnTypeEnum, crdb.Default(0)), }, crdb.NewPrimaryKey(KeyColumnInstanceID, KeyColumnID), - crdb.WithConstraint(crdb.NewConstraint("key3_id_unique", []string{KeyColumnID})), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(KeyPrivateColumnID, crdb.ColumnTypeText), @@ -79,7 +78,7 @@ func newKeyProjection(ctx context.Context, config crdb.StatementHandlerConfig, k }, crdb.NewPrimaryKey(KeyPrivateColumnInstanceID, KeyPrivateColumnID), privateKeyTableSuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_private_ref_keys3")), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(KeyPublicColumnID, crdb.ColumnTypeText), @@ -89,7 +88,7 @@ func newKeyProjection(ctx context.Context, config crdb.StatementHandlerConfig, k }, crdb.NewPrimaryKey(KeyPublicColumnInstanceID, KeyPublicColumnID), publicKeyTableSuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_public_ref_keys3")), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(CertificateColumnID, crdb.ColumnTypeText), @@ -99,7 +98,7 @@ func newKeyProjection(ctx context.Context, config crdb.StatementHandlerConfig, k }, crdb.NewPrimaryKey(CertificateColumnInstanceID, CertificateColumnID), certificateTableSuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_certificate_ref_keys3")), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), ), ) p.encryptionAlgorithm = keyEncryptionAlgorithm diff --git a/internal/query/projection/key_test.go b/internal/query/projection/key_test.go index 54b1539027..2c93e38594 100644 --- a/internal/query/projection/key_test.go +++ b/internal/query/projection/key_test.go @@ -44,7 +44,7 @@ func TestKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.keys3 (id, creation_date, change_date, resource_owner, instance_id, sequence, algorithm, use) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.keys4 (id, creation_date, change_date, resource_owner, instance_id, sequence, algorithm, use) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "agg-id", anyArg{}, @@ -57,7 +57,7 @@ func TestKeyProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.keys3_private (id, instance_id, expiry, key) VALUES ($1, $2, $3, $4)", + expectedStmt: "INSERT INTO projections.keys4_private (id, instance_id, expiry, key) VALUES ($1, $2, $3, $4)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -71,7 +71,7 @@ func TestKeyProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.keys3_public (id, instance_id, expiry, key) VALUES ($1, $2, $3, $4)", + expectedStmt: "INSERT INTO projections.keys4_public (id, instance_id, expiry, key) VALUES ($1, $2, $3, $4)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -117,7 +117,7 @@ func TestKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.keys3 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.keys4 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -143,7 +143,7 @@ func TestKeyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.keys3_certificate (id, instance_id, expiry, certificate) VALUES ($1, $2, $3, $4)", + expectedStmt: "INSERT INTO projections.keys4_certificate (id, instance_id, expiry, certificate) VALUES ($1, $2, $3, $4)", expectedArgs: []interface{}{ "agg-id", "instance-id", diff --git a/internal/query/projection/label_policy.go b/internal/query/projection/label_policy.go index f4203d1cd5..b8a84d9221 100644 --- a/internal/query/projection/label_policy.go +++ b/internal/query/projection/label_policy.go @@ -14,7 +14,7 @@ import ( ) const ( - LabelPolicyTable = "projections.label_policies" + LabelPolicyTable = "projections.label_policies2" LabelPolicyIDCol = "id" LabelPolicyCreationDateCol = "creation_date" @@ -28,6 +28,7 @@ const ( LabelPolicyWatermarkDisabledCol = "watermark_disabled" LabelPolicyShouldErrorPopupCol = "should_error_popup" LabelPolicyFontURLCol = "font_url" + LabelPolicyOwnerRemovedCol = "owner_removed" LabelPolicyLightPrimaryColorCol = "light_primary_color" LabelPolicyLightWarnColorCol = "light_warn_color" @@ -78,8 +79,10 @@ func newLabelPolicyProjection(ctx context.Context, config crdb.StatementHandlerC crdb.NewColumn(LabelPolicyDarkFontColorCol, crdb.ColumnTypeText, crdb.Nullable()), crdb.NewColumn(LabelPolicyDarkLogoURLCol, crdb.ColumnTypeText, crdb.Nullable()), crdb.NewColumn(LabelPolicyDarkIconURLCol, crdb.ColumnTypeText, crdb.Nullable()), + crdb.NewColumn(LabelPolicyOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(LabelPolicyInstanceIDCol, LabelPolicyIDCol, LabelPolicyStateCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{LabelPolicyOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -151,6 +154,10 @@ func (p *labelPolicyProjection) reducers() []handler.AggregateReducer { Event: org.LabelPolicyAssetsRemovedEventType, Reduce: p.reduceAssetsRemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -593,3 +600,23 @@ func (p *labelPolicyProjection) reduceAssetsRemoved(event eventstore.Event) (*ha handler.NewCond(LabelPolicyInstanceIDCol, event.Aggregate().InstanceID), }), nil } + +func (p *labelPolicyProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-Su6pX", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(LabelPolicyChangeDateCol, e.CreationDate()), + handler.NewCol(LabelPolicySequenceCol, e.Sequence()), + handler.NewCol(LabelPolicyOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(LabelPolicyInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(LabelPolicyResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/label_policy_test.go b/internal/query/projection/label_policy_test.go index ae638fb697..f7190f6d52 100644 --- a/internal/query/projection/label_policy_test.go +++ b/internal/query/projection/label_policy_test.go @@ -39,7 +39,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.label_policies (creation_date, change_date, sequence, id, state, is_default, resource_owner, instance_id, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)", + expectedStmt: "INSERT INTO projections.label_policies2 (creation_date, change_date, sequence, id, state, is_default, resource_owner, instance_id, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -83,7 +83,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_primary_color, light_background_color, light_warn_color, light_font_color) = ($1, $2, $3, $4, $5, $6) WHERE (id = $7) AND (state = $8) AND (instance_id = $9)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_primary_color, light_background_color, light_warn_color, light_font_color) = ($1, $2, $3, $4, $5, $6) WHERE (id = $7) AND (state = $8) AND (instance_id = $9)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -117,7 +117,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.label_policies WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.label_policies2 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -144,7 +144,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.label_policies WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.label_policies2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -170,7 +170,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.label_policies (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url FROM projections.label_policies AS copy_table WHERE copy_table.id = $4 AND copy_table.state = $5 AND copy_table.instance_id = $6 ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url)", + expectedStmt: "INSERT INTO projections.label_policies2 (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url FROM projections.label_policies2 AS copy_table WHERE copy_table.id = $4 AND copy_table.state = $5 AND copy_table.instance_id = $6 ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -201,7 +201,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -232,7 +232,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -263,7 +263,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -294,7 +294,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -325,7 +325,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -356,7 +356,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -387,7 +387,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -418,7 +418,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -449,7 +449,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -480,7 +480,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -511,7 +511,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_logo_url, light_icon_url, dark_logo_url, dark_icon_url, font_url) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (state = $9) AND (instance_id = $10)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url, light_icon_url, dark_logo_url, dark_icon_url, font_url) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (state = $9) AND (instance_id = $10)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -546,7 +546,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.label_policies (creation_date, change_date, sequence, id, state, is_default, resource_owner, instance_id, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)", + expectedStmt: "INSERT INTO projections.label_policies2 (creation_date, change_date, sequence, id, state, is_default, resource_owner, instance_id, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -590,7 +590,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) WHERE (id = $14) AND (state = $15) AND (instance_id = $16)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_primary_color, light_background_color, light_warn_color, light_font_color, dark_primary_color, dark_background_color, dark_warn_color, dark_font_color, hide_login_name_suffix, should_error_popup, watermark_disabled) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) WHERE (id = $14) AND (state = $15) AND (instance_id = $16)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -631,7 +631,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.label_policies (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url FROM projections.label_policies AS copy_table WHERE copy_table.id = $4 AND copy_table.state = $5 AND copy_table.instance_id = $6 ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url)", + expectedStmt: "INSERT INTO projections.label_policies2 (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) SELECT $1, $2, $3, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url FROM projections.label_policies2 AS copy_table WHERE copy_table.id = $4 AND copy_table.state = $5 AND copy_table.instance_id = $6 ON CONFLICT (instance_id, id, state) DO UPDATE SET (change_date, sequence, state, creation_date, resource_owner, instance_id, id, is_default, hide_login_name_suffix, font_url, watermark_disabled, should_error_popup, light_primary_color, light_warn_color, light_background_color, light_font_color, light_logo_url, light_icon_url, dark_primary_color, dark_warn_color, dark_background_color, dark_font_color, dark_logo_url, dark_icon_url) = ($1, $2, $3, EXCLUDED.creation_date, EXCLUDED.resource_owner, EXCLUDED.instance_id, EXCLUDED.id, EXCLUDED.is_default, EXCLUDED.hide_login_name_suffix, EXCLUDED.font_url, EXCLUDED.watermark_disabled, EXCLUDED.should_error_popup, EXCLUDED.light_primary_color, EXCLUDED.light_warn_color, EXCLUDED.light_background_color, EXCLUDED.light_font_color, EXCLUDED.light_logo_url, EXCLUDED.light_icon_url, EXCLUDED.dark_primary_color, EXCLUDED.dark_warn_color, EXCLUDED.dark_background_color, EXCLUDED.dark_font_color, EXCLUDED.dark_logo_url, EXCLUDED.dark_icon_url)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -662,7 +662,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -693,7 +693,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -724,7 +724,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -755,7 +755,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -786,7 +786,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -817,7 +817,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_logo_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -848,7 +848,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -879,7 +879,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, dark_icon_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -910,7 +910,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -941,7 +941,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, font_url) = ($1, $2, $3) WHERE (id = $4) AND (state = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -972,7 +972,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.label_policies SET (change_date, sequence, light_logo_url, light_icon_url, dark_logo_url, dark_icon_url, font_url) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (state = $9) AND (instance_id = $10)", + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, light_logo_url, light_icon_url, dark_logo_url, dark_icon_url, font_url) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (state = $9) AND (instance_id = $10)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -990,6 +990,36 @@ func TestLabelPolicyProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&labelPolicyProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.label_policies2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/lockout_policy.go b/internal/query/projection/lockout_policy.go index 62ef6eba94..025213381f 100644 --- a/internal/query/projection/lockout_policy.go +++ b/internal/query/projection/lockout_policy.go @@ -14,7 +14,7 @@ import ( ) const ( - LockoutPolicyTable = "projections.lockout_policies" + LockoutPolicyTable = "projections.lockout_policies2" LockoutPolicyIDCol = "id" LockoutPolicyCreationDateCol = "creation_date" @@ -26,6 +26,7 @@ const ( LockoutPolicyInstanceIDCol = "instance_id" LockoutPolicyMaxPasswordAttemptsCol = "max_password_attempts" LockoutPolicyShowLockOutFailuresCol = "show_failure" + LockoutPolicyOwnerRemovedCol = "owner_removed" ) type lockoutPolicyProjection struct { @@ -48,8 +49,10 @@ func newLockoutPolicyProjection(ctx context.Context, config crdb.StatementHandle crdb.NewColumn(LockoutPolicyInstanceIDCol, crdb.ColumnTypeText), crdb.NewColumn(LockoutPolicyMaxPasswordAttemptsCol, crdb.ColumnTypeInt64), crdb.NewColumn(LockoutPolicyShowLockOutFailuresCol, crdb.ColumnTypeBool), + crdb.NewColumn(LockoutPolicyOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(LockoutPolicyInstanceIDCol, LockoutPolicyIDCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{LockoutPolicyOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -73,6 +76,10 @@ func (p *lockoutPolicyProjection) reducers() []handler.AggregateReducer { Event: org.LockoutPolicyRemovedEventType, Reduce: p.reduceRemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -165,3 +172,23 @@ func (p *lockoutPolicyProjection) reduceRemoved(event eventstore.Event) (*handle handler.NewCond(LabelPolicyInstanceIDCol, event.Aggregate().InstanceID), }), nil } + +func (p *lockoutPolicyProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-IoW0x", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(LockoutPolicyChangeDateCol, e.CreationDate()), + handler.NewCol(LockoutPolicySequenceCol, e.Sequence()), + handler.NewCol(LockoutPolicyOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(LockoutPolicyInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(LockoutPolicyResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/lockout_policy_test.go b/internal/query/projection/lockout_policy_test.go index 0fe107cda4..1b853dfc6b 100644 --- a/internal/query/projection/lockout_policy_test.go +++ b/internal/query/projection/lockout_policy_test.go @@ -42,7 +42,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.lockout_policies (creation_date, change_date, sequence, id, state, max_password_attempts, show_failure, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.lockout_policies2 (creation_date, change_date, sequence, id, state, max_password_attempts, show_failure, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -80,7 +80,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.lockout_policies SET (change_date, sequence, max_password_attempts, show_failure) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.lockout_policies2 SET (change_date, sequence, max_password_attempts, show_failure) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -111,7 +111,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.lockout_policies WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.lockout_policies2 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -138,7 +138,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.lockout_policies WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.lockout_policies2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -167,7 +167,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.lockout_policies (creation_date, change_date, sequence, id, state, max_password_attempts, show_failure, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.lockout_policies2 (creation_date, change_date, sequence, id, state, max_password_attempts, show_failure, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -205,7 +205,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.lockout_policies SET (change_date, sequence, max_password_attempts, show_failure) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.lockout_policies2 SET (change_date, sequence, max_password_attempts, show_failure) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -219,6 +219,36 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&lockoutPolicyProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.lockout_policies2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/login_name.go b/internal/query/projection/login_name.go index 5d121fd9d9..12aaeb2af8 100644 --- a/internal/query/projection/login_name.go +++ b/internal/query/projection/login_name.go @@ -2,7 +2,9 @@ package projection import ( "context" - "fmt" + "strings" + + sq "github.com/Masterminds/squirrel" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" @@ -15,76 +17,160 @@ import ( ) const ( - LoginNameProjectionTable = "projections.login_names" + LoginNameTableAlias = "login_names2" + LoginNameProjectionTable = "projections." + LoginNameTableAlias LoginNameUserProjectionTable = LoginNameProjectionTable + "_" + loginNameUserSuffix LoginNamePolicyProjectionTable = LoginNameProjectionTable + "_" + loginNamePolicySuffix LoginNameDomainProjectionTable = LoginNameProjectionTable + "_" + loginNameDomainSuffix - LoginNameCol = "login_name" + LoginNameCol = "login_name" + LoginNameUserCol = "user_id" + LoginNameIsPrimaryCol = "is_primary" + LoginNameInstanceIDCol = "instance_id" + LoginNameOwnerRemovedUserCol = "user_owner_removed" + LoginNameOwnerRemovedPolicyCol = "policy_owner_removed" + LoginNameOwnerRemovedDomainCol = "domain_owner_removed" + + usersAlias = "users" + policyCustomAlias = "policy_custom" + policyDefaultAlias = "policy_default" + policyUsersAlias = "policy_users" + domainsAlias = "domains" + domainAlias = "domain" loginNameUserSuffix = "users" LoginNameUserIDCol = "id" LoginNameUserUserNameCol = "user_name" LoginNameUserResourceOwnerCol = "resource_owner" LoginNameUserInstanceIDCol = "instance_id" + LoginNameUserOwnerRemovedCol = "owner_removed" loginNameDomainSuffix = "domains" LoginNameDomainNameCol = "name" LoginNameDomainIsPrimaryCol = "is_primary" LoginNameDomainResourceOwnerCol = "resource_owner" LoginNameDomainInstanceIDCol = "instance_id" + LoginNameDomainOwnerRemovedCol = "owner_removed" loginNamePolicySuffix = "policies" LoginNamePoliciesMustBeDomainCol = "must_be_domain" LoginNamePoliciesIsDefaultCol = "is_default" LoginNamePoliciesResourceOwnerCol = "resource_owner" LoginNamePoliciesInstanceIDCol = "instance_id" + LoginNamePoliciesOwnerRemovedCol = "owner_removed" ) var ( - viewStmt = fmt.Sprintf("SELECT"+ - " user_id"+ - " , (CASE WHEN %[1]s THEN CONCAT(%[2]s, '@', domain) ELSE %[2]s END) AS login_name"+ - " , COALESCE(%[3]s, true) AS %[3]s"+ - " , %[4]s"+ - " FROM ("+ - " SELECT"+ - " policy_users.user_id"+ - " , policy_users.%[2]s"+ - " , policy_users.%[5]s"+ - " , policy_users.%[4]s"+ - " , policy_users.%[1]s"+ - " , domains.%[6]s AS domain"+ - " , domains.%[3]s"+ - " FROM ("+ - " SELECT"+ - " users.id as user_id"+ - " , users.%[2]s"+ - " , users.%[4]s"+ - " , users.%[5]s"+ - " , COALESCE(policy_custom.%[1]s, policy_default.%[1]s) AS %[1]s"+ - " FROM %[7]s users"+ - " LEFT JOIN %[8]s policy_custom on policy_custom.%[9]s = users.%[5]s AND policy_custom.%[10]s = users.%[4]s"+ - " LEFT JOIN %[8]s policy_default on policy_default.%[11]s = true AND policy_default.%[10]s = users.%[4]s) policy_users"+ - " LEFT JOIN %[12]s domains ON policy_users.%[1]s AND policy_users.%[5]s = domains.%[13]s AND policy_users.%[10]s = domains.%[14]s"+ - ") AS login_names;", - LoginNamePoliciesMustBeDomainCol, - LoginNameUserUserNameCol, - LoginNameDomainIsPrimaryCol, - LoginNameUserInstanceIDCol, - LoginNameUserResourceOwnerCol, - LoginNameDomainNameCol, - LoginNameUserProjectionTable, - LoginNamePolicyProjectionTable, - LoginNamePoliciesResourceOwnerCol, - LoginNamePoliciesInstanceIDCol, - LoginNamePoliciesIsDefaultCol, - LoginNameDomainProjectionTable, - LoginNameDomainResourceOwnerCol, - LoginNameDomainInstanceIDCol, - ) + policyUsers = sq.Select( + alias( + col(usersAlias, LoginNameUserIDCol), + LoginNameUserCol, + ), + col(usersAlias, LoginNameUserUserNameCol), + col(usersAlias, LoginNameUserInstanceIDCol), + col(usersAlias, LoginNameUserResourceOwnerCol), + alias( + coalesce(col(policyCustomAlias, LoginNamePoliciesMustBeDomainCol), col(policyDefaultAlias, LoginNamePoliciesMustBeDomainCol)), + LoginNamePoliciesMustBeDomainCol, + ), + alias(col(usersAlias, LoginNameUserOwnerRemovedCol), + LoginNameOwnerRemovedUserCol), + alias(coalesce(col(policyCustomAlias, LoginNamePoliciesOwnerRemovedCol), "false"), + LoginNameOwnerRemovedPolicyCol), + ).From(alias(LoginNameUserProjectionTable, usersAlias)). + LeftJoin( + leftJoin(LoginNamePolicyProjectionTable, policyCustomAlias, + eq(col(policyCustomAlias, LoginNamePoliciesResourceOwnerCol), col(usersAlias, LoginNameUserResourceOwnerCol)), + eq(col(policyCustomAlias, LoginNamePoliciesInstanceIDCol), col(usersAlias, LoginNameUserInstanceIDCol)), + ), + ). + LeftJoin( + leftJoin(LoginNamePolicyProjectionTable, policyDefaultAlias, + eq(col(policyDefaultAlias, LoginNamePoliciesIsDefaultCol), "true"), + eq(col(policyDefaultAlias, LoginNamePoliciesInstanceIDCol), col(usersAlias, LoginNameUserInstanceIDCol)), + ), + ) + + loginNamesTable = sq.Select( + col(policyUsersAlias, LoginNameUserCol), + col(policyUsersAlias, LoginNameUserUserNameCol), + col(policyUsersAlias, LoginNameUserResourceOwnerCol), + alias(col(policyUsersAlias, LoginNameUserInstanceIDCol), + LoginNameInstanceIDCol), + col(policyUsersAlias, LoginNamePoliciesMustBeDomainCol), + alias(col(domainsAlias, LoginNameDomainNameCol), + domainAlias), + col(domainsAlias, LoginNameDomainIsPrimaryCol), + col(policyUsersAlias, LoginNameOwnerRemovedUserCol), + col(policyUsersAlias, LoginNameOwnerRemovedPolicyCol), + alias(coalesce(col(domainsAlias, LoginNameDomainOwnerRemovedCol), "false"), + LoginNameOwnerRemovedDomainCol), + ).FromSelect(policyUsers, policyUsersAlias). + LeftJoin( + leftJoin(LoginNameDomainProjectionTable, domainsAlias, + col(policyUsersAlias, LoginNamePoliciesMustBeDomainCol), + eq(col(policyUsersAlias, LoginNameUserResourceOwnerCol), col(domainsAlias, LoginNameDomainResourceOwnerCol)), + eq(col(policyUsersAlias, LoginNamePoliciesInstanceIDCol), col(domainsAlias, LoginNameDomainInstanceIDCol)), + ), + ) + + viewStmt, _ = sq.Select( + LoginNameUserCol, + alias( + whenThenElse( + LoginNamePoliciesMustBeDomainCol, + concat(LoginNameUserUserNameCol, "'@'", domainAlias), + LoginNameUserUserNameCol), + LoginNameCol), + alias(coalesce(LoginNameDomainIsPrimaryCol, "true"), + LoginNameIsPrimaryCol), + LoginNameInstanceIDCol, + LoginNameOwnerRemovedUserCol, + LoginNameOwnerRemovedPolicyCol, + LoginNameOwnerRemovedDomainCol, + ).FromSelect(loginNamesTable, LoginNameTableAlias).MustSql() ) +func col(table, name string) string { + return table + "." + name +} + +func alias(col, alias string) string { + return col + " AS " + alias +} + +func coalesce(values ...string) string { + str := "COALESCE(" + for i, value := range values { + if i > 0 { + str += ", " + } + str += value + } + str += ")" + return str +} + +func eq(first, second string) string { + return first + " = " + second +} + +func leftJoin(table, alias, on string, and ...string) string { + st := table + " " + alias + " ON " + on + for _, a := range and { + st += " AND " + a + } + return st +} + +func concat(strs ...string) string { + return "CONCAT(" + strings.Join(strs, ", ") + ")" +} + +func whenThenElse(when, then, el string) string { + return "(CASE WHEN " + when + " THEN " + then + " ELSE " + el + " END)" +} + type loginNameProjection struct { crdb.StatementHandler } @@ -100,29 +186,35 @@ func newLoginNameProjection(ctx context.Context, config crdb.StatementHandlerCon crdb.NewColumn(LoginNameUserUserNameCol, crdb.ColumnTypeText), crdb.NewColumn(LoginNameUserResourceOwnerCol, crdb.ColumnTypeText), crdb.NewColumn(LoginNameUserInstanceIDCol, crdb.ColumnTypeText), + crdb.NewColumn(LoginNameUserOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(LoginNameUserInstanceIDCol, LoginNameUserIDCol), loginNameUserSuffix, - crdb.WithIndex(crdb.NewIndex("ro_idx", []string{LoginNameUserResourceOwnerCol})), + crdb.WithIndex(crdb.NewIndex("resource_owner", []string{LoginNameUserResourceOwnerCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{LoginNameUserOwnerRemovedCol})), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(LoginNameDomainNameCol, crdb.ColumnTypeText), crdb.NewColumn(LoginNameDomainIsPrimaryCol, crdb.ColumnTypeBool, crdb.Default(false)), crdb.NewColumn(LoginNameDomainResourceOwnerCol, crdb.ColumnTypeText), crdb.NewColumn(LoginNameDomainInstanceIDCol, crdb.ColumnTypeText), + crdb.NewColumn(LoginNameDomainOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(LoginNameDomainInstanceIDCol, LoginNameDomainResourceOwnerCol, LoginNameDomainNameCol), loginNameDomainSuffix, + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{LoginNameDomainOwnerRemovedCol})), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(LoginNamePoliciesMustBeDomainCol, crdb.ColumnTypeBool), crdb.NewColumn(LoginNamePoliciesIsDefaultCol, crdb.ColumnTypeBool), crdb.NewColumn(LoginNamePoliciesResourceOwnerCol, crdb.ColumnTypeText), crdb.NewColumn(LoginNamePoliciesInstanceIDCol, crdb.ColumnTypeText), + crdb.NewColumn(LoginNamePoliciesOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(LoginNamePoliciesInstanceIDCol, LoginNamePoliciesResourceOwnerCol), loginNamePolicySuffix, - crdb.WithIndex(crdb.NewIndex("is_default_idx", []string{LoginNamePoliciesResourceOwnerCol, LoginNamePoliciesIsDefaultCol})), + crdb.WithIndex(crdb.NewIndex("is_default", []string{LoginNamePoliciesResourceOwnerCol, LoginNamePoliciesIsDefaultCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{LoginNamePoliciesOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -198,6 +290,10 @@ func (p *loginNameProjection) reducers() []handler.AggregateReducer { Event: org.OrgDomainVerifiedEventType, Reduce: p.reduceDomainVerified, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -469,3 +565,44 @@ func (p *loginNameProjection) reduceInstanceRemoved(event eventstore.Event) (*ha ), ), nil } + +func (p *loginNameProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-px02mo", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewMultiStatement( + event, + crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(LoginNameDomainOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(LoginNameDomainInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(LoginNameDomainResourceOwnerCol, e.Aggregate().ID), + }, + crdb.WithTableSuffix(loginNameDomainSuffix), + ), + crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(LoginNamePoliciesOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(LoginNamePoliciesInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(LoginNamePoliciesResourceOwnerCol, e.Aggregate().ID), + }, + crdb.WithTableSuffix(loginNamePolicySuffix), + ), + crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(LoginNameUserOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(LoginNameUserInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(LoginNameUserResourceOwnerCol, 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 b213e89352..3364fcb1d7 100644 --- a/internal/query/projection/login_name_test.go +++ b/internal/query/projection/login_name_test.go @@ -41,7 +41,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.login_names_users (id, user_name, resource_owner, instance_id) VALUES ($1, $2, $3, $4)", + expectedStmt: "INSERT INTO projections.login_names2_users (id, user_name, resource_owner, instance_id) VALUES ($1, $2, $3, $4)", expectedArgs: []interface{}{ "agg-id", "human-added", @@ -72,7 +72,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.login_names_users (id, user_name, resource_owner, instance_id) VALUES ($1, $2, $3, $4)", + expectedStmt: "INSERT INTO projections.login_names2_users (id, user_name, resource_owner, instance_id) VALUES ($1, $2, $3, $4)", expectedArgs: []interface{}{ "agg-id", "human-registered", @@ -103,7 +103,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.login_names_users (id, user_name, resource_owner, instance_id) VALUES ($1, $2, $3, $4)", + expectedStmt: "INSERT INTO projections.login_names2_users (id, user_name, resource_owner, instance_id) VALUES ($1, $2, $3, $4)", expectedArgs: []interface{}{ "agg-id", "machine-added", @@ -132,7 +132,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.login_names_users WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.login_names2_users WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -161,7 +161,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_names_users SET user_name = $1 WHERE (id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.login_names2_users SET user_name = $1 WHERE (id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "changed", "agg-id", @@ -191,7 +191,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_names_users SET user_name = $1 WHERE (id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.login_names2_users SET user_name = $1 WHERE (id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "claimed", "agg-id", @@ -221,7 +221,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.login_names_policies (must_be_domain, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4)", + expectedStmt: "INSERT INTO projections.login_names2_policies (must_be_domain, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4)", expectedArgs: []interface{}{ true, false, @@ -252,7 +252,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_names_policies SET must_be_domain = $1 WHERE (resource_owner = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.login_names2_policies SET must_be_domain = $1 WHERE (resource_owner = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ false, "ro-id", @@ -299,7 +299,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.login_names_policies WHERE (resource_owner = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.login_names2_policies WHERE (resource_owner = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "ro-id", "instance-id", @@ -328,7 +328,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.login_names_domains (name, resource_owner, instance_id) VALUES ($1, $2, $3)", + expectedStmt: "INSERT INTO projections.login_names2_domains (name, resource_owner, instance_id) VALUES ($1, $2, $3)", expectedArgs: []interface{}{ "verified", "ro-id", @@ -358,7 +358,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.login_names_domains WHERE (name = $1) AND (resource_owner = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.login_names2_domains WHERE (name = $1) AND (resource_owner = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "remove", "ro-id", @@ -388,7 +388,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_names_domains SET is_primary = $1 WHERE (resource_owner = $2) AND (is_primary = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.login_names2_domains SET is_primary = $1 WHERE (resource_owner = $2) AND (is_primary = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ false, "ro-id", @@ -397,7 +397,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.login_names_domains SET is_primary = $1 WHERE (name = $2) AND (resource_owner = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.login_names2_domains SET is_primary = $1 WHERE (name = $2) AND (resource_owner = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ true, "primary", @@ -428,7 +428,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.login_names_policies (must_be_domain, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4)", + expectedStmt: "INSERT INTO projections.login_names2_policies (must_be_domain, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4)", expectedArgs: []interface{}{ true, true, @@ -459,7 +459,7 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_names_policies SET must_be_domain = $1 WHERE (resource_owner = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.login_names2_policies SET must_be_domain = $1 WHERE (resource_owner = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ false, "ro-id", @@ -506,19 +506,19 @@ func TestLoginNameProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.login_names_domains WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.login_names2_domains WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, }, { - expectedStmt: "DELETE FROM projections.login_names_policies WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.login_names2_policies WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, }, { - expectedStmt: "DELETE FROM projections.login_names_users WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.login_names2_users WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -527,6 +527,50 @@ func TestLoginNameProjection_reduces(t *testing.T) { }, }, }, + { + name: "instance.reduceOwnerRemoved", + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + []byte(`{"name": "Name"}`), + ), org.OrgRemovedEventMapper), + }, + reduce: (&loginNameProjection{}).reduceOwnerRemoved, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.login_names2_domains SET owner_removed = $1 WHERE (instance_id = $2) AND (resource_owner = $3)", + expectedArgs: []interface{}{ + true, + "instance-id", + "agg-id", + }, + }, + { + expectedStmt: "UPDATE projections.login_names2_policies SET owner_removed = $1 WHERE (instance_id = $2) AND (resource_owner = $3)", + expectedArgs: []interface{}{ + true, + "instance-id", + "agg-id", + }, + }, + { + expectedStmt: "UPDATE projections.login_names2_users SET owner_removed = $1 WHERE (instance_id = $2) AND (resource_owner = $3)", + expectedArgs: []interface{}{ + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/login_policy.go b/internal/query/projection/login_policy.go index 114f8f142f..601a4531b3 100644 --- a/internal/query/projection/login_policy.go +++ b/internal/query/projection/login_policy.go @@ -13,7 +13,7 @@ import ( ) const ( - LoginPolicyTable = "projections.login_policies3" + LoginPolicyTable = "projections.login_policies4" LoginPolicyIDCol = "aggregate_id" LoginPolicyInstanceIDCol = "instance_id" @@ -39,6 +39,7 @@ const ( MFAInitSkipLifetimeCol = "mfa_init_skip_lifetime" SecondFactorCheckLifetimeCol = "second_factor_check_lifetime" MultiFactorCheckLifetimeCol = "multi_factor_check_lifetime" + LoginPolicyOwnerRemovedCol = "owner_removed" ) type loginPolicyProjection struct { @@ -75,8 +76,10 @@ func newLoginPolicyProjection(ctx context.Context, config crdb.StatementHandlerC crdb.NewColumn(MFAInitSkipLifetimeCol, crdb.ColumnTypeInt64), crdb.NewColumn(SecondFactorCheckLifetimeCol, crdb.ColumnTypeInt64), crdb.NewColumn(MultiFactorCheckLifetimeCol, crdb.ColumnTypeInt64), + crdb.NewColumn(LoginPolicyOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(LoginPolicyInstanceIDCol, LoginPolicyIDCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{LoginPolicyOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -116,6 +119,10 @@ func (p *loginPolicyProjection) reducers() []handler.AggregateReducer { Event: org.LoginPolicySecondFactorRemovedEventType, Reduce: p.reduce2FARemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -381,3 +388,23 @@ func (p *loginPolicyProjection) reduce2FARemoved(event eventstore.Event) (*handl }, ), nil } + +func (p *loginPolicyProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-B8NZW", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(LoginPolicyChangeDateCol, e.CreationDate()), + handler.NewCol(LoginPolicySequenceCol, e.Sequence()), + handler.NewCol(LoginPolicyOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(LoginPolicyInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(LoginPolicyIDCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/login_policy_test.go b/internal/query/projection/login_policy_test.go index 071fa3659f..8ade083c0e 100644 --- a/internal/query/projection/login_policy_test.go +++ b/internal/query/projection/login_policy_test.go @@ -57,7 +57,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.login_policies3 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)", + expectedStmt: "INSERT INTO projections.login_policies4 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -121,7 +121,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) WHERE (aggregate_id = $19) AND (instance_id = $20)", + expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) WHERE (aggregate_id = $19) AND (instance_id = $20)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -168,7 +168,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -200,7 +200,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -230,7 +230,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.login_policies3 WHERE (aggregate_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.login_policies4 WHERE (aggregate_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -259,7 +259,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -291,7 +291,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -338,7 +338,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.login_policies3 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)", + expectedStmt: "INSERT INTO projections.login_policies4 (aggregate_id, instance_id, creation_date, change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, is_default, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri, password_check_lifetime, external_login_check_lifetime, mfa_init_skip_lifetime, second_factor_check_lifetime, multi_factor_check_lifetime) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -397,7 +397,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) WHERE (aggregate_id = $14) AND (instance_id = $15)", + expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, allow_register, allow_username_password, allow_external_idps, force_mfa, passwordless_type, hide_password_reset, ignore_unknown_usernames, allow_domain_discovery, disable_login_with_email, disable_login_with_phone, default_redirect_uri) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) WHERE (aggregate_id = $14) AND (instance_id = $15)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -439,7 +439,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, multi_factors) = ($1, $2, array_append(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -471,7 +471,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, multi_factors) = ($1, $2, array_remove(multi_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -503,7 +503,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, second_factors) = ($1, $2, array_append(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -535,7 +535,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.login_policies3 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, second_factors) = ($1, $2, array_remove(second_factors, $3)) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -548,6 +548,36 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&loginPolicyProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.login_policies4 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (aggregate_id = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, { name: "instance reduceInstanceRemoved", args: args{ @@ -565,7 +595,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.login_policies3 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.login_policies4 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/mail_template.go b/internal/query/projection/mail_template.go index d8e8cd8108..8153ffceb4 100644 --- a/internal/query/projection/mail_template.go +++ b/internal/query/projection/mail_template.go @@ -14,7 +14,7 @@ import ( ) const ( - MailTemplateTable = "projections.mail_templates" + MailTemplateTable = "projections.mail_templates2" MailTemplateAggregateIDCol = "aggregate_id" MailTemplateInstanceIDCol = "instance_id" @@ -24,6 +24,7 @@ const ( MailTemplateStateCol = "state" MailTemplateIsDefaultCol = "is_default" MailTemplateTemplateCol = "template" + MailTemplateOwnerRemovedCol = "owner_removed" ) type mailTemplateProjection struct { @@ -44,8 +45,10 @@ func newMailTemplateProjection(ctx context.Context, config crdb.StatementHandler crdb.NewColumn(MailTemplateStateCol, crdb.ColumnTypeEnum), crdb.NewColumn(MailTemplateIsDefaultCol, crdb.ColumnTypeBool, crdb.Default(false)), crdb.NewColumn(MailTemplateTemplateCol, crdb.ColumnTypeBytes), + crdb.NewColumn(MailTemplateOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(MailTemplateInstanceIDCol, MailTemplateAggregateIDCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{MailTemplateOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -69,6 +72,10 @@ func (p *mailTemplateProjection) reducers() []handler.AggregateReducer { Event: org.MailTemplateRemovedEventType, Reduce: p.reduceRemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -156,3 +163,23 @@ func (p *mailTemplateProjection) reduceRemoved(event eventstore.Event) (*handler handler.NewCond(MailTemplateInstanceIDCol, policyEvent.Aggregate().InstanceID), }), nil } + +func (p *mailTemplateProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-CThXR", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(MailTemplateChangeDateCol, e.CreationDate()), + handler.NewCol(MailTemplateSequenceCol, e.Sequence()), + handler.NewCol(MailTemplateOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(MailTemplateInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(MailTemplateAggregateIDCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/mail_template_test.go b/internal/query/projection/mail_template_test.go index 047af571b8..284a75b154 100644 --- a/internal/query/projection/mail_template_test.go +++ b/internal/query/projection/mail_template_test.go @@ -23,7 +23,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { want wantReduce }{ { - name: "org reduceAdded", + name: "org.reduceAdded", args: args{ event: getEvent(testEvent( repository.EventType(org.MailTemplateAddedEventType), @@ -41,7 +41,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.mail_templates (aggregate_id, instance_id, creation_date, change_date, sequence, state, is_default, template) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.mail_templates2 (aggregate_id, instance_id, creation_date, change_date, sequence, state, is_default, template) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -58,7 +58,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { }, }, { - name: "org reduceChanged", + name: "org.reduceChanged", reduce: (&mailTemplateProjection{}).reduceChanged, args: args{ event: getEvent(testEvent( @@ -76,7 +76,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.mail_templates SET (change_date, sequence, template) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.mail_templates2 SET (change_date, sequence, template) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -90,7 +90,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { }, }, { - name: "org reduceRemoved", + name: "org.reduceRemoved", reduce: (&mailTemplateProjection{}).reduceRemoved, args: args{ event: getEvent(testEvent( @@ -106,7 +106,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.mail_templates WHERE (aggregate_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.mail_templates2 WHERE (aggregate_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -117,7 +117,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { }, }, { - name: "instance reduceInstanceRemoved", + name: "instance.reduceInstanceRemoved", args: args{ event: getEvent(testEvent( repository.EventType(instance.InstanceRemovedEventType), @@ -133,7 +133,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.mail_templates WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.mail_templates2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -143,7 +143,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { }, }, { - name: "instance reduceAdded", + name: "instance.reduceAdded", reduce: (&mailTemplateProjection{}).reduceAdded, args: args{ event: getEvent(testEvent( @@ -161,7 +161,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.mail_templates (aggregate_id, instance_id, creation_date, change_date, sequence, state, is_default, template) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.mail_templates2 (aggregate_id, instance_id, creation_date, change_date, sequence, state, is_default, template) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -178,7 +178,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { }, }, { - name: "instance reduceChanged", + name: "instance.reduceChanged", reduce: (&mailTemplateProjection{}).reduceChanged, args: args{ event: getEvent(testEvent( @@ -196,7 +196,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.mail_templates SET (change_date, sequence, template) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.mail_templates2 SET (change_date, sequence, template) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -209,6 +209,36 @@ func TestMailTemplateProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&mailTemplateProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.mail_templates2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (aggregate_id = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/main_test.go b/internal/query/projection/main_test.go new file mode 100644 index 0000000000..6d7001902d --- /dev/null +++ b/internal/query/projection/main_test.go @@ -0,0 +1,61 @@ +package projection + +import ( + "database/sql" + "testing" + "time" + + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/eventstore/repository" + "github.com/zitadel/zitadel/internal/eventstore/repository/mock" + action_repo "github.com/zitadel/zitadel/internal/repository/action" + iam_repo "github.com/zitadel/zitadel/internal/repository/instance" + key_repo "github.com/zitadel/zitadel/internal/repository/keypair" + "github.com/zitadel/zitadel/internal/repository/org" + proj_repo "github.com/zitadel/zitadel/internal/repository/project" + usr_repo "github.com/zitadel/zitadel/internal/repository/user" + "github.com/zitadel/zitadel/internal/repository/usergrant" +) + +type expect func(mockRepository *mock.MockRepository) + +func eventstoreExpect(t *testing.T, expects ...expect) *eventstore.Eventstore { + m := mock.NewRepo(t) + for _, e := range expects { + e(m) + } + es := eventstore.NewEventstore(m) + iam_repo.RegisterEventMappers(es) + org.RegisterEventMappers(es) + usr_repo.RegisterEventMappers(es) + proj_repo.RegisterEventMappers(es) + usergrant.RegisterEventMappers(es) + key_repo.RegisterEventMappers(es) + action_repo.RegisterEventMappers(es) + return es +} + +func expectFilter(events ...*repository.Event) expect { + return func(m *mock.MockRepository) { + m.ExpectFilterEvents(events...) + } +} + +func eventFromEventPusher(event eventstore.Command) *repository.Event { + data, _ := eventstore.EventData(event) + return &repository.Event{ + ID: "", + Sequence: 0, + PreviousAggregateSequence: 0, + PreviousAggregateTypeSequence: 0, + CreationDate: time.Time{}, + Type: repository.EventType(event.Type()), + Data: data, + EditorService: event.EditorService(), + EditorUser: event.EditorUser(), + Version: repository.Version(event.Aggregate().Version), + AggregateID: event.Aggregate().ID, + AggregateType: repository.AggregateType(event.Aggregate().Type), + ResourceOwner: sql.NullString{String: event.Aggregate().ResourceOwner, Valid: event.Aggregate().ResourceOwner != ""}, + } +} diff --git a/internal/query/projection/member.go b/internal/query/projection/member.go index b9c7e0cac4..b6cad5098b 100644 --- a/internal/query/projection/member.go +++ b/internal/query/projection/member.go @@ -1,6 +1,9 @@ package projection import ( + "context" + + "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/database" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler" @@ -9,14 +12,17 @@ import ( ) const ( - MemberUserIDCol = "user_id" - MemberRolesCol = "roles" + MemberUserIDCol = "user_id" + MemberRolesCol = "roles" + MemberUserResourceOwner = "user_resource_owner" + MemberUserOwnerRemoved = "user_owner_removed" MemberCreationDate = "creation_date" MemberChangeDate = "change_date" MemberSequence = "sequence" MemberResourceOwner = "resource_owner" MemberInstanceID = "instance_id" + MemberOwnerRemoved = "owner_removed" ) var ( @@ -24,10 +30,13 @@ var ( crdb.NewColumn(MemberCreationDate, crdb.ColumnTypeTimestamp), crdb.NewColumn(MemberChangeDate, crdb.ColumnTypeTimestamp), crdb.NewColumn(MemberUserIDCol, crdb.ColumnTypeText), + crdb.NewColumn(MemberUserResourceOwner, crdb.ColumnTypeText), + crdb.NewColumn(MemberUserOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), crdb.NewColumn(MemberRolesCol, crdb.ColumnTypeTextArray, crdb.Nullable()), crdb.NewColumn(MemberSequence, crdb.ColumnTypeInt64), crdb.NewColumn(MemberResourceOwner, crdb.ColumnTypeText), crdb.NewColumn(MemberInstanceID, crdb.ColumnTypeText), + crdb.NewColumn(MemberOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), } ) @@ -52,16 +61,19 @@ func withMemberCond(cond string, value interface{}) reduceMemberOpt { } } -func reduceMemberAdded(e member.MemberAddedEvent, opts ...reduceMemberOpt) (*handler.Statement, error) { +func reduceMemberAdded(e member.MemberAddedEvent, userResourceOwner string, opts ...reduceMemberOpt) (*handler.Statement, error) { config := reduceMemberConfig{ cols: []handler.Column{ handler.NewCol(MemberUserIDCol, e.UserID), + handler.NewCol(MemberUserResourceOwner, userResourceOwner), + handler.NewCol(MemberUserOwnerRemoved, false), handler.NewCol(MemberRolesCol, database.StringArray(e.Roles)), handler.NewCol(MemberCreationDate, e.CreationDate()), handler.NewCol(MemberChangeDate, e.CreationDate()), handler.NewCol(MemberSequence, e.Sequence()), handler.NewCol(MemberResourceOwner, e.Aggregate().ResourceOwner), handler.NewCol(MemberInstanceID, e.Aggregate().InstanceID), + handler.NewCol(MemberOwnerRemoved, false), }} for _, opt := range opts { @@ -115,3 +127,65 @@ func reduceMemberRemoved(e eventstore.Event, opts ...reduceMemberOpt) (*handler. } return crdb.NewDeleteStatement(e, config.conds), nil } + +func multiReduceMemberOwnerRemoved(e eventstore.Event, opts ...reduceMemberOpt) func(eventstore.Event) crdb.Exec { + config := reduceMemberConfig{ + conds: []handler.Condition{ + handler.NewCond(MemberInstanceID, e.Aggregate().InstanceID), + handler.NewCond(MemberResourceOwner, e.Aggregate().ID), + }, + } + + for _, opt := range opts { + config = opt(config) + } + return crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(MemberChangeDate, e.CreationDate()), + handler.NewCol(MemberSequence, e.Sequence()), + handler.NewCol(MemberOwnerRemoved, true), + }, + config.conds, + ) +} + +func memberUserOwnerRemovedConds(e eventstore.Event, opts ...reduceMemberOpt) []handler.Condition { + config := reduceMemberConfig{ + conds: []handler.Condition{ + handler.NewCond(MemberInstanceID, e.Aggregate().InstanceID), + handler.NewCond(MemberUserResourceOwner, e.Aggregate().ID), + }, + } + + for _, opt := range opts { + config = opt(config) + } + return config.conds +} + +func memberUserOwnerRemovedCols(e eventstore.Event) []handler.Column { + return []handler.Column{ + handler.NewCol(MemberChangeDate, e.CreationDate()), + handler.NewCol(MemberSequence, e.Sequence()), + handler.NewCol(MemberUserOwnerRemoved, true), + } +} + +func reduceMemberUserOwnerRemoved(e eventstore.Event, opts ...reduceMemberOpt) (*handler.Statement, error) { + return crdb.NewUpdateStatement( + e, + memberUserOwnerRemovedCols(e), + memberUserOwnerRemovedConds(e, opts...), + ), nil +} + +func multiReduceMemberUserOwnerRemoved(e eventstore.Event, opts ...reduceMemberOpt) func(eventstore.Event) crdb.Exec { + return crdb.AddUpdateStatement( + memberUserOwnerRemovedCols(e), + memberUserOwnerRemovedConds(e, opts...), + ) +} + +func setMemberContext(event eventstore.Aggregate) context.Context { + return authz.WithInstanceID(context.Background(), event.InstanceID) +} diff --git a/internal/query/projection/message_text_test.go b/internal/query/projection/message_text_test.go index 7e0eaad444..b48dbed0fd 100644 --- a/internal/query/projection/message_text_test.go +++ b/internal/query/projection/message_text_test.go @@ -44,7 +44,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.message_texts (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, title) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, title) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.title)", + expectedStmt: "INSERT INTO projections.message_texts2 (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, title) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, title) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.title)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -83,7 +83,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.message_texts (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, pre_header) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, pre_header) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.pre_header)", + expectedStmt: "INSERT INTO projections.message_texts2 (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, pre_header) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, pre_header) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.pre_header)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -122,7 +122,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.message_texts (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, subject) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, subject) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.subject)", + expectedStmt: "INSERT INTO projections.message_texts2 (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, subject) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, subject) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.subject)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -161,7 +161,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.message_texts (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, greeting) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, greeting) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.greeting)", + expectedStmt: "INSERT INTO projections.message_texts2 (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, greeting) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, greeting) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.greeting)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -200,7 +200,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.message_texts (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, text) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, text) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.text)", + expectedStmt: "INSERT INTO projections.message_texts2 (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, text) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, text) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.text)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -239,7 +239,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.message_texts (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, button_text) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, button_text) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.button_text)", + expectedStmt: "INSERT INTO projections.message_texts2 (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, button_text) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, button_text) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.button_text)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -278,7 +278,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.message_texts (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, footer_text) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, footer_text) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.footer_text)", + expectedStmt: "INSERT INTO projections.message_texts2 (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, footer_text) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, footer_text) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.footer_text)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -316,7 +316,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.message_texts SET (change_date, sequence, title) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.message_texts2 SET (change_date, sequence, title) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -348,7 +348,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.message_texts WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.message_texts2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -378,7 +378,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.message_texts SET (change_date, sequence, pre_header) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.message_texts2 SET (change_date, sequence, pre_header) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -414,7 +414,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.message_texts SET (change_date, sequence, subject) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.message_texts2 SET (change_date, sequence, subject) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -450,7 +450,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.message_texts SET (change_date, sequence, greeting) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.message_texts2 SET (change_date, sequence, greeting) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -486,7 +486,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.message_texts SET (change_date, sequence, text) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.message_texts2 SET (change_date, sequence, text) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -522,7 +522,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.message_texts SET (change_date, sequence, button_text) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.message_texts2 SET (change_date, sequence, button_text) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -558,7 +558,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.message_texts SET (change_date, sequence, footer_text) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.message_texts2 SET (change_date, sequence, footer_text) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -594,7 +594,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.message_texts WHERE (aggregate_id = $1) AND (type = $2) AND (language = $3) AND (instance_id = $4)", + expectedStmt: "DELETE FROM projections.message_texts2 WHERE (aggregate_id = $1) AND (type = $2) AND (language = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "agg-id", "InitCode", @@ -628,7 +628,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.message_texts (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, title) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, title) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.title)", + expectedStmt: "INSERT INTO projections.message_texts2 (aggregate_id, instance_id, creation_date, change_date, sequence, state, type, language, title) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (instance_id, aggregate_id, type, language) DO UPDATE SET (creation_date, change_date, sequence, state, title) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.title)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -666,7 +666,7 @@ func TestMessageTextProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.message_texts SET (change_date, sequence, title) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.message_texts2 SET (change_date, sequence, title) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (type = $5) AND (language = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -681,6 +681,36 @@ func TestMessageTextProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&messageTextProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.message_texts2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (aggregate_id = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/message_texts.go b/internal/query/projection/message_texts.go index 1e74536231..ab005938d4 100644 --- a/internal/query/projection/message_texts.go +++ b/internal/query/projection/message_texts.go @@ -14,7 +14,7 @@ import ( ) const ( - MessageTextTable = "projections.message_texts" + MessageTextTable = "projections.message_texts2" MessageTextAggregateIDCol = "aggregate_id" MessageTextInstanceIDCol = "instance_id" @@ -31,6 +31,7 @@ const ( MessageTextTextCol = "text" MessageTextButtonTextCol = "button_text" MessageTextFooterCol = "footer_text" + MessageTextOwnerRemovedCol = "owner_removed" ) type messageTextProjection struct { @@ -58,8 +59,10 @@ func newMessageTextProjection(ctx context.Context, config crdb.StatementHandlerC crdb.NewColumn(MessageTextTextCol, crdb.ColumnTypeText, crdb.Nullable()), crdb.NewColumn(MessageTextButtonTextCol, crdb.ColumnTypeText, crdb.Nullable()), crdb.NewColumn(MessageTextFooterCol, crdb.ColumnTypeText, crdb.Nullable()), + crdb.NewColumn(MessageTextOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(MessageTextInstanceIDCol, MessageTextAggregateIDCol, MessageTextTypeCol, MessageTextLanguageCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{MessageTextOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -83,6 +86,10 @@ func (p *messageTextProjection) reducers() []handler.AggregateReducer { Event: org.CustomTextTemplateRemovedEventType, Reduce: p.reduceTemplateRemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -240,6 +247,26 @@ func (p *messageTextProjection) reduceTemplateRemoved(event eventstore.Event) (* ), nil } +func (p *messageTextProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-mLsQw", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(MessageTextChangeDateCol, e.CreationDate()), + handler.NewCol(MessageTextSequenceCol, e.Sequence()), + handler.NewCol(MessageTextOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(MessageTextInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(MessageTextAggregateIDCol, e.Aggregate().ID), + }, + ), nil +} + func isMessageTemplate(template string) bool { return template == domain.InitCodeMessageType || template == domain.PasswordResetMessageType || diff --git a/internal/query/projection/org.go b/internal/query/projection/org.go index 8ed5317c2c..1906b8977c 100644 --- a/internal/query/projection/org.go +++ b/internal/query/projection/org.go @@ -47,8 +47,8 @@ func newOrgProjection(ctx context.Context, config crdb.StatementHandlerConfig) * crdb.NewColumn(OrgColumnDomain, crdb.ColumnTypeText, crdb.Default("")), }, crdb.NewPrimaryKey(OrgColumnInstanceID, OrgColumnID), - crdb.WithIndex(crdb.NewIndex("domain_idx", []string{OrgColumnDomain})), - crdb.WithIndex(crdb.NewIndex("name_idx", []string{OrgColumnName})), + crdb.WithIndex(crdb.NewIndex("domain", []string{OrgColumnDomain})), + crdb.WithIndex(crdb.NewIndex("name", []string{OrgColumnName})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -76,6 +76,10 @@ func (p *orgProjection) reducers() []handler.AggregateReducer { Event: org.OrgReactivatedEventType, Reduce: p.reduceOrgReactivated, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOrgRemoved, + }, { Event: org.OrgDomainPrimarySetEventType, Reduce: p.reducePrimaryDomainSet, @@ -192,3 +196,22 @@ func (p *orgProjection) reducePrimaryDomainSet(event eventstore.Event) (*handler }, ), nil } + +func (p *orgProjection) reduceOrgRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-DgMSg", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(OrgColumnChangeDate, e.CreationDate()), + handler.NewCol(OrgColumnSequence, e.Sequence()), + handler.NewCol(OrgColumnState, domain.OrgStateRemoved), + }, + []handler.Condition{ + handler.NewCond(OrgColumnID, e.Aggregate().ID), + handler.NewCond(OrgColumnInstanceID, e.Aggregate().InstanceID), + }, + ), nil +} diff --git a/internal/query/projection/org_domain.go b/internal/query/projection/org_domain.go index 6ac9af1702..3211cf7c2c 100644 --- a/internal/query/projection/org_domain.go +++ b/internal/query/projection/org_domain.go @@ -13,7 +13,7 @@ import ( ) const ( - OrgDomainTable = "projections.org_domains" + OrgDomainTable = "projections.org_domains2" OrgDomainOrgIDCol = "org_id" OrgDomainInstanceIDCol = "instance_id" @@ -24,6 +24,7 @@ const ( OrgDomainIsVerifiedCol = "is_verified" OrgDomainIsPrimaryCol = "is_primary" OrgDomainValidationTypeCol = "validation_type" + OrgDomainOwnerRemovedCol = "owner_removed" ) type orgDomainProjection struct { @@ -45,8 +46,10 @@ func newOrgDomainProjection(ctx context.Context, config crdb.StatementHandlerCon crdb.NewColumn(OrgDomainIsVerifiedCol, crdb.ColumnTypeBool), crdb.NewColumn(OrgDomainIsPrimaryCol, crdb.ColumnTypeBool), crdb.NewColumn(OrgDomainValidationTypeCol, crdb.ColumnTypeEnum), + crdb.NewColumn(OrgDomainOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(OrgDomainOrgIDCol, OrgDomainDomainCol, OrgDomainInstanceIDCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{OrgDomainOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -78,6 +81,10 @@ func (p *orgDomainProjection) reducers() []handler.AggregateReducer { Event: org.OrgDomainRemovedEventType, Reduce: p.reduceDomainRemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -201,3 +208,23 @@ func (p *orgDomainProjection) reduceDomainRemoved(event eventstore.Event) (*hand }, ), nil } + +func (p *orgDomainProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-dMUKJ", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(OrgDomainChangeDateCol, e.CreationDate()), + handler.NewCol(OrgDomainSequenceCol, e.Sequence()), + handler.NewCol(OrgDomainOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(OrgDomainInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(OrgDomainOrgIDCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/org_domain_test.go b/internal/query/projection/org_domain_test.go index 7f545899d9..4c59cdcdef 100644 --- a/internal/query/projection/org_domain_test.go +++ b/internal/query/projection/org_domain_test.go @@ -39,7 +39,7 @@ func TestOrgDomainProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.org_domains (creation_date, change_date, sequence, domain, org_id, instance_id, is_verified, is_primary, validation_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.org_domains2 (creation_date, change_date, sequence, domain, org_id, instance_id, is_verified, is_primary, validation_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -73,7 +73,7 @@ func TestOrgDomainProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.org_domains SET (change_date, sequence, validation_type) = ($1, $2, $3) WHERE (domain = $4) AND (org_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.org_domains2 SET (change_date, sequence, validation_type) = ($1, $2, $3) WHERE (domain = $4) AND (org_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -104,7 +104,7 @@ func TestOrgDomainProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.org_domains SET (change_date, sequence, is_verified) = ($1, $2, $3) WHERE (domain = $4) AND (org_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.org_domains2 SET (change_date, sequence, is_verified) = ($1, $2, $3) WHERE (domain = $4) AND (org_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -135,7 +135,7 @@ func TestOrgDomainProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.org_domains SET (change_date, sequence, is_primary) = ($1, $2, $3) WHERE (org_id = $4) AND (is_primary = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.org_domains2 SET (change_date, sequence, is_primary) = ($1, $2, $3) WHERE (org_id = $4) AND (is_primary = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -146,7 +146,7 @@ func TestOrgDomainProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.org_domains SET (change_date, sequence, is_primary) = ($1, $2, $3) WHERE (domain = $4) AND (org_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.org_domains2 SET (change_date, sequence, is_primary) = ($1, $2, $3) WHERE (domain = $4) AND (org_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -177,7 +177,7 @@ func TestOrgDomainProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.org_domains WHERE (domain = $1) AND (org_id = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.org_domains2 WHERE (domain = $1) AND (org_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "domain.new", "agg-id", @@ -188,6 +188,36 @@ func TestOrgDomainProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&orgDomainProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.org_domains2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (org_id = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, { name: "instance reduceInstanceRemoved", args: args{ @@ -205,7 +235,7 @@ func TestOrgDomainProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.org_domains WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.org_domains2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/org_member.go b/internal/query/projection/org_member.go index e5daa07a4e..b606eee61d 100644 --- a/internal/query/projection/org_member.go +++ b/internal/query/projection/org_member.go @@ -13,7 +13,7 @@ import ( ) const ( - OrgMemberProjectionTable = "projections.org_members2" + OrgMemberProjectionTable = "projections.org_members3" OrgMemberOrgIDCol = "org_id" ) @@ -29,7 +29,9 @@ func newOrgMemberProjection(ctx context.Context, config crdb.StatementHandlerCon crdb.NewTable( append(memberColumns, crdb.NewColumn(OrgMemberOrgIDCol, crdb.ColumnTypeText)), crdb.NewPrimaryKey(MemberInstanceID, OrgMemberOrgIDCol, MemberUserIDCol), - crdb.WithIndex(crdb.NewIndex("org_memb_user_idx", []string{MemberUserIDCol})), + crdb.WithIndex(crdb.NewIndex("user_id", []string{MemberUserIDCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{MemberOwnerRemoved})), + crdb.WithIndex(crdb.NewIndex("user_owner_removed", []string{MemberUserOwnerRemoved})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -89,7 +91,12 @@ func (p *orgMemberProjection) reduceAdded(event eventstore.Event) (*handler.Stat if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-uYq4r", "reduce.wrong.event.type %s", org.MemberAddedEventType) } - return reduceMemberAdded(e.MemberAddedEvent, withMemberCol(OrgMemberOrgIDCol, e.Aggregate().ID)) + ctx := setMemberContext(e.Aggregate()) + userOwner, err := getResourceOwnerOfUser(ctx, p.Eventstore, e.Aggregate().InstanceID, e.UserID) + if err != nil { + return nil, err + } + return reduceMemberAdded(e.MemberAddedEvent, userOwner, withMemberCol(OrgMemberOrgIDCol, e.Aggregate().ID)) } func (p *orgMemberProjection) reduceChanged(event eventstore.Event) (*handler.Statement, error) { @@ -128,13 +135,13 @@ func (p *orgMemberProjection) reduceUserRemoved(event eventstore.Event) (*handle } func (p *orgMemberProjection) reduceOrgRemoved(event eventstore.Event) (*handler.Statement, error) { - //TODO: as soon as org deletion is implemented: - // Case: The user has resource owner A and an org has resource owner B - // if org B deleted it works - // if org A is deleted, the membership wouldn't be deleted e, ok := event.(*org.OrgRemovedEvent) if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-jnGAV", "reduce.wrong.event.type %s", org.OrgRemovedEventType) } - return reduceMemberRemoved(e, withMemberCond(OrgMemberOrgIDCol, e.Aggregate().ID)) + return crdb.NewMultiStatement( + e, + multiReduceMemberOwnerRemoved(e), + multiReduceMemberUserOwnerRemoved(e), + ), nil } diff --git a/internal/query/projection/org_member_test.go b/internal/query/projection/org_member_test.go index daa4591d37..b2066ab4c3 100644 --- a/internal/query/projection/org_member_test.go +++ b/internal/query/projection/org_member_test.go @@ -1,9 +1,13 @@ package projection import ( + "context" "testing" + "golang.org/x/text/language" + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler" @@ -35,7 +39,21 @@ func TestOrgMemberProjection_reduces(t *testing.T) { }`), ), org.MemberAddedEventMapper), }, - reduce: (&orgMemberProjection{}).reduceAdded, + reduce: (&orgMemberProjection{ + StatementHandler: getStatementHandlerWithFilters( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user-id", "org1").Aggregate, + "username1", + "firstname1", + "lastname1", + "nickname1", + "displayname1", + language.German, + domain.GenderMale, + "email1", + true, + ), + )(t)}).reduceAdded, want: wantReduce{ aggregateType: org.AggregateType, sequence: 15, @@ -43,15 +61,18 @@ func TestOrgMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.org_members2 (user_id, roles, creation_date, change_date, sequence, resource_owner, instance_id, org_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.org_members3 (user_id, user_resource_owner, user_owner_removed, roles, creation_date, change_date, sequence, resource_owner, instance_id, owner_removed, org_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "user-id", + "org1", + false, database.StringArray{"role"}, anyArg{}, anyArg{}, uint64(15), "ro-id", "instance-id", + false, "agg-id", }, }, @@ -79,7 +100,7 @@ func TestOrgMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.org_members2 SET (roles, change_date, sequence) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_id = $5) AND (org_id = $6)", + expectedStmt: "UPDATE projections.org_members3 SET (roles, change_date, sequence) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_id = $5) AND (org_id = $6)", expectedArgs: []interface{}{ database.StringArray{"role", "changed"}, anyArg{}, @@ -112,7 +133,7 @@ func TestOrgMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.org_members2 WHERE (instance_id = $1) AND (user_id = $2) AND (org_id = $3)", + expectedStmt: "DELETE FROM projections.org_members3 WHERE (instance_id = $1) AND (user_id = $2) AND (org_id = $3)", expectedArgs: []interface{}{ "instance-id", "user-id", @@ -142,7 +163,7 @@ func TestOrgMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.org_members2 WHERE (instance_id = $1) AND (user_id = $2) AND (org_id = $3)", + expectedStmt: "DELETE FROM projections.org_members3 WHERE (instance_id = $1) AND (user_id = $2) AND (org_id = $3)", expectedArgs: []interface{}{ "instance-id", "user-id", @@ -170,7 +191,7 @@ func TestOrgMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.org_members2 WHERE (instance_id = $1) AND (user_id = $2)", + expectedStmt: "DELETE FROM projections.org_members3 WHERE (instance_id = $1) AND (user_id = $2)", expectedArgs: []interface{}{ "instance-id", "agg-id", @@ -197,8 +218,21 @@ func TestOrgMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.org_members2 WHERE (instance_id = $1) AND (org_id = $2)", + expectedStmt: "UPDATE projections.org_members3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + { + expectedStmt: "UPDATE projections.org_members3 SET (change_date, sequence, user_owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, "instance-id", "agg-id", }, @@ -224,7 +258,7 @@ func TestOrgMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.org_members2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.org_members3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/org_metadata.go b/internal/query/projection/org_metadata.go index 0f58cecdc5..3907bd4ee7 100644 --- a/internal/query/projection/org_metadata.go +++ b/internal/query/projection/org_metadata.go @@ -12,7 +12,7 @@ import ( ) const ( - OrgMetadataProjectionTable = "projections.org_metadata" + OrgMetadataProjectionTable = "projections.org_metadata2" OrgMetadataColumnOrgID = "org_id" OrgMetadataColumnCreationDate = "creation_date" @@ -22,6 +22,7 @@ const ( OrgMetadataColumnInstanceID = "instance_id" OrgMetadataColumnKey = "key" OrgMetadataColumnValue = "value" + OrgMetadataColumnOwnerRemoved = "owner_removed" ) type orgMetadataProjection struct { @@ -42,8 +43,10 @@ func newOrgMetadataProjection(ctx context.Context, config crdb.StatementHandlerC crdb.NewColumn(OrgMetadataColumnInstanceID, crdb.ColumnTypeText), crdb.NewColumn(OrgMetadataColumnKey, crdb.ColumnTypeText), crdb.NewColumn(OrgMetadataColumnValue, crdb.ColumnTypeBytes, crdb.Nullable()), + crdb.NewColumn(OrgMetadataColumnOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(OrgMetadataColumnInstanceID, OrgMetadataColumnOrgID, OrgMetadataColumnKey), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{OrgMetadataColumnOwnerRemoved})), ), ) @@ -70,7 +73,7 @@ func (p *orgMetadataProjection) reducers() []handler.AggregateReducer { }, { Event: org.OrgRemovedEventType, - Reduce: p.reduceMetadataRemovedAll, + Reduce: p.reduceOwnerRemoved, }, }, }, @@ -142,3 +145,23 @@ func (p *orgMetadataProjection) reduceMetadataRemovedAll(event eventstore.Event) }, ), nil } + +func (p *orgMetadataProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-Hkd1f", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(OrgMetadataColumnChangeDate, e.CreationDate()), + handler.NewCol(OrgMetadataColumnSequence, e.Sequence()), + handler.NewCol(OrgMetadataColumnOwnerRemoved, true), + }, + []handler.Condition{ + handler.NewCond(OrgMetadataColumnInstanceID, e.Aggregate().InstanceID), + handler.NewCond(OrgMetadataColumnResourceOwner, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/org_metadata_test.go b/internal/query/projection/org_metadata_test.go index fdb67ec912..034dbddd0b 100644 --- a/internal/query/projection/org_metadata_test.go +++ b/internal/query/projection/org_metadata_test.go @@ -41,7 +41,7 @@ func TestOrgMetadataProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.org_metadata (instance_id, org_id, key, resource_owner, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (instance_id, org_id, key) DO UPDATE SET (resource_owner, creation_date, change_date, sequence, value) = (EXCLUDED.resource_owner, EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)", + expectedStmt: "INSERT INTO projections.org_metadata2 (instance_id, org_id, key, resource_owner, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (instance_id, org_id, key) DO UPDATE SET (resource_owner, creation_date, change_date, sequence, value) = (EXCLUDED.resource_owner, EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)", expectedArgs: []interface{}{ "instance-id", "agg-id", @@ -76,7 +76,7 @@ func TestOrgMetadataProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.org_metadata WHERE (org_id = $1) AND (key = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.org_metadata2 WHERE (org_id = $1) AND (key = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "agg-id", "key", @@ -104,7 +104,7 @@ func TestOrgMetadataProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.org_metadata WHERE (org_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.org_metadata2 WHERE (org_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -115,7 +115,7 @@ func TestOrgMetadataProjection_reduces(t *testing.T) { }, }, { - name: "reduceMetadataRemovedAll (org removed)", + name: "reduceOwnerRemoved(org removed)", args: args{ event: getEvent(testEvent( repository.EventType(org.OrgRemovedEventType), @@ -123,7 +123,7 @@ func TestOrgMetadataProjection_reduces(t *testing.T) { nil, ), org.OrgRemovedEventMapper), }, - reduce: (&orgMetadataProjection{}).reduceMetadataRemovedAll, + reduce: (&orgMetadataProjection{}).reduceOwnerRemoved, want: wantReduce{ aggregateType: org.AggregateType, sequence: 15, @@ -131,10 +131,13 @@ func TestOrgMetadataProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.org_metadata WHERE (org_id = $1) AND (instance_id = $2)", + expectedStmt: "UPDATE projections.org_metadata2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", expectedArgs: []interface{}{ - "agg-id", + anyArg{}, + uint64(15), + true, "instance-id", + "agg-id", }, }, }, @@ -158,7 +161,7 @@ func TestOrgMetadataProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.org_metadata WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.org_metadata2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/org_test.go b/internal/query/projection/org_test.go index cf2eb12d5b..bae5d6bec6 100644 --- a/internal/query/projection/org_test.go +++ b/internal/query/projection/org_test.go @@ -192,6 +192,36 @@ func TestOrgProjection_reduces(t *testing.T) { }, }, }, + { + name: "reduceOrgRemoved", + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + reduce: (&orgProjection{}).reduceOrgRemoved, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.orgs SET (change_date, sequence, org_state) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + domain.OrgStateRemoved, + "agg-id", + "instance-id", + }, + }, + }, + }, + }, + }, { name: "instance reduceInstanceRemoved", args: args{ diff --git a/internal/query/projection/password_age_policy.go b/internal/query/projection/password_age_policy.go index a553667389..e8a2a3c958 100644 --- a/internal/query/projection/password_age_policy.go +++ b/internal/query/projection/password_age_policy.go @@ -14,7 +14,7 @@ import ( ) const ( - PasswordAgeTable = "projections.password_age_policies" + PasswordAgeTable = "projections.password_age_policies2" AgePolicyIDCol = "id" AgePolicyCreationDateCol = "creation_date" @@ -26,6 +26,7 @@ const ( AgePolicyInstanceIDCol = "instance_id" AgePolicyExpireWarnDaysCol = "expire_warn_days" AgePolicyMaxAgeDaysCol = "max_age_days" + AgePolicyOwnerRemovedCol = "owner_removed" ) type passwordAgeProjection struct { @@ -48,8 +49,10 @@ func newPasswordAgeProjection(ctx context.Context, config crdb.StatementHandlerC crdb.NewColumn(AgePolicyInstanceIDCol, crdb.ColumnTypeText), crdb.NewColumn(AgePolicyExpireWarnDaysCol, crdb.ColumnTypeInt64), crdb.NewColumn(AgePolicyMaxAgeDaysCol, crdb.ColumnTypeInt64), + crdb.NewColumn(AgePolicyOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(AgePolicyInstanceIDCol, AgePolicyIDCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{AgePolicyOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -73,6 +76,10 @@ func (p *passwordAgeProjection) reducers() []handler.AggregateReducer { Event: org.PasswordAgePolicyRemovedEventType, Reduce: p.reduceRemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -165,3 +172,23 @@ func (p *passwordAgeProjection) reduceRemoved(event eventstore.Event) (*handler. handler.NewCond(AgePolicyInstanceIDCol, policyEvent.Aggregate().InstanceID), }), nil } + +func (p *passwordAgeProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-edLs2", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(AgePolicyChangeDateCol, e.CreationDate()), + handler.NewCol(AgePolicySequenceCol, e.Sequence()), + handler.NewCol(AgePolicyOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(AgePolicyInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(AgePolicyResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/password_age_policy_test.go b/internal/query/projection/password_age_policy_test.go index a01cb38cdc..baff9c2f3d 100644 --- a/internal/query/projection/password_age_policy_test.go +++ b/internal/query/projection/password_age_policy_test.go @@ -42,7 +42,7 @@ func TestPasswordAgeProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.password_age_policies (creation_date, change_date, sequence, id, state, expire_warn_days, max_age_days, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.password_age_policies2 (creation_date, change_date, sequence, id, state, expire_warn_days, max_age_days, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -80,7 +80,7 @@ func TestPasswordAgeProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.password_age_policies SET (change_date, sequence, expire_warn_days, max_age_days) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.password_age_policies2 SET (change_date, sequence, expire_warn_days, max_age_days) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -111,7 +111,7 @@ func TestPasswordAgeProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.password_age_policies WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.password_age_policies2 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -138,7 +138,7 @@ func TestPasswordAgeProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.password_age_policies WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.password_age_policies2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -167,7 +167,7 @@ func TestPasswordAgeProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.password_age_policies (creation_date, change_date, sequence, id, state, expire_warn_days, max_age_days, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.password_age_policies2 (creation_date, change_date, sequence, id, state, expire_warn_days, max_age_days, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -205,7 +205,7 @@ func TestPasswordAgeProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.password_age_policies SET (change_date, sequence, expire_warn_days, max_age_days) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.password_age_policies2 SET (change_date, sequence, expire_warn_days, max_age_days) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -219,6 +219,36 @@ func TestPasswordAgeProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&passwordAgeProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.password_age_policies2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/password_complexity_policy.go b/internal/query/projection/password_complexity_policy.go index 0bd93e892e..dde4f32ca8 100644 --- a/internal/query/projection/password_complexity_policy.go +++ b/internal/query/projection/password_complexity_policy.go @@ -14,7 +14,7 @@ import ( ) const ( - PasswordComplexityTable = "projections.password_complexity_policies" + PasswordComplexityTable = "projections.password_complexity_policies2" ComplexityPolicyIDCol = "id" ComplexityPolicyCreationDateCol = "creation_date" @@ -29,6 +29,7 @@ const ( ComplexityPolicyHasUppercaseCol = "has_uppercase" ComplexityPolicyHasSymbolCol = "has_symbol" ComplexityPolicyHasNumberCol = "has_number" + ComplexityPolicyOwnerRemovedCol = "owner_removed" ) type passwordComplexityProjection struct { @@ -54,8 +55,10 @@ func newPasswordComplexityProjection(ctx context.Context, config crdb.StatementH crdb.NewColumn(ComplexityPolicyHasUppercaseCol, crdb.ColumnTypeBool), crdb.NewColumn(ComplexityPolicyHasSymbolCol, crdb.ColumnTypeBool), crdb.NewColumn(ComplexityPolicyHasNumberCol, crdb.ColumnTypeBool), + crdb.NewColumn(ComplexityPolicyOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(ComplexityPolicyInstanceIDCol, ComplexityPolicyIDCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{ComplexityPolicyOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -79,6 +82,10 @@ func (p *passwordComplexityProjection) reducers() []handler.AggregateReducer { Event: org.PasswordComplexityPolicyRemovedEventType, Reduce: p.reduceRemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -183,3 +190,23 @@ func (p *passwordComplexityProjection) reduceRemoved(event eventstore.Event) (*h handler.NewCond(ComplexityPolicyInstanceIDCol, policyEvent.Aggregate().InstanceID), }), nil } + +func (p *passwordComplexityProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-pGTz9", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(ComplexityPolicyChangeDateCol, e.CreationDate()), + handler.NewCol(ComplexityPolicySequenceCol, e.Sequence()), + handler.NewCol(ComplexityPolicyOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(ComplexityPolicyInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(ComplexityPolicyResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/password_complexity_policy_test.go b/internal/query/projection/password_complexity_policy_test.go index 6caf310a65..f9d2b1d836 100644 --- a/internal/query/projection/password_complexity_policy_test.go +++ b/internal/query/projection/password_complexity_policy_test.go @@ -45,7 +45,7 @@ func TestPasswordComplexityProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.password_complexity_policies (creation_date, change_date, sequence, id, state, min_length, has_lowercase, has_uppercase, has_symbol, has_number, resource_owner, instance_id, is_default) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)", + expectedStmt: "INSERT INTO projections.password_complexity_policies2 (creation_date, change_date, sequence, id, state, min_length, has_lowercase, has_uppercase, has_symbol, has_number, resource_owner, instance_id, is_default) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -89,7 +89,7 @@ func TestPasswordComplexityProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.password_complexity_policies SET (change_date, sequence, min_length, has_lowercase, has_uppercase, has_symbol, has_number) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (instance_id = $9)", + expectedStmt: "UPDATE projections.password_complexity_policies2 SET (change_date, sequence, min_length, has_lowercase, has_uppercase, has_symbol, has_number) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (instance_id = $9)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -123,7 +123,7 @@ func TestPasswordComplexityProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.password_complexity_policies WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.password_complexity_policies2 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -150,7 +150,7 @@ func TestPasswordComplexityProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.password_complexity_policies WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.password_complexity_policies2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -182,7 +182,7 @@ func TestPasswordComplexityProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.password_complexity_policies (creation_date, change_date, sequence, id, state, min_length, has_lowercase, has_uppercase, has_symbol, has_number, resource_owner, instance_id, is_default) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)", + expectedStmt: "INSERT INTO projections.password_complexity_policies2 (creation_date, change_date, sequence, id, state, min_length, has_lowercase, has_uppercase, has_symbol, has_number, resource_owner, instance_id, is_default) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -226,7 +226,7 @@ func TestPasswordComplexityProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.password_complexity_policies SET (change_date, sequence, min_length, has_lowercase, has_uppercase, has_symbol, has_number) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (instance_id = $9)", + expectedStmt: "UPDATE projections.password_complexity_policies2 SET (change_date, sequence, min_length, has_lowercase, has_uppercase, has_symbol, has_number) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (instance_id = $9)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -243,6 +243,36 @@ func TestPasswordComplexityProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&passwordComplexityProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.password_complexity_policies2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/privacy_policy.go b/internal/query/projection/privacy_policy.go index 5c854f3075..ca0b8b3bab 100644 --- a/internal/query/projection/privacy_policy.go +++ b/internal/query/projection/privacy_policy.go @@ -14,7 +14,7 @@ import ( ) const ( - PrivacyPolicyTable = "projections.privacy_policies" + PrivacyPolicyTable = "projections.privacy_policies2" PrivacyPolicyIDCol = "id" PrivacyPolicyCreationDateCol = "creation_date" @@ -27,6 +27,7 @@ const ( PrivacyPolicyPrivacyLinkCol = "privacy_link" PrivacyPolicyTOSLinkCol = "tos_link" PrivacyPolicyHelpLinkCol = "help_link" + PrivacyPolicyOwnerRemovedCol = "owner_removed" ) type privacyPolicyProjection struct { @@ -50,8 +51,10 @@ func newPrivacyPolicyProjection(ctx context.Context, config crdb.StatementHandle crdb.NewColumn(PrivacyPolicyPrivacyLinkCol, crdb.ColumnTypeText), crdb.NewColumn(PrivacyPolicyTOSLinkCol, crdb.ColumnTypeText), crdb.NewColumn(PrivacyPolicyHelpLinkCol, crdb.ColumnTypeText), + crdb.NewColumn(PrivacyPolicyOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(PrivacyPolicyInstanceIDCol, PrivacyPolicyIDCol), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{PrivacyPolicyOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -75,6 +78,10 @@ func (p *privacyPolicyProjection) reducers() []handler.AggregateReducer { Event: org.PrivacyPolicyRemovedEventType, Reduce: p.reduceRemoved, }, + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, }, }, { @@ -171,3 +178,23 @@ func (p *privacyPolicyProjection) reduceRemoved(event eventstore.Event) (*handle handler.NewCond(PrivacyPolicyInstanceIDCol, policyEvent.Aggregate().InstanceID), }), nil } + +func (p *privacyPolicyProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-bxJCY", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(PrivacyPolicyChangeDateCol, e.CreationDate()), + handler.NewCol(PrivacyPolicySequenceCol, e.Sequence()), + handler.NewCol(PrivacyPolicyOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(PrivacyPolicyInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(PrivacyPolicyResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/privacy_policy_test.go b/internal/query/projection/privacy_policy_test.go index 92fd2da1ff..61866e01b5 100644 --- a/internal/query/projection/privacy_policy_test.go +++ b/internal/query/projection/privacy_policy_test.go @@ -43,7 +43,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.privacy_policies (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", + expectedStmt: "INSERT INTO projections.privacy_policies2 (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -83,7 +83,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.privacy_policies SET (change_date, sequence, privacy_link, tos_link, help_link) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.privacy_policies2 SET (change_date, sequence, privacy_link, tos_link, help_link) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -115,7 +115,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.privacy_policies WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.privacy_policies2 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -141,7 +141,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.privacy_policies WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.privacy_policies2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -171,7 +171,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.privacy_policies (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", + expectedStmt: "INSERT INTO projections.privacy_policies2 (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -211,7 +211,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.privacy_policies SET (change_date, sequence, privacy_link, tos_link, help_link) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.privacy_policies2 SET (change_date, sequence, privacy_link, tos_link, help_link) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -226,6 +226,36 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&privacyPolicyProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.privacy_policies2 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/project.go b/internal/query/projection/project.go index a4873eeb1a..c8f286f40a 100644 --- a/internal/query/projection/project.go +++ b/internal/query/projection/project.go @@ -9,11 +9,12 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/project" ) const ( - ProjectProjectionTable = "projections.projects2" + ProjectProjectionTable = "projections.projects3" ProjectColumnID = "id" ProjectColumnCreationDate = "creation_date" @@ -27,6 +28,7 @@ const ( ProjectColumnProjectRoleCheck = "project_role_check" ProjectColumnHasProjectCheck = "has_project_check" ProjectColumnPrivateLabelingSetting = "private_labeling_setting" + ProjectColumnOwnerRemoved = "owner_removed" ) type projectProjection struct { @@ -51,9 +53,11 @@ func newProjectProjection(ctx context.Context, config crdb.StatementHandlerConfi crdb.NewColumn(ProjectColumnProjectRoleCheck, crdb.ColumnTypeBool), crdb.NewColumn(ProjectColumnHasProjectCheck, crdb.ColumnTypeBool), crdb.NewColumn(ProjectColumnPrivateLabelingSetting, crdb.ColumnTypeEnum), + crdb.NewColumn(ProjectColumnOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(ProjectColumnInstanceID, ProjectColumnID), - crdb.WithIndex(crdb.NewIndex("project_ro_idx", []string{ProjectColumnResourceOwner})), + crdb.WithIndex(crdb.NewIndex("resource_owner", []string{ProjectColumnResourceOwner})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{ProjectColumnOwnerRemoved})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -87,6 +91,15 @@ func (p *projectProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, + }, + }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ @@ -211,3 +224,23 @@ func (p *projectProjection) reduceProjectRemoved(event eventstore.Event) (*handl }, ), nil } + +func (p *projectProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-sbgru", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(ProjectColumnChangeDate, e.CreationDate()), + handler.NewCol(ProjectColumnSequence, e.Sequence()), + handler.NewCol(ProjectColumnOwnerRemoved, true), + }, + []handler.Condition{ + handler.NewCond(ProjectColumnInstanceID, e.Aggregate().InstanceID), + handler.NewCond(ProjectColumnResourceOwner, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/project_grant.go b/internal/query/projection/project_grant.go index a83b1ba33d..e68d2b6c0f 100644 --- a/internal/query/projection/project_grant.go +++ b/internal/query/projection/project_grant.go @@ -10,22 +10,25 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/project" ) const ( - ProjectGrantProjectionTable = "projections.project_grants2" + ProjectGrantProjectionTable = "projections.project_grants3" - ProjectGrantColumnGrantID = "grant_id" - ProjectGrantColumnCreationDate = "creation_date" - ProjectGrantColumnChangeDate = "change_date" - ProjectGrantColumnSequence = "sequence" - ProjectGrantColumnState = "state" - ProjectGrantColumnResourceOwner = "resource_owner" - ProjectGrantColumnInstanceID = "instance_id" - ProjectGrantColumnProjectID = "project_id" - ProjectGrantColumnGrantedOrgID = "granted_org_id" - ProjectGrantColumnRoleKeys = "granted_role_keys" + ProjectGrantColumnGrantID = "grant_id" + ProjectGrantColumnCreationDate = "creation_date" + ProjectGrantColumnChangeDate = "change_date" + ProjectGrantColumnSequence = "sequence" + ProjectGrantColumnState = "state" + ProjectGrantColumnResourceOwner = "resource_owner" + ProjectGrantColumnInstanceID = "instance_id" + ProjectGrantColumnProjectID = "project_id" + ProjectGrantColumnGrantedOrgID = "granted_org_id" + ProjectGrantColumnRoleKeys = "granted_role_keys" + ProjectGrantColumnOwnerRemoved = "owner_removed" + ProjectGrantColumnGrantedOrgRemoved = "granted_org_removed" ) type projectGrantProjection struct { @@ -48,10 +51,14 @@ func newProjectGrantProjection(ctx context.Context, config crdb.StatementHandler crdb.NewColumn(ProjectGrantColumnProjectID, crdb.ColumnTypeText), crdb.NewColumn(ProjectGrantColumnGrantedOrgID, crdb.ColumnTypeText), crdb.NewColumn(ProjectGrantColumnRoleKeys, crdb.ColumnTypeTextArray, crdb.Nullable()), + crdb.NewColumn(ProjectGrantColumnOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), + crdb.NewColumn(ProjectGrantColumnGrantedOrgRemoved, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(ProjectGrantColumnInstanceID, ProjectGrantColumnGrantID), - crdb.WithIndex(crdb.NewIndex("pg_ro_idx", []string{ProjectGrantColumnResourceOwner})), - crdb.WithIndex(crdb.NewIndex("granted_org_idx", []string{ProjectGrantColumnGrantedOrgID})), + crdb.WithIndex(crdb.NewIndex("resource_owner", []string{ProjectGrantColumnResourceOwner})), + crdb.WithIndex(crdb.NewIndex("granted_org", []string{ProjectGrantColumnGrantedOrgID})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{ProjectGrantColumnOwnerRemoved})), + crdb.WithIndex(crdb.NewIndex("granted_org_removed", []string{ProjectGrantColumnGrantedOrgRemoved})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -93,6 +100,15 @@ func (p *projectGrantProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, + }, + }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ @@ -235,3 +251,36 @@ func (p *projectGrantProjection) reduceProjectRemoved(event eventstore.Event) (* }, ), nil } + +func (p *projectGrantProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-HDgW3", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewMultiStatement( + e, + crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(ProjectGrantColumnChangeDate, e.CreationDate()), + handler.NewCol(ProjectGrantColumnSequence, e.Sequence()), + handler.NewCol(ProjectGrantColumnOwnerRemoved, true), + }, + []handler.Condition{ + handler.NewCond(ProjectGrantColumnInstanceID, e.Aggregate().InstanceID), + handler.NewCond(ProjectGrantColumnResourceOwner, e.Aggregate().ID), + }, + ), + crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(ProjectGrantColumnChangeDate, e.CreationDate()), + handler.NewCol(ProjectGrantColumnSequence, e.Sequence()), + handler.NewCol(ProjectGrantColumnGrantedOrgRemoved, true), + }, + []handler.Condition{ + handler.NewCond(ProjectGrantColumnInstanceID, e.Aggregate().InstanceID), + handler.NewCond(ProjectGrantColumnGrantedOrgID, e.Aggregate().ID), + }, + ), + ), nil +} diff --git a/internal/query/projection/project_grant_member.go b/internal/query/projection/project_grant_member.go index 3ba8f16b4e..06523df46f 100644 --- a/internal/query/projection/project_grant_member.go +++ b/internal/query/projection/project_grant_member.go @@ -15,9 +15,11 @@ import ( ) const ( - ProjectGrantMemberProjectionTable = "projections.project_grant_members2" - ProjectGrantMemberProjectIDCol = "project_id" - ProjectGrantMemberGrantIDCol = "grant_id" + ProjectGrantMemberProjectionTable = "projections.project_grant_members3" + ProjectGrantMemberProjectIDCol = "project_id" + ProjectGrantMemberGrantIDCol = "grant_id" + ProjectGrantMemberGrantedOrg = "granted_org" + ProjectGrantMemberGrantedOrgRemoved = "granted_org_removed" ) type projectGrantMemberProjection struct { @@ -33,9 +35,14 @@ func newProjectGrantMemberProjection(ctx context.Context, config crdb.StatementH append(memberColumns, crdb.NewColumn(ProjectGrantMemberProjectIDCol, crdb.ColumnTypeText), crdb.NewColumn(ProjectGrantMemberGrantIDCol, crdb.ColumnTypeText), + crdb.NewColumn(ProjectGrantMemberGrantedOrg, crdb.ColumnTypeText), + crdb.NewColumn(ProjectGrantMemberGrantedOrgRemoved, crdb.ColumnTypeBool, crdb.Default(false)), ), crdb.NewPrimaryKey(MemberInstanceID, ProjectGrantMemberProjectIDCol, ProjectGrantMemberGrantIDCol, MemberUserIDCol), - crdb.WithIndex(crdb.NewIndex("proj_grant_memb_user_idx", []string{MemberUserIDCol})), + crdb.WithIndex(crdb.NewIndex("user_id", []string{MemberUserIDCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{MemberOwnerRemoved})), + crdb.WithIndex(crdb.NewIndex("user_owner_removed", []string{MemberUserOwnerRemoved})), + crdb.WithIndex(crdb.NewIndex("granted_org_removed", []string{ProjectGrantMemberGrantedOrgRemoved})), ), ) @@ -109,10 +116,22 @@ func (p *projectGrantMemberProjection) reduceAdded(event eventstore.Event) (*han if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-0EBQf", "reduce.wrong.event.type %s", project.GrantMemberAddedType) } + ctx := setMemberContext(e.Aggregate()) + userOwner, err := getResourceOwnerOfUser(ctx, p.Eventstore, e.Aggregate().InstanceID, e.UserID) + if err != nil { + return nil, err + } + grantedOrg, err := getGrantedOrgOfGrantedProject(ctx, p.Eventstore, e.Aggregate().InstanceID, e.Aggregate().ID, e.GrantID) + if err != nil { + return nil, err + } return reduceMemberAdded( *member.NewMemberAddedEvent(&e.BaseEvent, e.UserID, e.Roles...), + userOwner, withMemberCol(ProjectGrantMemberProjectIDCol, e.Aggregate().ID), withMemberCol(ProjectGrantMemberGrantIDCol, e.GrantID), + withMemberCol(ProjectGrantMemberGrantedOrg, grantedOrg), + withMemberCol(ProjectGrantMemberGrantedOrgRemoved, false), ) } @@ -169,15 +188,26 @@ func (p *projectGrantMemberProjection) reduceInstanceRemoved(event eventstore.Ev } func (p *projectGrantMemberProjection) reduceOrgRemoved(event eventstore.Event) (*handler.Statement, error) { - //TODO: as soon as org deletion is implemented: - // Case: The user has resource owner A and project has resource owner B - // if org B deleted it works - // if org A is deleted, the membership wouldn't be deleted e, ok := event.(*org.OrgRemovedEvent) if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-Zzp6o", "reduce.wrong.event.type %s", org.OrgRemovedEventType) } - return reduceMemberRemoved(e, withMemberCond(MemberResourceOwner, e.Aggregate().ID)) + return crdb.NewMultiStatement( + e, + multiReduceMemberOwnerRemoved(e), + multiReduceMemberUserOwnerRemoved(e), + crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(MemberChangeDate, e.CreationDate()), + handler.NewCol(MemberSequence, e.Sequence()), + handler.NewCol(ProjectGrantMemberGrantedOrgRemoved, true), + }, + []handler.Condition{ + handler.NewCond(ProjectGrantColumnInstanceID, e.Aggregate().InstanceID), + handler.NewCond(ProjectGrantMemberGrantedOrg, e.Aggregate().ID), + }, + ), + ), nil } func (p *projectGrantMemberProjection) reduceProjectRemoved(event eventstore.Event) (*handler.Statement, error) { diff --git a/internal/query/projection/project_grant_member_test.go b/internal/query/projection/project_grant_member_test.go index 0095f183d3..133c599264 100644 --- a/internal/query/projection/project_grant_member_test.go +++ b/internal/query/projection/project_grant_member_test.go @@ -1,9 +1,13 @@ package projection import ( + "context" "testing" + "golang.org/x/text/language" + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler" @@ -37,7 +41,25 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { }`), ), project.GrantMemberAddedEventMapper), }, - reduce: (&projectGrantMemberProjection{}).reduceAdded, + reduce: (&projectGrantMemberProjection{ + StatementHandler: getStatementHandlerWithFilters( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user-id", "org1").Aggregate, + "username1", + "firstname1", + "lastname1", + "nickname1", + "displayname1", + language.German, + domain.GenderMale, + "email1", + true, + ), + project.NewGrantAddedEvent(context.Background(), + &project.NewAggregate("project1", "org2").Aggregate, + "grant", "org3", []string{}, + ), + )(t)}).reduceAdded, want: wantReduce{ aggregateType: project.AggregateType, sequence: 15, @@ -45,17 +67,22 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.project_grant_members2 (user_id, roles, creation_date, change_date, sequence, resource_owner, instance_id, project_id, grant_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.project_grant_members3 (user_id, user_resource_owner, user_owner_removed, roles, creation_date, change_date, sequence, resource_owner, instance_id, owner_removed, project_id, grant_id, granted_org, granted_org_removed) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)", expectedArgs: []interface{}{ "user-id", + "org1", + false, database.StringArray{"role"}, anyArg{}, anyArg{}, uint64(15), "ro-id", "instance-id", + false, "agg-id", "grant-id", + "org3", + false, }, }, }, @@ -83,7 +110,7 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.project_grant_members2 SET (roles, change_date, sequence) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_id = $5) AND (project_id = $6) AND (grant_id = $7)", + expectedStmt: "UPDATE projections.project_grant_members3 SET (roles, change_date, sequence) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_id = $5) AND (project_id = $6) AND (grant_id = $7)", expectedArgs: []interface{}{ database.StringArray{"role", "changed"}, anyArg{}, @@ -118,7 +145,7 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_grant_members2 WHERE (instance_id = $1) AND (user_id = $2) AND (project_id = $3) AND (grant_id = $4)", + expectedStmt: "DELETE FROM projections.project_grant_members3 WHERE (instance_id = $1) AND (user_id = $2) AND (project_id = $3) AND (grant_id = $4)", expectedArgs: []interface{}{ "instance-id", "user-id", @@ -150,7 +177,7 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_grant_members2 WHERE (instance_id = $1) AND (user_id = $2) AND (project_id = $3) AND (grant_id = $4)", + expectedStmt: "DELETE FROM projections.project_grant_members3 WHERE (instance_id = $1) AND (user_id = $2) AND (project_id = $3) AND (grant_id = $4)", expectedArgs: []interface{}{ "instance-id", "user-id", @@ -179,7 +206,7 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_grant_members2 WHERE (instance_id = $1) AND (user_id = $2)", + expectedStmt: "DELETE FROM projections.project_grant_members3 WHERE (instance_id = $1) AND (user_id = $2)", expectedArgs: []interface{}{ "instance-id", "agg-id", @@ -190,23 +217,23 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { }, }, { - name: "org OrgRemovedEventType", + name: "project ProjectRemovedEventType", args: args{ event: getEvent(testEvent( - repository.EventType(org.OrgRemovedEventType), - org.AggregateType, + repository.EventType(project.ProjectRemovedType), + project.AggregateType, []byte(`{}`), - ), org.OrgRemovedEventMapper), + ), project.ProjectRemovedEventMapper), }, - reduce: (&projectGrantMemberProjection{}).reduceOrgRemoved, + reduce: (&projectGrantMemberProjection{}).reduceProjectRemoved, want: wantReduce{ - aggregateType: org.AggregateType, + aggregateType: project.AggregateType, sequence: 15, previousSequence: 10, executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_grant_members2 WHERE (instance_id = $1) AND (resource_owner = $2)", + expectedStmt: "DELETE FROM projections.project_grant_members3 WHERE (instance_id = $1) AND (project_id = $2)", expectedArgs: []interface{}{ "instance-id", "agg-id", @@ -232,7 +259,7 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_grant_members2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.project_grant_members3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -241,33 +268,6 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { }, }, }, - { - name: "project ProjectRemovedEventType", - args: args{ - event: getEvent(testEvent( - repository.EventType(project.ProjectRemovedType), - project.AggregateType, - []byte(`{}`), - ), project.ProjectRemovedEventMapper), - }, - reduce: (&projectGrantMemberProjection{}).reduceProjectRemoved, - want: wantReduce{ - aggregateType: project.AggregateType, - sequence: 15, - previousSequence: 10, - executer: &testExecuter{ - executions: []execution{ - { - expectedStmt: "DELETE FROM projections.project_grant_members2 WHERE (instance_id = $1) AND (project_id = $2)", - expectedArgs: []interface{}{ - "instance-id", - "agg-id", - }, - }, - }, - }, - }, - }, { name: "project GrantRemovedEventType", args: args{ @@ -285,7 +285,7 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_grant_members2 WHERE (instance_id = $1) AND (grant_id = $2) AND (project_id = $3)", + expectedStmt: "DELETE FROM projections.project_grant_members3 WHERE (instance_id = $1) AND (grant_id = $2) AND (project_id = $3)", expectedArgs: []interface{}{ "instance-id", "grant-id", @@ -296,6 +296,56 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) { }, }, }, + { + name: "org OrgRemovedEventType", + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + []byte(`{}`), + ), org.OrgRemovedEventMapper), + }, + reduce: (&projectGrantMemberProjection{}).reduceOrgRemoved, + want: wantReduce{ + aggregateType: org.AggregateType, + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.project_grant_members3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + { + expectedStmt: "UPDATE projections.project_grant_members3 SET (change_date, sequence, user_owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + { + expectedStmt: "UPDATE projections.project_grant_members3 SET (change_date, sequence, granted_org_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (granted_org = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/project_grant_test.go b/internal/query/projection/project_grant_test.go index eba503e607..0c4af2f093 100644 --- a/internal/query/projection/project_grant_test.go +++ b/internal/query/projection/project_grant_test.go @@ -10,6 +10,7 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/project" ) @@ -40,7 +41,7 @@ func TestProjectGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_grants2 WHERE (project_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.project_grants3 WHERE (project_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -67,7 +68,7 @@ func TestProjectGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_grants2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.project_grants3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -93,7 +94,7 @@ func TestProjectGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_grants2 WHERE (grant_id = $1) AND (project_id = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.project_grants3 WHERE (grant_id = $1) AND (project_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "grant-id", "agg-id", @@ -121,7 +122,7 @@ func TestProjectGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.project_grants2 SET (change_date, sequence, state) = ($1, $2, $3) WHERE (grant_id = $4) AND (project_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.project_grants3 SET (change_date, sequence, state) = ($1, $2, $3) WHERE (grant_id = $4) AND (project_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -152,7 +153,7 @@ func TestProjectGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.project_grants2 SET (change_date, sequence, state) = ($1, $2, $3) WHERE (grant_id = $4) AND (project_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.project_grants3 SET (change_date, sequence, state) = ($1, $2, $3) WHERE (grant_id = $4) AND (project_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -183,7 +184,7 @@ func TestProjectGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.project_grants2 SET (change_date, sequence, granted_role_keys) = ($1, $2, $3) WHERE (grant_id = $4) AND (project_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.project_grants3 SET (change_date, sequence, granted_role_keys) = ($1, $2, $3) WHERE (grant_id = $4) AND (project_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -214,7 +215,7 @@ func TestProjectGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.project_grants2 SET (change_date, sequence, granted_role_keys) = ($1, $2, $3) WHERE (grant_id = $4) AND (project_id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.project_grants3 SET (change_date, sequence, granted_role_keys) = ($1, $2, $3) WHERE (grant_id = $4) AND (project_id = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -245,7 +246,7 @@ func TestProjectGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.project_grants2 (grant_id, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence, granted_org_id, granted_role_keys) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.project_grants3 (grant_id, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence, granted_org_id, granted_role_keys) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ "grant-id", "agg-id", @@ -263,6 +264,46 @@ func TestProjectGrantProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&projectGrantProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.project_grants3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + { + expectedStmt: "UPDATE projections.project_grants3 SET (change_date, sequence, granted_org_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (granted_org_id = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/project_member.go b/internal/query/projection/project_member.go index 8986cebae6..4039f82846 100644 --- a/internal/query/projection/project_member.go +++ b/internal/query/projection/project_member.go @@ -15,7 +15,7 @@ import ( ) const ( - ProjectMemberProjectionTable = "projections.project_members2" + ProjectMemberProjectionTable = "projections.project_members3" ProjectMemberProjectIDCol = "project_id" ) @@ -33,7 +33,9 @@ func newProjectMemberProjection(ctx context.Context, config crdb.StatementHandle crdb.NewColumn(ProjectMemberProjectIDCol, crdb.ColumnTypeText), ), crdb.NewPrimaryKey(MemberInstanceID, ProjectMemberProjectIDCol, MemberUserIDCol), - crdb.WithIndex(crdb.NewIndex("proj_memb_user_idx", []string{MemberUserIDCol})), + crdb.WithIndex(crdb.NewIndex("user_id", []string{MemberUserIDCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{MemberOwnerRemoved})), + crdb.WithIndex(crdb.NewIndex("user_owner_removed", []string{MemberUserOwnerRemoved})), ), ) @@ -103,8 +105,14 @@ func (p *projectMemberProjection) reduceAdded(event eventstore.Event) (*handler. if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-bgx5Q", "reduce.wrong.event.type %s", project.MemberAddedType) } + ctx := setMemberContext(e.Aggregate()) + userOwner, err := getResourceOwnerOfUser(ctx, p.Eventstore, e.Aggregate().InstanceID, e.UserID) + if err != nil { + return nil, err + } return reduceMemberAdded( *member.NewMemberAddedEvent(&e.BaseEvent, e.UserID, e.Roles...), + userOwner, withMemberCol(ProjectMemberProjectIDCol, e.Aggregate().ID), ) } @@ -151,15 +159,15 @@ func (p *projectMemberProjection) reduceUserRemoved(event eventstore.Event) (*ha } func (p *projectMemberProjection) reduceOrgRemoved(event eventstore.Event) (*handler.Statement, error) { - //TODO: as soon as org deletion is implemented: - // Case: The user has resource owner A and project has resource owner B - // if org B deleted it works - // if org A is deleted, the membership wouldn't be deleted e, ok := event.(*org.OrgRemovedEvent) if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-NGUEL", "reduce.wrong.event.type %s", org.OrgRemovedEventType) } - return reduceMemberRemoved(e, withMemberCond(MemberResourceOwner, e.Aggregate().ID)) + return crdb.NewMultiStatement( + e, + multiReduceMemberOwnerRemoved(e), + multiReduceMemberUserOwnerRemoved(e), + ), nil } func (p *projectMemberProjection) reduceProjectRemoved(event eventstore.Event) (*handler.Statement, error) { diff --git a/internal/query/projection/project_member_test.go b/internal/query/projection/project_member_test.go index a2fddaf14e..698cc34b1d 100644 --- a/internal/query/projection/project_member_test.go +++ b/internal/query/projection/project_member_test.go @@ -1,9 +1,13 @@ package projection import ( + "context" "testing" + "golang.org/x/text/language" + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler" @@ -36,7 +40,21 @@ func TestProjectMemberProjection_reduces(t *testing.T) { }`), ), project.MemberAddedEventMapper), }, - reduce: (&projectMemberProjection{}).reduceAdded, + reduce: (&projectMemberProjection{ + StatementHandler: getStatementHandlerWithFilters( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user-id", "org1").Aggregate, + "username1", + "firstname1", + "lastname1", + "nickname1", + "displayname1", + language.German, + domain.GenderMale, + "email1", + true, + ), + )(t)}).reduceAdded, want: wantReduce{ aggregateType: project.AggregateType, sequence: 15, @@ -44,15 +62,18 @@ func TestProjectMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.project_members2 (user_id, roles, creation_date, change_date, sequence, resource_owner, instance_id, project_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.project_members3 (user_id, user_resource_owner, user_owner_removed, roles, creation_date, change_date, sequence, resource_owner, instance_id, owner_removed, project_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "user-id", + "org1", + false, database.StringArray{"role"}, anyArg{}, anyArg{}, uint64(15), "ro-id", "instance-id", + false, "agg-id", }, }, @@ -80,7 +101,7 @@ func TestProjectMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.project_members2 SET (roles, change_date, sequence) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_id = $5) AND (project_id = $6)", + expectedStmt: "UPDATE projections.project_members3 SET (roles, change_date, sequence) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_id = $5) AND (project_id = $6)", expectedArgs: []interface{}{ database.StringArray{"role", "changed"}, anyArg{}, @@ -113,7 +134,7 @@ func TestProjectMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_members2 WHERE (instance_id = $1) AND (user_id = $2) AND (project_id = $3)", + expectedStmt: "DELETE FROM projections.project_members3 WHERE (instance_id = $1) AND (user_id = $2) AND (project_id = $3)", expectedArgs: []interface{}{ "instance-id", "user-id", @@ -143,7 +164,7 @@ func TestProjectMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_members2 WHERE (instance_id = $1) AND (user_id = $2) AND (project_id = $3)", + expectedStmt: "DELETE FROM projections.project_members3 WHERE (instance_id = $1) AND (user_id = $2) AND (project_id = $3)", expectedArgs: []interface{}{ "instance-id", "user-id", @@ -171,7 +192,7 @@ func TestProjectMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_members2 WHERE (instance_id = $1) AND (user_id = $2)", + expectedStmt: "DELETE FROM projections.project_members3 WHERE (instance_id = $1) AND (user_id = $2)", expectedArgs: []interface{}{ "instance-id", "agg-id", @@ -182,23 +203,23 @@ func TestProjectMemberProjection_reduces(t *testing.T) { }, }, { - name: "org OrgRemovedEventType", + name: "project ProjectRemovedEventType", args: args{ event: getEvent(testEvent( - repository.EventType(org.OrgRemovedEventType), - org.AggregateType, + repository.EventType(project.ProjectRemovedType), + project.AggregateType, []byte(`{}`), - ), org.OrgRemovedEventMapper), + ), project.ProjectRemovedEventMapper), }, - reduce: (&projectMemberProjection{}).reduceOrgRemoved, + reduce: (&projectMemberProjection{}).reduceProjectRemoved, want: wantReduce{ - aggregateType: org.AggregateType, + aggregateType: project.AggregateType, sequence: 15, previousSequence: 10, executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_members2 WHERE (instance_id = $1) AND (resource_owner = $2)", + expectedStmt: "DELETE FROM projections.project_members3 WHERE (instance_id = $1) AND (project_id = $2)", expectedArgs: []interface{}{ "instance-id", "agg-id", @@ -225,7 +246,7 @@ func TestProjectMemberProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_members2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.project_members3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -235,24 +256,37 @@ func TestProjectMemberProjection_reduces(t *testing.T) { }, }, { - name: "project ProjectRemovedEventType", + name: "org OrgRemovedEventType", args: args{ event: getEvent(testEvent( - repository.EventType(project.ProjectRemovedType), - project.AggregateType, + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, []byte(`{}`), - ), project.ProjectRemovedEventMapper), + ), org.OrgRemovedEventMapper), }, - reduce: (&projectMemberProjection{}).reduceProjectRemoved, + reduce: (&projectMemberProjection{}).reduceOrgRemoved, want: wantReduce{ - aggregateType: project.AggregateType, + aggregateType: org.AggregateType, sequence: 15, previousSequence: 10, executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_members2 WHERE (instance_id = $1) AND (project_id = $2)", + expectedStmt: "UPDATE projections.project_members3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + { + expectedStmt: "UPDATE projections.project_members3 SET (change_date, sequence, user_owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (user_resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, "instance-id", "agg-id", }, diff --git a/internal/query/projection/project_role.go b/internal/query/projection/project_role.go index e44f69212a..5ee96e9e73 100644 --- a/internal/query/projection/project_role.go +++ b/internal/query/projection/project_role.go @@ -8,11 +8,12 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/project" ) const ( - ProjectRoleProjectionTable = "projections.project_roles" + ProjectRoleProjectionTable = "projections.project_roles3" ProjectRoleColumnProjectID = "project_id" ProjectRoleColumnKey = "role_key" @@ -23,6 +24,7 @@ const ( ProjectRoleColumnInstanceID = "instance_id" ProjectRoleColumnDisplayName = "display_name" ProjectRoleColumnGroupName = "group_name" + ProjectRoleColumnOwnerRemoved = "owner_removed" ) type projectRoleProjection struct { @@ -44,8 +46,10 @@ func newProjectRoleProjection(ctx context.Context, config crdb.StatementHandlerC crdb.NewColumn(ProjectRoleColumnInstanceID, crdb.ColumnTypeText), crdb.NewColumn(ProjectRoleColumnDisplayName, crdb.ColumnTypeText), crdb.NewColumn(ProjectRoleColumnGroupName, crdb.ColumnTypeText), + crdb.NewColumn(ProjectRoleColumnOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(ProjectRoleColumnInstanceID, ProjectRoleColumnProjectID, ProjectRoleColumnKey), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{ProjectRoleColumnOwnerRemoved})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -75,6 +79,15 @@ func (p *projectRoleProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, + }, + }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ @@ -164,3 +177,23 @@ func (p *projectRoleProjection) reduceProjectRemoved(event eventstore.Event) (*h }, ), nil } + +func (p *projectRoleProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-3XrHY", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(ProjectRoleColumnChangeDate, e.CreationDate()), + handler.NewCol(ProjectRoleColumnSequence, e.Sequence()), + handler.NewCol(ProjectRoleColumnOwnerRemoved, true), + }, + []handler.Condition{ + handler.NewCond(ProjectRoleColumnInstanceID, e.Aggregate().InstanceID), + handler.NewCond(ProjectRoleColumnResourceOwner, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/project_role_test.go b/internal/query/projection/project_role_test.go index 987145dffe..201c73e686 100644 --- a/internal/query/projection/project_role_test.go +++ b/internal/query/projection/project_role_test.go @@ -8,6 +8,7 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/project" ) @@ -38,7 +39,7 @@ func TestProjectRoleProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_roles WHERE (project_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.project_roles3 WHERE (project_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -65,7 +66,7 @@ func TestProjectRoleProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_roles WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.project_roles3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -91,7 +92,7 @@ func TestProjectRoleProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.project_roles WHERE (role_key = $1) AND (project_id = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.project_roles3 WHERE (role_key = $1) AND (project_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "key", "agg-id", @@ -119,7 +120,7 @@ func TestProjectRoleProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.project_roles SET (change_date, sequence, display_name, group_name) = ($1, $2, $3, $4) WHERE (role_key = $5) AND (project_id = $6) AND (instance_id = $7)", + expectedStmt: "UPDATE projections.project_roles3 SET (change_date, sequence, display_name, group_name) = ($1, $2, $3, $4) WHERE (role_key = $5) AND (project_id = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -168,7 +169,7 @@ func TestProjectRoleProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.project_roles (role_key, project_id, creation_date, change_date, resource_owner, instance_id, sequence, display_name, group_name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.project_roles3 (role_key, project_id, creation_date, change_date, resource_owner, instance_id, sequence, display_name, group_name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "key", "agg-id", @@ -185,6 +186,36 @@ func TestProjectRoleProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&projectRoleProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.project_roles3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/project_test.go b/internal/query/projection/project_test.go index e2983ad328..3ad1f18e09 100644 --- a/internal/query/projection/project_test.go +++ b/internal/query/projection/project_test.go @@ -9,6 +9,7 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/project" ) @@ -39,7 +40,7 @@ func TestProjectProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.projects2 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.projects3 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -66,7 +67,7 @@ func TestProjectProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.projects2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.projects3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -92,7 +93,7 @@ func TestProjectProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.projects2 SET (change_date, sequence, state) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.projects3 SET (change_date, sequence, state) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -122,7 +123,7 @@ func TestProjectProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.projects2 SET (change_date, sequence, state) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.projects3 SET (change_date, sequence, state) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -152,7 +153,7 @@ func TestProjectProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.projects2 SET (change_date, sequence, name, project_role_assertion, project_role_check, has_project_check, private_labeling_setting) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (instance_id = $9)", + expectedStmt: "UPDATE projections.projects3 SET (change_date, sequence, name, project_role_assertion, project_role_check, has_project_check, private_labeling_setting) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (instance_id = $9)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -203,7 +204,7 @@ func TestProjectProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.projects2 (id, creation_date, change_date, resource_owner, instance_id, sequence, name, project_role_assertion, project_role_check, has_project_check, private_labeling_setting, state) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)", + expectedStmt: "INSERT INTO projections.projects3 (id, creation_date, change_date, resource_owner, instance_id, sequence, name, project_role_assertion, project_role_check, has_project_check, private_labeling_setting, state) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)", expectedArgs: []interface{}{ "agg-id", anyArg{}, @@ -223,6 +224,36 @@ func TestProjectProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&projectProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.projects3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/query/projection/sms.go b/internal/query/projection/sms.go index 886d8d9658..b2da5df130 100644 --- a/internal/query/projection/sms.go +++ b/internal/query/projection/sms.go @@ -12,7 +12,7 @@ import ( ) const ( - SMSConfigProjectionTable = "projections.sms_configs" + SMSConfigProjectionTable = "projections.sms_configs2" SMSTwilioTable = SMSConfigProjectionTable + "_" + smsTwilioTableSuffix SMSColumnID = "id" @@ -51,7 +51,7 @@ func newSMSConfigProjection(ctx context.Context, config crdb.StatementHandlerCon crdb.NewColumn(SMSColumnResourceOwner, crdb.ColumnTypeText), crdb.NewColumn(SMSColumnInstanceID, crdb.ColumnTypeText), }, - crdb.NewPrimaryKey(SMSColumnID, SMSColumnInstanceID), + crdb.NewPrimaryKey(SMSColumnInstanceID, SMSColumnID), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(SMSTwilioConfigColumnSMSID, crdb.ColumnTypeText), @@ -60,9 +60,9 @@ func newSMSConfigProjection(ctx context.Context, config crdb.StatementHandlerCon crdb.NewColumn(SMSTwilioConfigColumnSenderNumber, crdb.ColumnTypeText), crdb.NewColumn(SMSTwilioConfigColumnToken, crdb.ColumnTypeJSONB), }, - crdb.NewPrimaryKey(SMSTwilioConfigColumnSMSID, SMSTwilioColumnInstanceID), + crdb.NewPrimaryKey(SMSTwilioColumnInstanceID, SMSTwilioConfigColumnSMSID), smsTwilioTableSuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_twilio_ref_sms")), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) diff --git a/internal/query/projection/sms_test.go b/internal/query/projection/sms_test.go index 6863a9d3d2..17ce2bec32 100644 --- a/internal/query/projection/sms_test.go +++ b/internal/query/projection/sms_test.go @@ -49,7 +49,7 @@ func TestSMSProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.sms_configs (id, aggregate_id, creation_date, change_date, resource_owner, instance_id, state, sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", + expectedStmt: "INSERT INTO projections.sms_configs2 (id, aggregate_id, creation_date, change_date, resource_owner, instance_id, state, sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", expectedArgs: []interface{}{ "id", "agg-id", @@ -62,7 +62,7 @@ func TestSMSProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.sms_configs_twilio (sms_id, instance_id, sid, token, sender_number) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.sms_configs2_twilio (sms_id, instance_id, sid, token, sender_number) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "id", "instance-id", @@ -101,7 +101,7 @@ func TestSMSProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.sms_configs_twilio SET (sid, sender_number) = ($1, $2) WHERE (sms_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.sms_configs2_twilio SET (sid, sender_number) = ($1, $2) WHERE (sms_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "sid", "sender-number", @@ -110,7 +110,7 @@ func TestSMSProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.sms_configs SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.sms_configs2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -147,7 +147,7 @@ func TestSMSProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.sms_configs_twilio SET token = $1 WHERE (sms_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.sms_configs2_twilio SET token = $1 WHERE (sms_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ &crypto.CryptoValue{ CryptoType: crypto.TypeEncryption, @@ -160,7 +160,7 @@ func TestSMSProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.sms_configs SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.sms_configs2 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -191,7 +191,7 @@ func TestSMSProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.sms_configs SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.sms_configs2 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ domain.SMSConfigStateActive, anyArg{}, @@ -223,7 +223,7 @@ func TestSMSProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.sms_configs SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.sms_configs2 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ domain.SMSConfigStateInactive, anyArg{}, @@ -255,7 +255,7 @@ func TestSMSProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.sms_configs WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.sms_configs2 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "id", "instance-id", @@ -282,7 +282,7 @@ func TestSMSProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.sms_configs WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.sms_configs2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/user.go b/internal/query/projection/user.go index ed890ea45d..c6c2f4de1e 100644 --- a/internal/query/projection/user.go +++ b/internal/query/projection/user.go @@ -10,6 +10,7 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/user" ) @@ -18,7 +19,7 @@ type userProjection struct { } const ( - UserTable = "projections.users5" + UserTable = "projections.users6" UserHumanTable = UserTable + "_" + UserHumanSuffix UserMachineTable = UserTable + "_" + UserMachineSuffix UserNotifyTable = UserTable + "_" + UserNotifySuffix @@ -32,6 +33,7 @@ const ( UserInstanceIDCol = "instance_id" UserUsernameCol = "username" UserTypeCol = "type" + UserOwnerRemovedCol = "owner_removed" UserHumanSuffix = "humans" HumanUserIDCol = "user_id" @@ -87,10 +89,12 @@ func newUserProjection(ctx context.Context, config crdb.StatementHandlerConfig) crdb.NewColumn(UserInstanceIDCol, crdb.ColumnTypeText), crdb.NewColumn(UserUsernameCol, crdb.ColumnTypeText), crdb.NewColumn(UserTypeCol, crdb.ColumnTypeEnum), + crdb.NewColumn(UserOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, - crdb.NewPrimaryKey(UserIDCol, UserInstanceIDCol), - crdb.WithIndex(crdb.NewIndex("username_idx5", []string{UserUsernameCol})), - crdb.WithIndex(crdb.NewIndex("user_ro_idx5", []string{UserResourceOwnerCol})), + crdb.NewPrimaryKey(UserInstanceIDCol, UserIDCol), + crdb.WithIndex(crdb.NewIndex("username", []string{UserUsernameCol})), + crdb.WithIndex(crdb.NewIndex("resource_owner", []string{UserResourceOwnerCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{UserOwnerRemovedCol})), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(HumanUserIDCol, crdb.ColumnTypeText), @@ -107,9 +111,9 @@ func newUserProjection(ctx context.Context, config crdb.StatementHandlerConfig) crdb.NewColumn(HumanPhoneCol, crdb.ColumnTypeText, crdb.Nullable()), crdb.NewColumn(HumanIsPhoneVerifiedCol, crdb.ColumnTypeBool, crdb.Nullable()), }, - crdb.NewPrimaryKey(HumanUserIDCol, HumanUserInstanceIDCol), + crdb.NewPrimaryKey(HumanUserInstanceIDCol, HumanUserIDCol), UserHumanSuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_human_ref_user5")), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(MachineUserIDCol, crdb.ColumnTypeText), @@ -117,9 +121,9 @@ func newUserProjection(ctx context.Context, config crdb.StatementHandlerConfig) crdb.NewColumn(MachineNameCol, crdb.ColumnTypeText), crdb.NewColumn(MachineDescriptionCol, crdb.ColumnTypeText, crdb.Nullable()), }, - crdb.NewPrimaryKey(MachineUserIDCol, MachineUserInstanceIDCol), + crdb.NewPrimaryKey(MachineUserInstanceIDCol, MachineUserIDCol), UserMachineSuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_machine_ref_user5")), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), ), crdb.NewSuffixedTable([]*crdb.Column{ crdb.NewColumn(NotifyUserIDCol, crdb.ColumnTypeText), @@ -130,9 +134,9 @@ func newUserProjection(ctx context.Context, config crdb.StatementHandlerConfig) crdb.NewColumn(NotifyVerifiedPhoneCol, crdb.ColumnTypeText, crdb.Nullable()), crdb.NewColumn(NotifyPasswordSetCol, crdb.ColumnTypeBool, crdb.Default(false)), }, - crdb.NewPrimaryKey(NotifyUserIDCol, NotifyInstanceIDCol), + crdb.NewPrimaryKey(NotifyInstanceIDCol, NotifyUserIDCol), UserNotifySuffix, - crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_notify_ref_user5")), + crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -274,6 +278,15 @@ func (p *userProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, + }, + }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ @@ -965,4 +978,25 @@ func (p *userProjection) reduceMachineChanged(event eventstore.Event) (*handler. crdb.WithTableSuffix(UserMachineSuffix), ), ), nil + +} + +func (p *userProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-NCsdV", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(UserChangeDateCol, e.CreationDate()), + handler.NewCol(UserSequenceCol, e.Sequence()), + handler.NewCol(UserOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(UserInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(UserResourceOwnerCol, e.Aggregate().ID), + }, + ), nil } diff --git a/internal/query/projection/user_auth_method.go b/internal/query/projection/user_auth_method.go index a551a7217e..ee6f92a404 100644 --- a/internal/query/projection/user_auth_method.go +++ b/internal/query/projection/user_auth_method.go @@ -9,11 +9,12 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/user" ) const ( - UserAuthMethodTable = "projections.user_auth_methods3" + UserAuthMethodTable = "projections.user_auth_methods4" UserAuthMethodUserIDCol = "user_id" UserAuthMethodTypeCol = "method_type" @@ -25,6 +26,7 @@ const ( UserAuthMethodInstanceIDCol = "instance_id" UserAuthMethodStateCol = "state" UserAuthMethodNameCol = "name" + UserAuthMethodOwnerRemovedCol = "owner_removed" ) type userAuthMethodProjection struct { @@ -47,9 +49,11 @@ func newUserAuthMethodProjection(ctx context.Context, config crdb.StatementHandl crdb.NewColumn(UserAuthMethodResourceOwnerCol, crdb.ColumnTypeText), crdb.NewColumn(UserAuthMethodInstanceIDCol, crdb.ColumnTypeText), crdb.NewColumn(UserAuthMethodNameCol, crdb.ColumnTypeText), + crdb.NewColumn(UserAuthMethodOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(UserAuthMethodInstanceIDCol, UserAuthMethodUserIDCol, UserAuthMethodTypeCol, UserAuthMethodTokenIDCol), - crdb.WithIndex(crdb.NewIndex("auth_meth_ro_idx", []string{UserAuthMethodResourceOwnerCol})), + crdb.WithIndex(crdb.NewIndex("resource_owner", []string{UserAuthMethodResourceOwnerCol})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{UserAuthMethodOwnerRemovedCol})), ), ) p.StatementHandler = crdb.NewStatementHandler(ctx, config) @@ -99,6 +103,15 @@ func (p *userAuthMethodProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, + }, + }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ @@ -219,3 +232,23 @@ func (p *userAuthMethodProjection) reduceRemoveAuthMethod(event eventstore.Event conditions, ), nil } + +func (p *userAuthMethodProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-FwDZ8", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(UserAuthMethodChangeDateCol, e.CreationDate()), + handler.NewCol(UserAuthMethodSequenceCol, e.Sequence()), + handler.NewCol(UserAuthMethodOwnerRemovedCol, true), + }, + []handler.Condition{ + handler.NewCond(UserAuthMethodInstanceIDCol, e.Aggregate().InstanceID), + handler.NewCond(UserAuthMethodResourceOwnerCol, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/user_auth_method_test.go b/internal/query/projection/user_auth_method_test.go index 0c87b821d0..252df8fe04 100644 --- a/internal/query/projection/user_auth_method_test.go +++ b/internal/query/projection/user_auth_method_test.go @@ -9,6 +9,7 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/user" ) @@ -41,7 +42,7 @@ func TestUserAuthMethodProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.user_auth_methods3 (token_id, creation_date, change_date, resource_owner, instance_id, user_id, sequence, state, method_type, name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (instance_id, user_id, method_type, token_id) DO UPDATE SET (creation_date, change_date, resource_owner, sequence, state, name) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.resource_owner, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.name)", + expectedStmt: "INSERT INTO projections.user_auth_methods4 (token_id, creation_date, change_date, resource_owner, instance_id, user_id, sequence, state, method_type, name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (instance_id, user_id, method_type, token_id) DO UPDATE SET (creation_date, change_date, resource_owner, sequence, state, name) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.resource_owner, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.name)", expectedArgs: []interface{}{ "token-id", anyArg{}, @@ -78,7 +79,7 @@ func TestUserAuthMethodProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.user_auth_methods3 (token_id, creation_date, change_date, resource_owner, instance_id, user_id, sequence, state, method_type, name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (instance_id, user_id, method_type, token_id) DO UPDATE SET (creation_date, change_date, resource_owner, sequence, state, name) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.resource_owner, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.name)", + expectedStmt: "INSERT INTO projections.user_auth_methods4 (token_id, creation_date, change_date, resource_owner, instance_id, user_id, sequence, state, method_type, name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (instance_id, user_id, method_type, token_id) DO UPDATE SET (creation_date, change_date, resource_owner, sequence, state, name) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.resource_owner, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.name)", expectedArgs: []interface{}{ "token-id", anyArg{}, @@ -114,7 +115,7 @@ func TestUserAuthMethodProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.user_auth_methods3 (token_id, creation_date, change_date, resource_owner, instance_id, user_id, sequence, state, method_type, name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (instance_id, user_id, method_type, token_id) DO UPDATE SET (creation_date, change_date, resource_owner, sequence, state, name) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.resource_owner, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.name)", + expectedStmt: "INSERT INTO projections.user_auth_methods4 (token_id, creation_date, change_date, resource_owner, instance_id, user_id, sequence, state, method_type, name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ON CONFLICT (instance_id, user_id, method_type, token_id) DO UPDATE SET (creation_date, change_date, resource_owner, sequence, state, name) = (EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.resource_owner, EXCLUDED.sequence, EXCLUDED.state, EXCLUDED.name)", expectedArgs: []interface{}{ "", anyArg{}, @@ -152,7 +153,7 @@ func TestUserAuthMethodProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.user_auth_methods3 SET (change_date, sequence, name, state) = ($1, $2, $3, $4) WHERE (user_id = $5) AND (method_type = $6) AND (resource_owner = $7) AND (token_id = $8) AND (instance_id = $9)", + expectedStmt: "UPDATE projections.user_auth_methods4 SET (change_date, sequence, name, state) = ($1, $2, $3, $4) WHERE (user_id = $5) AND (method_type = $6) AND (resource_owner = $7) AND (token_id = $8) AND (instance_id = $9)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -189,7 +190,7 @@ func TestUserAuthMethodProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.user_auth_methods3 SET (change_date, sequence, name, state) = ($1, $2, $3, $4) WHERE (user_id = $5) AND (method_type = $6) AND (resource_owner = $7) AND (token_id = $8) AND (instance_id = $9)", + expectedStmt: "UPDATE projections.user_auth_methods4 SET (change_date, sequence, name, state) = ($1, $2, $3, $4) WHERE (user_id = $5) AND (method_type = $6) AND (resource_owner = $7) AND (token_id = $8) AND (instance_id = $9)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -224,7 +225,7 @@ func TestUserAuthMethodProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.user_auth_methods3 SET (change_date, sequence, name, state) = ($1, $2, $3, $4) WHERE (user_id = $5) AND (method_type = $6) AND (resource_owner = $7) AND (token_id = $8) AND (instance_id = $9)", + expectedStmt: "UPDATE projections.user_auth_methods4 SET (change_date, sequence, name, state) = ($1, $2, $3, $4) WHERE (user_id = $5) AND (method_type = $6) AND (resource_owner = $7) AND (token_id = $8) AND (instance_id = $9)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -241,6 +242,36 @@ func TestUserAuthMethodProjection_reduces(t *testing.T) { }, }, }, + { + name: "org reduceOwnerRemoved", + reduce: (&userAuthMethodProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.user_auth_methods4 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, { name: "instance reduceInstanceRemoved", args: args{ @@ -258,7 +289,7 @@ func TestUserAuthMethodProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.user_auth_methods3 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.user_auth_methods4 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/user_grant.go b/internal/query/projection/user_grant.go index c8e2630119..d074e16e7a 100644 --- a/internal/query/projection/user_grant.go +++ b/internal/query/projection/user_grant.go @@ -3,6 +3,7 @@ package projection import ( "context" + "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/database" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" @@ -10,25 +11,33 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/user" "github.com/zitadel/zitadel/internal/repository/usergrant" ) const ( - UserGrantProjectionTable = "projections.user_grants2" + UserGrantProjectionTable = "projections.user_grants3" - UserGrantID = "id" - UserGrantCreationDate = "creation_date" - UserGrantChangeDate = "change_date" - UserGrantSequence = "sequence" - UserGrantState = "state" - UserGrantResourceOwner = "resource_owner" - UserGrantInstanceID = "instance_id" - UserGrantUserID = "user_id" - UserGrantProjectID = "project_id" - UserGrantGrantID = "grant_id" - UserGrantRoles = "roles" + UserGrantID = "id" + UserGrantCreationDate = "creation_date" + UserGrantChangeDate = "change_date" + UserGrantSequence = "sequence" + UserGrantState = "state" + UserGrantResourceOwner = "resource_owner" + UserGrantInstanceID = "instance_id" + UserGrantUserID = "user_id" + UserGrantResourceOwnerUser = "resource_owner_user" + UserGrantUserOwnerRemoved = "user_owner_removed" + UserGrantProjectID = "project_id" + UserGrantResourceOwnerProject = "resource_owner_project" + UserGrantProjectOwnerRemoved = "project_owner_removed" + UserGrantGrantID = "grant_id" + UserGrantGrantedOrg = "granted_org" + UserGrantGrantedOrgRemoved = "granted_org_removed" + UserGrantRoles = "roles" + UserGrantOwnerRemoved = "owner_removed" ) type userGrantProjection struct { @@ -49,13 +58,24 @@ func newUserGrantProjection(ctx context.Context, config crdb.StatementHandlerCon crdb.NewColumn(UserGrantResourceOwner, crdb.ColumnTypeText), crdb.NewColumn(UserGrantInstanceID, crdb.ColumnTypeText), crdb.NewColumn(UserGrantUserID, crdb.ColumnTypeText), + crdb.NewColumn(UserGrantResourceOwnerUser, crdb.ColumnTypeText), + crdb.NewColumn(UserGrantUserOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), crdb.NewColumn(UserGrantProjectID, crdb.ColumnTypeText), + crdb.NewColumn(UserGrantResourceOwnerProject, crdb.ColumnTypeText), + crdb.NewColumn(UserGrantProjectOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), crdb.NewColumn(UserGrantGrantID, crdb.ColumnTypeText), + crdb.NewColumn(UserGrantGrantedOrg, crdb.ColumnTypeText), + crdb.NewColumn(UserGrantGrantedOrgRemoved, crdb.ColumnTypeBool, crdb.Default(false)), crdb.NewColumn(UserGrantRoles, crdb.ColumnTypeTextArray, crdb.Nullable()), + crdb.NewColumn(UserGrantOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(UserGrantInstanceID, UserGrantID), - crdb.WithIndex(crdb.NewIndex("user_grant_user_idx", []string{UserGrantUserID})), - crdb.WithIndex(crdb.NewIndex("user_grant_ro_idx", []string{UserGrantResourceOwner})), + crdb.WithIndex(crdb.NewIndex("user_id", []string{UserGrantUserID})), + crdb.WithIndex(crdb.NewIndex("resource_owner", []string{UserGrantResourceOwner})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{UserGrantOwnerRemoved})), + crdb.WithIndex(crdb.NewIndex("user_owner_removed", []string{UserGrantUserOwnerRemoved})), + crdb.WithIndex(crdb.NewIndex("project_owner_removed", []string{UserGrantProjectOwnerRemoved})), + crdb.WithIndex(crdb.NewIndex("granted_org_removed", []string{UserGrantGrantedOrgRemoved})), ), ) @@ -132,6 +152,15 @@ func (p *userGrantProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, + }, + }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ @@ -149,6 +178,27 @@ func (p *userGrantProjection) reduceAdded(event eventstore.Event) (*handler.Stat if !ok { return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-MQHVB", "reduce.wrong.event.type %s", usergrant.UserGrantAddedType) } + + ctx := setUserGrantContext(e.Aggregate()) + userOwner, err := getResourceOwnerOfUser(ctx, p.Eventstore, e.Aggregate().InstanceID, e.UserID) + if err != nil { + return nil, err + } + + projectOwner := "" + grantOwner := "" + if e.ProjectGrantID != "" { + grantOwner, err = getGrantedOrgOfGrantedProject(ctx, p.Eventstore, e.Aggregate().InstanceID, e.ProjectID, e.ProjectGrantID) + if err != nil { + return nil, err + } + } else { + projectOwner, err = getResourceOwnerOfProject(ctx, p.Eventstore, e.Aggregate().InstanceID, e.ProjectID) + if err != nil { + return nil, err + } + } + return crdb.NewCreateStatement( e, []handler.Column{ @@ -159,8 +209,11 @@ func (p *userGrantProjection) reduceAdded(event eventstore.Event) (*handler.Stat handler.NewCol(UserGrantChangeDate, e.CreationDate()), handler.NewCol(UserGrantSequence, e.Sequence()), handler.NewCol(UserGrantUserID, e.UserID), + handler.NewCol(UserGrantResourceOwnerUser, userOwner), handler.NewCol(UserGrantProjectID, e.ProjectID), + handler.NewCol(UserGrantResourceOwnerProject, projectOwner), handler.NewCol(UserGrantGrantID, e.ProjectGrantID), + handler.NewCol(UserGrantGrantedOrg, grantOwner), handler.NewCol(UserGrantRoles, database.StringArray(e.RoleKeys)), handler.NewCol(UserGrantState, domain.UserGrantStateActive), }, @@ -334,3 +387,129 @@ func (p *userGrantProjection) reduceProjectGrantChanged(event eventstore.Event) }, ), nil } + +func (p *userGrantProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-jpIvp", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewMultiStatement( + e, + crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(UserGrantChangeDate, e.CreationDate()), + handler.NewCol(UserGrantSequence, e.Sequence()), + handler.NewCol(UserGrantOwnerRemoved, true), + }, + []handler.Condition{ + handler.NewCond(UserGrantInstanceID, e.Aggregate().InstanceID), + handler.NewCond(UserGrantResourceOwner, e.Aggregate().ID), + }, + ), + crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(UserGrantChangeDate, e.CreationDate()), + handler.NewCol(UserGrantSequence, e.Sequence()), + handler.NewCol(UserGrantUserOwnerRemoved, true), + }, + []handler.Condition{ + handler.NewCond(UserGrantInstanceID, e.Aggregate().InstanceID), + handler.NewCond(UserGrantResourceOwnerUser, e.Aggregate().ID), + }, + ), + crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(UserGrantChangeDate, e.CreationDate()), + handler.NewCol(UserGrantSequence, e.Sequence()), + handler.NewCol(UserGrantProjectOwnerRemoved, true), + }, + []handler.Condition{ + handler.NewCond(UserGrantInstanceID, e.Aggregate().InstanceID), + handler.NewCond(UserGrantResourceOwnerProject, e.Aggregate().ID), + }, + ), + crdb.AddUpdateStatement( + []handler.Column{ + handler.NewCol(UserGrantChangeDate, e.CreationDate()), + handler.NewCol(UserGrantSequence, e.Sequence()), + handler.NewCol(UserGrantGrantedOrgRemoved, true), + }, + []handler.Condition{ + handler.NewCond(UserGrantInstanceID, e.Aggregate().InstanceID), + handler.NewCond(UserGrantGrantedOrg, e.Aggregate().ID), + }, + ), + ), nil +} + +func getResourceOwnerOfUser(ctx context.Context, es *eventstore.Eventstore, instanceID, aggID string) (string, error) { + events, err := es.Filter( + ctx, + eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + InstanceID(instanceID). + AddQuery(). + AggregateTypes(user.AggregateType). + AggregateIDs(aggID). + EventTypes(user.HumanRegisteredType, user.HumanAddedType, user.MachineAddedEventType). + Builder(), + ) + if err != nil { + return "", err + } + if len(events) != 1 { + return "", errors.ThrowNotFound(nil, "PROJ-0I92sp", "Errors.User.NotFound") + } + return events[0].Aggregate().ResourceOwner, nil +} + +func getResourceOwnerOfProject(ctx context.Context, es *eventstore.Eventstore, instanceID, aggID string) (string, error) { + events, err := es.Filter( + ctx, + eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + InstanceID(instanceID). + AddQuery(). + AggregateTypes(project.AggregateType). + AggregateIDs(aggID). + EventTypes(project.ProjectAddedType). + Builder(), + ) + if err != nil { + return "", err + } + if len(events) != 1 { + return "", errors.ThrowNotFound(nil, "PROJ-0I91sp", "Errors.Project.NotFound") + } + return events[0].Aggregate().ResourceOwner, nil +} + +func getGrantedOrgOfGrantedProject(ctx context.Context, es *eventstore.Eventstore, instanceID, projectID, grantID string) (string, error) { + events, err := es.Filter( + ctx, + eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + InstanceID(instanceID). + AddQuery(). + AggregateTypes(project.AggregateType). + AggregateIDs(projectID). + EventTypes(project.GrantAddedType). + EventData(map[string]interface{}{ + "grantId": grantID, + }). + Builder(), + ) + if err != nil { + return "", err + } + if len(events) != 1 { + return "", errors.ThrowNotFound(nil, "PROJ-MoaSpw", "Errors.Grant.NotFound") + } + grantAddedEvent, ok := events[0].(*project.GrantAddedEvent) + if !ok { + return "", errors.ThrowNotFound(nil, "PROJ-P0s2o0", "Errors.Grant.NotFound") + } + return grantAddedEvent.GrantedOrgID, nil +} + +func setUserGrantContext(event eventstore.Aggregate) context.Context { + return authz.WithInstanceID(context.Background(), event.InstanceID) +} diff --git a/internal/query/projection/user_grant_test.go b/internal/query/projection/user_grant_test.go index bcff7cba2b..a3e1c49079 100644 --- a/internal/query/projection/user_grant_test.go +++ b/internal/query/projection/user_grant_test.go @@ -1,15 +1,20 @@ package projection import ( + "context" "testing" + "golang.org/x/text/language" + "github.com/zitadel/zitadel/internal/database" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "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/eventstore/repository" "github.com/zitadel/zitadel/internal/repository/instance" + "github.com/zitadel/zitadel/internal/repository/org" "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/user" "github.com/zitadel/zitadel/internal/repository/usergrant" @@ -38,7 +43,29 @@ func TestUserGrantProjection_reduces(t *testing.T) { }`), ), usergrant.UserGrantAddedEventMapper), }, - reduce: (&userGrantProjection{}).reduceAdded, + reduce: (&userGrantProjection{ + StatementHandler: getStatementHandlerWithFilters( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user-id", "org1").Aggregate, + "username1", + "firstname1", + "lastname1", + "nickname1", + "displayname1", + language.German, + domain.GenderMale, + "email1", + true, + ), + project.NewProjectAddedEvent(context.Background(), + &project.NewAggregate("project-id", "org2").Aggregate, + "project", + false, + false, + false, + domain.PrivateLabelingSettingUnspecified, + ), + )(t)}).reduceAdded, want: wantReduce{ aggregateType: usergrant.AggregateType, sequence: 15, @@ -46,7 +73,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.user_grants2 (id, resource_owner, instance_id, creation_date, change_date, sequence, user_id, project_id, grant_id, roles, state) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", + expectedStmt: "INSERT INTO projections.user_grants3 (id, resource_owner, instance_id, creation_date, change_date, sequence, user_id, resource_owner_user, project_id, resource_owner_project, grant_id, granted_org, roles, state) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)", expectedArgs: []interface{}{ "agg-id", "ro-id", @@ -55,8 +82,75 @@ func TestUserGrantProjection_reduces(t *testing.T) { anyArg{}, uint64(15), "user-id", + "org1", + "project-id", + "org2", + "", + "", + database.StringArray{"role"}, + domain.UserGrantStateActive, + }, + }, + }, + }, + }, + }, + { + name: "reduceAdded with projectgrant", + args: args{ + event: getEvent(testEvent( + repository.EventType(usergrant.UserGrantAddedType), + usergrant.AggregateType, + []byte(`{ + "userId": "user-id", + "projectId": "project-id", + "grantId": "grant-id", + "roleKeys": ["role"] + }`), + ), usergrant.UserGrantAddedEventMapper), + }, + reduce: (&userGrantProjection{ + StatementHandler: getStatementHandlerWithFilters( + user.NewHumanAddedEvent(context.Background(), + &user.NewAggregate("user-id", "org1").Aggregate, + "username1", + "firstname1", + "lastname1", + "nickname1", + "displayname1", + language.German, + domain.GenderMale, + "email1", + true, + ), + project.NewGrantAddedEvent(context.Background(), + &project.NewAggregate("project-id", "org2").Aggregate, + "grant-id", + "org3", + []string{}, + ), + )(t)}).reduceAdded, + want: wantReduce{ + aggregateType: usergrant.AggregateType, + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "INSERT INTO projections.user_grants3 (id, resource_owner, instance_id, creation_date, change_date, sequence, user_id, resource_owner_user, project_id, resource_owner_project, grant_id, granted_org, roles, state) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)", + expectedArgs: []interface{}{ + "agg-id", + "ro-id", + "instance-id", + anyArg{}, + anyArg{}, + uint64(15), + "user-id", + "org1", "project-id", "", + "grant-id", + "org3", database.StringArray{"role"}, domain.UserGrantStateActive, }, @@ -84,7 +178,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.user_grants2 SET (change_date, roles, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.user_grants3 SET (change_date, roles, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, database.StringArray{"role"}, @@ -116,7 +210,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.user_grants2 SET (change_date, roles, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.user_grants3 SET (change_date, roles, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, database.StringArray{"role"}, @@ -146,7 +240,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.user_grants2 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.user_grants3 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ anyArg{}, "instance-id", @@ -173,7 +267,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.user_grants2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.user_grants3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -199,7 +293,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.user_grants2 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.user_grants3 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ anyArg{}, "instance-id", @@ -226,7 +320,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.user_grants2 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.user_grants3 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, domain.UserGrantStateInactive, @@ -256,7 +350,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.user_grants2 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.user_grants3 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, domain.UserGrantStateActive, @@ -286,7 +380,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.user_grants2 WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.user_grants3 WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ anyArg{}, "instance-id", @@ -313,7 +407,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.user_grants2 WHERE (project_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.user_grants3 WHERE (project_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ anyArg{}, "instance-id", @@ -340,7 +434,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.user_grants2 WHERE (grant_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.user_grants3 WHERE (grant_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "grantID", "instance-id", @@ -367,7 +461,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.user_grants2 SET roles = array_remove(roles, $1) WHERE (project_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.user_grants3 SET roles = array_remove(roles, $1) WHERE (project_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "key", "agg-id", @@ -395,7 +489,7 @@ func TestUserGrantProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.user_grants2 SET (roles) = (SELECT ARRAY( SELECT UNNEST(roles) INTERSECT SELECT UNNEST ($1::TEXT[]))) WHERE (grant_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.user_grants3 SET (roles) = (SELECT ARRAY( SELECT UNNEST(roles) INTERSECT SELECT UNNEST ($1::TEXT[]))) WHERE (grant_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ database.StringArray{"key"}, "grantID", @@ -406,6 +500,66 @@ func TestUserGrantProjection_reduces(t *testing.T) { }, }, }, + { + name: "org.reduceOwnerRemoved", + reduce: (&userGrantProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.user_grants3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + { + expectedStmt: "UPDATE projections.user_grants3 SET (change_date, sequence, user_owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner_user = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + { + expectedStmt: "UPDATE projections.user_grants3 SET (change_date, sequence, project_owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner_project = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + { + expectedStmt: "UPDATE projections.user_grants3 SET (change_date, sequence, granted_org_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (granted_org = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -421,3 +575,29 @@ func TestUserGrantProjection_reduces(t *testing.T) { }) } } + +func getStatementHandlerWithFilters(events ...eventstore.Command) func(t *testing.T) crdb.StatementHandler { + filters := make([]expect, 0) + for _, event := range events { + filters = append(filters, + expectFilter( + eventFromEventPusher( + event, + ), + ), + ) + } + + return func(t *testing.T) crdb.StatementHandler { + return crdb.StatementHandler{ + ProjectionHandler: &handler.ProjectionHandler{ + Handler: handler.Handler{ + Eventstore: eventstoreExpect( + t, + filters..., + ), + }, + }, + } + } +} diff --git a/internal/query/projection/user_metadata.go b/internal/query/projection/user_metadata.go index 17f2e3c91f..b7513d2d07 100644 --- a/internal/query/projection/user_metadata.go +++ b/internal/query/projection/user_metadata.go @@ -8,11 +8,12 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/user" ) const ( - UserMetadataProjectionTable = "projections.user_metadata3" + UserMetadataProjectionTable = "projections.user_metadata4" UserMetadataColumnUserID = "user_id" UserMetadataColumnCreationDate = "creation_date" @@ -22,6 +23,7 @@ const ( UserMetadataColumnInstanceID = "instance_id" UserMetadataColumnKey = "key" UserMetadataColumnValue = "value" + UserMetadataColumnOwnerRemoved = "owner_removed" ) type userMetadataProjection struct { @@ -42,9 +44,11 @@ func newUserMetadataProjection(ctx context.Context, config crdb.StatementHandler crdb.NewColumn(UserMetadataColumnInstanceID, crdb.ColumnTypeText), crdb.NewColumn(UserMetadataColumnKey, crdb.ColumnTypeText), crdb.NewColumn(UserMetadataColumnValue, crdb.ColumnTypeBytes, crdb.Nullable()), + crdb.NewColumn(UserMetadataColumnOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(UserMetadataColumnInstanceID, UserMetadataColumnUserID, UserMetadataColumnKey), - crdb.WithIndex(crdb.NewIndex("usr_md_ro_idx", []string{UserGrantResourceOwner})), + crdb.WithIndex(crdb.NewIndex("resource_owner", []string{UserGrantResourceOwner})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{UserMetadataColumnOwnerRemoved})), ), ) @@ -75,6 +79,15 @@ func (p *userMetadataProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, + }, + }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ @@ -143,3 +156,23 @@ func (p *userMetadataProjection) reduceMetadataRemovedAll(event eventstore.Event }, ), nil } + +func (p *userMetadataProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-oqwul", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(UserMetadataColumnChangeDate, e.CreationDate()), + handler.NewCol(UserMetadataColumnSequence, e.Sequence()), + handler.NewCol(UserMetadataColumnOwnerRemoved, true), + }, + []handler.Condition{ + handler.NewCond(UserMetadataColumnInstanceID, e.Aggregate().InstanceID), + handler.NewCond(UserMetadataColumnResourceOwner, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/user_metadata_test.go b/internal/query/projection/user_metadata_test.go index 15324a2f6d..e115326f13 100644 --- a/internal/query/projection/user_metadata_test.go +++ b/internal/query/projection/user_metadata_test.go @@ -8,6 +8,7 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/user" ) @@ -41,7 +42,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.user_metadata3 (instance_id, user_id, key, resource_owner, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (instance_id, user_id, key) DO UPDATE SET (resource_owner, creation_date, change_date, sequence, value) = (EXCLUDED.resource_owner, EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)", + expectedStmt: "INSERT INTO projections.user_metadata4 (instance_id, user_id, key, resource_owner, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (instance_id, user_id, key) DO UPDATE SET (resource_owner, creation_date, change_date, sequence, value) = (EXCLUDED.resource_owner, EXCLUDED.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)", expectedArgs: []interface{}{ "instance-id", "agg-id", @@ -76,7 +77,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.user_metadata3 WHERE (user_id = $1) AND (key = $2) AND (instance_id = $3)", + expectedStmt: "DELETE FROM projections.user_metadata4 WHERE (user_id = $1) AND (key = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "agg-id", "key", @@ -104,7 +105,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.user_metadata3 WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.user_metadata4 WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -131,7 +132,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.user_metadata3 WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.user_metadata4 WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -141,6 +142,36 @@ func TestUserMetadataProjection_reduces(t *testing.T) { }, }, }, + { + name: "org reduceOwnerRemoved", + reduce: (&userMetadataProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.user_metadata4 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, { name: "instance reduceInstanceRemoved", args: args{ @@ -158,7 +189,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.user_metadata3 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.user_metadata4 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/user_personal_access_token.go b/internal/query/projection/user_personal_access_token.go index 2e91777a8e..e44624f725 100644 --- a/internal/query/projection/user_personal_access_token.go +++ b/internal/query/projection/user_personal_access_token.go @@ -9,11 +9,12 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/user" ) const ( - PersonalAccessTokenProjectionTable = "projections.personal_access_tokens2" + PersonalAccessTokenProjectionTable = "projections.personal_access_tokens3" PersonalAccessTokenColumnID = "id" PersonalAccessTokenColumnCreationDate = "creation_date" @@ -24,6 +25,7 @@ const ( PersonalAccessTokenColumnUserID = "user_id" PersonalAccessTokenColumnExpiration = "expiration" PersonalAccessTokenColumnScopes = "scopes" + PersonalAccessTokenColumnOwnerRemoved = "owner_removed" ) type personalAccessTokenProjection struct { @@ -45,10 +47,12 @@ func newPersonalAccessTokenProjection(ctx context.Context, config crdb.Statement crdb.NewColumn(PersonalAccessTokenColumnUserID, crdb.ColumnTypeText), crdb.NewColumn(PersonalAccessTokenColumnExpiration, crdb.ColumnTypeTimestamp), crdb.NewColumn(PersonalAccessTokenColumnScopes, crdb.ColumnTypeTextArray, crdb.Nullable()), + crdb.NewColumn(PersonalAccessTokenColumnOwnerRemoved, crdb.ColumnTypeBool, crdb.Default(false)), }, crdb.NewPrimaryKey(PersonalAccessTokenColumnInstanceID, PersonalAccessTokenColumnID), - crdb.WithIndex(crdb.NewIndex("pat_user_idx", []string{PersonalAccessTokenColumnUserID})), - crdb.WithIndex(crdb.NewIndex("pat_ro_idx", []string{PersonalAccessTokenColumnResourceOwner})), + crdb.WithIndex(crdb.NewIndex("user_id", []string{PersonalAccessTokenColumnUserID})), + crdb.WithIndex(crdb.NewIndex("resource_owner", []string{PersonalAccessTokenColumnResourceOwner})), + crdb.WithIndex(crdb.NewIndex("owner_removed", []string{PersonalAccessTokenColumnOwnerRemoved})), ), ) @@ -75,6 +79,15 @@ func (p *personalAccessTokenProjection) reducers() []handler.AggregateReducer { }, }, }, + { + Aggregate: org.AggregateType, + EventRedusers: []handler.EventReducer{ + { + Event: org.OrgRemovedEventType, + Reduce: p.reduceOwnerRemoved, + }, + }, + }, { Aggregate: instance.AggregateType, EventRedusers: []handler.EventReducer{ @@ -135,3 +148,23 @@ func (p *personalAccessTokenProjection) reduceUserRemoved(event eventstore.Event }, ), nil } + +func (p *personalAccessTokenProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*org.OrgRemovedEvent) + if !ok { + return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-zQVhl", "reduce.wrong.event.type %s", org.OrgRemovedEventType) + } + + return crdb.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(PersonalAccessTokenColumnChangeDate, e.CreationDate()), + handler.NewCol(PersonalAccessTokenColumnSequence, e.Sequence()), + handler.NewCol(PersonalAccessTokenColumnOwnerRemoved, true), + }, + []handler.Condition{ + handler.NewCond(PersonalAccessTokenColumnInstanceID, e.Aggregate().InstanceID), + handler.NewCond(PersonalAccessTokenColumnResourceOwner, e.Aggregate().ID), + }, + ), nil +} diff --git a/internal/query/projection/user_personal_access_token_test.go b/internal/query/projection/user_personal_access_token_test.go index 6a41404ade..778e03d221 100644 --- a/internal/query/projection/user_personal_access_token_test.go +++ b/internal/query/projection/user_personal_access_token_test.go @@ -10,6 +10,7 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/user" ) @@ -40,7 +41,7 @@ func TestPersonalAccessTokenProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.personal_access_tokens2 (id, creation_date, change_date, resource_owner, instance_id, sequence, user_id, expiration, scopes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.personal_access_tokens3 (id, creation_date, change_date, resource_owner, instance_id, sequence, user_id, expiration, scopes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "tokenID", anyArg{}, @@ -74,7 +75,7 @@ func TestPersonalAccessTokenProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.personal_access_tokens2 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.personal_access_tokens3 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "tokenID", "instance-id", @@ -101,7 +102,7 @@ func TestPersonalAccessTokenProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.personal_access_tokens2 WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.personal_access_tokens3 WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -111,6 +112,36 @@ func TestPersonalAccessTokenProjection_reduces(t *testing.T) { }, }, }, + { + name: "org reduceOwnerRemoved", + reduce: (&personalAccessTokenProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.personal_access_tokens3 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, { name: "instance reduceInstanceRemoved", args: args{ @@ -128,7 +159,7 @@ func TestPersonalAccessTokenProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.personal_access_tokens2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.personal_access_tokens3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/projection/user_test.go b/internal/query/projection/user_test.go index 57e60485d3..bc435b23a4 100644 --- a/internal/query/projection/user_test.go +++ b/internal/query/projection/user_test.go @@ -10,6 +10,7 @@ import ( "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" "github.com/zitadel/zitadel/internal/repository/user" ) @@ -50,7 +51,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users5 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.users6 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "agg-id", anyArg{}, @@ -64,7 +65,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.users6_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -79,7 +80,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users6_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -119,7 +120,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users5 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.users6 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "agg-id", anyArg{}, @@ -133,7 +134,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.users6_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -148,7 +149,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users6_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -183,7 +184,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users5 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.users6 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "agg-id", anyArg{}, @@ -197,7 +198,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.users6_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -212,7 +213,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users6_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -252,7 +253,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users5 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.users6 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "agg-id", anyArg{}, @@ -266,7 +267,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.users6_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -281,7 +282,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users6_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -321,7 +322,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users5 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.users6 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "agg-id", anyArg{}, @@ -335,7 +336,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.users6_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -350,7 +351,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users6_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -385,7 +386,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users5 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.users6 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "agg-id", anyArg{}, @@ -399,7 +400,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.users6_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -414,7 +415,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users6_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -444,7 +445,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ domain.UserStateInitial, "agg-id", @@ -472,7 +473,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ domain.UserStateInitial, "agg-id", @@ -500,7 +501,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ domain.UserStateActive, "agg-id", @@ -528,7 +529,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ domain.UserStateActive, "agg-id", @@ -556,7 +557,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users6 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, domain.UserStateLocked, @@ -586,7 +587,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users6 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, domain.UserStateActive, @@ -616,7 +617,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users6 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, domain.UserStateInactive, @@ -646,7 +647,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users6 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, domain.UserStateActive, @@ -676,7 +677,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.users5 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.users6 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -705,7 +706,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users6 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, "username", @@ -737,7 +738,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users6 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, "id@temporary.domain", @@ -774,7 +775,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -783,7 +784,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)", + expectedStmt: "UPDATE projections.users6_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)", expectedArgs: []interface{}{ "first-name", "last-name", @@ -823,7 +824,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -832,7 +833,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)", + expectedStmt: "UPDATE projections.users6_humans SET (first_name, last_name, nick_name, display_name, preferred_language, gender) = ($1, $2, $3, $4, $5, $6) WHERE (user_id = $7) AND (instance_id = $8)", expectedArgs: []interface{}{ "first-name", "last-name", @@ -867,7 +868,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -876,7 +877,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "+41 00 000 00 00", false, @@ -885,7 +886,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ &sql.NullString{String: "+41 00 000 00 00", Valid: true}, "agg-id", @@ -915,7 +916,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -924,7 +925,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "+41 00 000 00 00", false, @@ -933,7 +934,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ &sql.NullString{String: "+41 00 000 00 00", Valid: true}, "agg-id", @@ -961,7 +962,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -970,7 +971,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ nil, nil, @@ -979,7 +980,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ nil, nil, @@ -1008,7 +1009,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1017,7 +1018,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ nil, nil, @@ -1026,7 +1027,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ nil, nil, @@ -1055,7 +1056,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1064,7 +1065,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ true, "agg-id", @@ -1072,7 +1073,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "UPDATE projections.users6_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1099,7 +1100,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1108,7 +1109,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ true, "agg-id", @@ -1116,7 +1117,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "UPDATE projections.users6_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1145,7 +1146,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1154,7 +1155,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "email@zitadel.com", false, @@ -1163,7 +1164,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ &sql.NullString{String: "email@zitadel.com", Valid: true}, "agg-id", @@ -1193,7 +1194,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1202,7 +1203,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "email@zitadel.com", false, @@ -1211,7 +1212,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ &sql.NullString{String: "email@zitadel.com", Valid: true}, "agg-id", @@ -1239,7 +1240,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1248,7 +1249,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ true, "agg-id", @@ -1256,7 +1257,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "UPDATE projections.users6_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1283,7 +1284,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1292,7 +1293,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ true, "agg-id", @@ -1300,7 +1301,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "UPDATE projections.users6_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1329,7 +1330,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1338,7 +1339,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "users/agg-id/avatar", "agg-id", @@ -1366,7 +1367,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1375,7 +1376,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ nil, "agg-id", @@ -1406,7 +1407,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users5 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.users6 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "agg-id", anyArg{}, @@ -1420,7 +1421,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_machines (user_id, instance_id, name, description) VALUES ($1, $2, $3, $4)", + expectedStmt: "INSERT INTO projections.users6_machines (user_id, instance_id, name, description) VALUES ($1, $2, $3, $4)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1453,7 +1454,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users5 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", + expectedStmt: "INSERT INTO projections.users6 (id, creation_date, change_date, resource_owner, instance_id, state, sequence, username, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "agg-id", anyArg{}, @@ -1467,7 +1468,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users5_machines (user_id, instance_id, name, description) VALUES ($1, $2, $3, $4)", + expectedStmt: "INSERT INTO projections.users6_machines (user_id, instance_id, name, description) VALUES ($1, $2, $3, $4)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1499,7 +1500,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1508,7 +1509,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_machines SET (name, description) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6_machines SET (name, description) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "machine-name", "description", @@ -1539,7 +1540,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1548,7 +1549,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_machines SET name = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_machines SET name = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "machine-name", "agg-id", @@ -1578,7 +1579,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users5 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1587,7 +1588,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users5_machines SET description = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users6_machines SET description = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "description", "agg-id", @@ -1617,6 +1618,36 @@ func TestUserProjection_reduces(t *testing.T) { }, }, }, + { + name: "org reduceOwnerRemoved", + reduce: (&userProjection{}).reduceOwnerRemoved, + args: args{ + event: getEvent(testEvent( + repository.EventType(org.OrgRemovedEventType), + org.AggregateType, + nil, + ), org.OrgRemovedEventMapper), + }, + want: wantReduce{ + aggregateType: eventstore.AggregateType("org"), + sequence: 15, + previousSequence: 10, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.users6 SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + true, + "instance-id", + "agg-id", + }, + }, + }, + }, + }, + }, { name: "instance reduceInstanceRemoved", args: args{ @@ -1634,7 +1665,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.users5 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.users6 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/sms_test.go b/internal/query/sms_test.go index 2b9dac71c2..2964cfe574 100644 --- a/internal/query/sms_test.go +++ b/internal/query/sms_test.go @@ -14,37 +14,37 @@ import ( ) var ( - expectedSMSConfigQuery = regexp.QuoteMeta(`SELECT projections.sms_configs.id,` + - ` projections.sms_configs.aggregate_id,` + - ` projections.sms_configs.creation_date,` + - ` projections.sms_configs.change_date,` + - ` projections.sms_configs.resource_owner,` + - ` projections.sms_configs.state,` + - ` projections.sms_configs.sequence,` + + expectedSMSConfigQuery = regexp.QuoteMeta(`SELECT projections.sms_configs2.id,` + + ` projections.sms_configs2.aggregate_id,` + + ` projections.sms_configs2.creation_date,` + + ` projections.sms_configs2.change_date,` + + ` projections.sms_configs2.resource_owner,` + + ` projections.sms_configs2.state,` + + ` projections.sms_configs2.sequence,` + // twilio config - ` projections.sms_configs_twilio.sms_id,` + - ` projections.sms_configs_twilio.sid,` + - ` projections.sms_configs_twilio.token,` + - ` projections.sms_configs_twilio.sender_number` + - ` FROM projections.sms_configs` + - ` LEFT JOIN projections.sms_configs_twilio ON projections.sms_configs.id = projections.sms_configs_twilio.sms_id`) - expectedSMSConfigsQuery = regexp.QuoteMeta(`SELECT projections.sms_configs.id,` + - ` projections.sms_configs.aggregate_id,` + - ` projections.sms_configs.creation_date,` + - ` projections.sms_configs.change_date,` + - ` projections.sms_configs.resource_owner,` + - ` projections.sms_configs.state,` + - ` projections.sms_configs.sequence,` + + ` projections.sms_configs2_twilio.sms_id,` + + ` projections.sms_configs2_twilio.sid,` + + ` projections.sms_configs2_twilio.token,` + + ` projections.sms_configs2_twilio.sender_number` + + ` FROM projections.sms_configs2` + + ` LEFT JOIN projections.sms_configs2_twilio ON projections.sms_configs2.id = projections.sms_configs2_twilio.sms_id`) + expectedSMSConfigsQuery = regexp.QuoteMeta(`SELECT projections.sms_configs2.id,` + + ` projections.sms_configs2.aggregate_id,` + + ` projections.sms_configs2.creation_date,` + + ` projections.sms_configs2.change_date,` + + ` projections.sms_configs2.resource_owner,` + + ` projections.sms_configs2.state,` + + ` projections.sms_configs2.sequence,` + // twilio config - ` projections.sms_configs_twilio.sms_id,` + - ` projections.sms_configs_twilio.sid,` + - ` projections.sms_configs_twilio.token,` + - ` projections.sms_configs_twilio.sender_number,` + + ` projections.sms_configs2_twilio.sms_id,` + + ` projections.sms_configs2_twilio.sid,` + + ` projections.sms_configs2_twilio.token,` + + ` projections.sms_configs2_twilio.sender_number,` + ` COUNT(*) OVER ()` + - ` FROM projections.sms_configs` + - ` LEFT JOIN projections.sms_configs_twilio ON projections.sms_configs.id = projections.sms_configs_twilio.sms_id`) + ` FROM projections.sms_configs2` + + ` LEFT JOIN projections.sms_configs2_twilio ON projections.sms_configs2.id = projections.sms_configs2_twilio.sms_id`) smsConfigCols = []string{ "id", diff --git a/internal/query/user.go b/internal/query/user.go index 5b24f8dc87..2cd1828c89 100644 --- a/internal/query/user.go +++ b/internal/query/user.go @@ -162,20 +162,30 @@ var ( name: projection.UserTypeCol, table: userTable, } + UserOwnerRemovedCol = Column{ + name: projection.UserOwnerRemovedCol, + table: userTable, + } - userLoginNamesTable = loginNameTable.setAlias("login_names") - userLoginNamesUserIDCol = LoginNameUserIDCol.setTable(userLoginNamesTable) - userLoginNamesNameCol = LoginNameNameCol.setTable(userLoginNamesTable) - userLoginNamesInstanceIDCol = LoginNameInstanceIDCol.setTable(userLoginNamesTable) - userLoginNamesListCol = Column{ + userLoginNamesTable = loginNameTable.setAlias("login_names") + userLoginNamesUserIDCol = LoginNameUserIDCol.setTable(userLoginNamesTable) + userLoginNamesNameCol = LoginNameNameCol.setTable(userLoginNamesTable) + userLoginNamesInstanceIDCol = LoginNameInstanceIDCol.setTable(userLoginNamesTable) + userLoginNamesOwnerRemovedUserCol = LoginNameOwnerRemovedUserCol.setTable(userLoginNamesTable) + userLoginNamesOwnerRemovedPolicyCol = LoginNameOwnerRemovedPolicyCol.setTable(userLoginNamesTable) + userLoginNamesOwnerRemovedDomainCol = LoginNameOwnerRemovedDomainCol.setTable(userLoginNamesTable) + userLoginNamesListCol = Column{ name: "loginnames", table: userLoginNamesTable, } - userPreferredLoginNameTable = loginNameTable.setAlias("preferred_login_name") - userPreferredLoginNameUserIDCol = LoginNameUserIDCol.setTable(userPreferredLoginNameTable) - userPreferredLoginNameCol = LoginNameNameCol.setTable(userPreferredLoginNameTable) - userPreferredLoginNameIsPrimaryCol = LoginNameIsPrimaryCol.setTable(userPreferredLoginNameTable) - userPreferredLoginNameInstanceIDCol = LoginNameInstanceIDCol.setTable(userPreferredLoginNameTable) + userPreferredLoginNameTable = loginNameTable.setAlias("preferred_login_name") + userPreferredLoginNameUserIDCol = LoginNameUserIDCol.setTable(userPreferredLoginNameTable) + userPreferredLoginNameCol = LoginNameNameCol.setTable(userPreferredLoginNameTable) + userPreferredLoginNameIsPrimaryCol = LoginNameIsPrimaryCol.setTable(userPreferredLoginNameTable) + userPreferredLoginNameInstanceIDCol = LoginNameInstanceIDCol.setTable(userPreferredLoginNameTable) + userPreferredLoginNameOwnerRemovedUserCol = LoginNameOwnerRemovedUserCol.setTable(userPreferredLoginNameTable) + userPreferredLoginNameOwnerRemovedPolicyCol = LoginNameOwnerRemovedPolicyCol.setTable(userPreferredLoginNameTable) + userPreferredLoginNameOwnerRemovedDomainCol = LoginNameOwnerRemovedDomainCol.setTable(userPreferredLoginNameTable) ) var ( @@ -296,7 +306,17 @@ var ( } ) -func (q *Queries) GetUserByID(ctx context.Context, shouldTriggerBulk bool, userID string, queries ...SearchQuery) (*User, error) { +func addUserWithoutOwnerRemoved(eq map[string]interface{}) { + eq[UserOwnerRemovedCol.identifier()] = false + eq[userLoginNamesOwnerRemovedUserCol.identifier()] = false + eq[userLoginNamesOwnerRemovedPolicyCol.identifier()] = false + eq[userLoginNamesOwnerRemovedDomainCol.identifier()] = false + eq[userPreferredLoginNameOwnerRemovedUserCol.identifier()] = false + eq[userPreferredLoginNameOwnerRemovedPolicyCol.identifier()] = false + eq[userPreferredLoginNameOwnerRemovedDomainCol.identifier()] = false +} + +func (q *Queries) GetUserByID(ctx context.Context, shouldTriggerBulk bool, userID string, withOwnerRemoved bool, queries ...SearchQuery) (*User, error) { if shouldTriggerBulk { projection.UserProjection.Trigger(ctx) projection.LoginNameProjection.Trigger(ctx) @@ -306,10 +326,14 @@ func (q *Queries) GetUserByID(ctx context.Context, shouldTriggerBulk bool, userI for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where(sq.Eq{ + eq := sq.Eq{ UserIDCol.identifier(): userID, UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + } + if !withOwnerRemoved { + addUserWithoutOwnerRemoved(eq) + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-FBg21", "Errors.Query.SQLStatment") } @@ -318,7 +342,7 @@ func (q *Queries) GetUserByID(ctx context.Context, shouldTriggerBulk bool, userI return scan(row) } -func (q *Queries) GetUser(ctx context.Context, shouldTriggerBulk bool, queries ...SearchQuery) (*User, error) { +func (q *Queries) GetUser(ctx context.Context, shouldTriggerBulk bool, withOwnerRemoved bool, queries ...SearchQuery) (*User, error) { if shouldTriggerBulk { projection.UserProjection.Trigger(ctx) projection.LoginNameProjection.Trigger(ctx) @@ -328,9 +352,13 @@ func (q *Queries) GetUser(ctx context.Context, shouldTriggerBulk bool, queries . for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where(sq.Eq{ + eq := sq.Eq{ UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + } + if !withOwnerRemoved { + addUserWithoutOwnerRemoved(eq) + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dnhr2", "Errors.Query.SQLStatment") } @@ -339,15 +367,19 @@ func (q *Queries) GetUser(ctx context.Context, shouldTriggerBulk bool, queries . return scan(row) } -func (q *Queries) GetHumanProfile(ctx context.Context, userID string, queries ...SearchQuery) (*Profile, error) { +func (q *Queries) GetHumanProfile(ctx context.Context, userID string, withOwnerRemoved bool, queries ...SearchQuery) (*Profile, error) { query, scan := prepareProfileQuery() for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where(sq.Eq{ + eq := sq.Eq{ UserIDCol.identifier(): userID, UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + } + if !withOwnerRemoved { + addUserWithoutOwnerRemoved(eq) + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dgbg2", "Errors.Query.SQLStatment") } @@ -356,15 +388,19 @@ func (q *Queries) GetHumanProfile(ctx context.Context, userID string, queries .. return scan(row) } -func (q *Queries) GetHumanEmail(ctx context.Context, userID string, queries ...SearchQuery) (*Email, error) { +func (q *Queries) GetHumanEmail(ctx context.Context, userID string, withOwnerRemoved bool, queries ...SearchQuery) (*Email, error) { query, scan := prepareEmailQuery() for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where(sq.Eq{ + eq := sq.Eq{ UserIDCol.identifier(): userID, UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + } + if !withOwnerRemoved { + addUserWithoutOwnerRemoved(eq) + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-BHhj3", "Errors.Query.SQLStatment") } @@ -373,15 +409,19 @@ func (q *Queries) GetHumanEmail(ctx context.Context, userID string, queries ...S return scan(row) } -func (q *Queries) GetHumanPhone(ctx context.Context, userID string, queries ...SearchQuery) (*Phone, error) { +func (q *Queries) GetHumanPhone(ctx context.Context, userID string, withOwnerRemoved bool, queries ...SearchQuery) (*Phone, error) { query, scan := preparePhoneQuery() for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where(sq.Eq{ + eq := sq.Eq{ UserIDCol.identifier(): userID, UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + } + if !withOwnerRemoved { + addUserWithoutOwnerRemoved(eq) + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dg43g", "Errors.Query.SQLStatment") } @@ -390,7 +430,7 @@ func (q *Queries) GetHumanPhone(ctx context.Context, userID string, queries ...S return scan(row) } -func (q *Queries) GetNotifyUserByID(ctx context.Context, shouldTriggered bool, userID string, queries ...SearchQuery) (*NotifyUser, error) { +func (q *Queries) GetNotifyUserByID(ctx context.Context, shouldTriggered bool, userID string, withOwnerRemoved bool, queries ...SearchQuery) (*NotifyUser, error) { if shouldTriggered { projection.UserProjection.Trigger(ctx) projection.LoginNameProjection.Trigger(ctx) @@ -400,10 +440,14 @@ func (q *Queries) GetNotifyUserByID(ctx context.Context, shouldTriggered bool, u for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where(sq.Eq{ + eq := sq.Eq{ UserIDCol.identifier(): userID, UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + } + if !withOwnerRemoved { + addUserWithoutOwnerRemoved(eq) + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Err3g", "Errors.Query.SQLStatment") } @@ -412,7 +456,7 @@ func (q *Queries) GetNotifyUserByID(ctx context.Context, shouldTriggered bool, u return scan(row) } -func (q *Queries) GetNotifyUser(ctx context.Context, shouldTriggered bool, queries ...SearchQuery) (*NotifyUser, error) { +func (q *Queries) GetNotifyUser(ctx context.Context, shouldTriggered bool, withOwnerRemoved bool, queries ...SearchQuery) (*NotifyUser, error) { if shouldTriggered { projection.UserProjection.Trigger(ctx) projection.LoginNameProjection.Trigger(ctx) @@ -422,9 +466,13 @@ func (q *Queries) GetNotifyUser(ctx context.Context, shouldTriggered bool, queri for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where(sq.Eq{ + eq := sq.Eq{ UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + } + if !withOwnerRemoved { + addUserWithoutOwnerRemoved(eq) + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Err3g", "Errors.Query.SQLStatment") } @@ -433,12 +481,13 @@ func (q *Queries) GetNotifyUser(ctx context.Context, shouldTriggered bool, queri return scan(row) } -func (q *Queries) SearchUsers(ctx context.Context, queries *UserSearchQueries) (*Users, error) { +func (q *Queries) SearchUsers(ctx context.Context, queries *UserSearchQueries, withOwnerRemoved bool) (*Users, error) { query, scan := prepareUsersQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }). + eq := sq.Eq{UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + addUserWithoutOwnerRemoved(eq) + } + stmt, args, err := queries.toQuery(query).Where(eq). ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dgbg2", "Errors.Query.SQLStatment") @@ -456,7 +505,7 @@ func (q *Queries) SearchUsers(ctx context.Context, queries *UserSearchQueries) ( return users, err } -func (q *Queries) IsUserUnique(ctx context.Context, username, email, resourceOwner string) (bool, error) { +func (q *Queries) IsUserUnique(ctx context.Context, username, email, resourceOwner string, withOwnerRemoved bool) (bool, error) { query, scan := prepareUserUniqueQuery() queries := make([]SearchQuery, 0, 3) if username != "" { @@ -483,9 +532,11 @@ func (q *Queries) IsUserUnique(ctx context.Context, username, email, resourceOwn for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where(sq.Eq{ - UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + addUserWithoutOwnerRemoved(eq) + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return false, errors.ThrowInternal(err, "QUERY-Dg43g", "Errors.Query.SQLStatment") } @@ -594,27 +645,45 @@ func NewUserLoginNameExistsQuery(value string, comparison TextComparison) (Searc ) } -func prepareUserQuery() (sq.SelectBuilder, func(*sql.Row) (*User, error)) { - loginNamesQuery, _, err := sq.Select( +func prepareLoginNamesQuery() (string, []interface{}, error) { + return sq.Select( userLoginNamesUserIDCol.identifier(), - "ARRAY_AGG("+userLoginNamesNameCol.identifier()+") AS "+userLoginNamesListCol.name, - userLoginNamesInstanceIDCol.identifier()). - From(userLoginNamesTable.identifier()). - GroupBy(userLoginNamesUserIDCol.identifier(), userLoginNamesInstanceIDCol.identifier()). - ToSql() + "ARRAY_AGG("+userLoginNamesNameCol.identifier()+")::TEXT[] AS "+userLoginNamesListCol.name, + userLoginNamesInstanceIDCol.identifier(), + userLoginNamesOwnerRemovedUserCol.identifier(), + userLoginNamesOwnerRemovedPolicyCol.identifier(), + userLoginNamesOwnerRemovedDomainCol.identifier(), + ).From(userLoginNamesTable.identifier()). + GroupBy( + userLoginNamesUserIDCol.identifier(), + userLoginNamesInstanceIDCol.identifier(), + userLoginNamesOwnerRemovedUserCol.identifier(), + userLoginNamesOwnerRemovedPolicyCol.identifier(), + userLoginNamesOwnerRemovedDomainCol.identifier(), + ).ToSql() +} + +func preparePreferredLoginNamesQuery() (string, []interface{}, error) { + return sq.Select( + userPreferredLoginNameUserIDCol.identifier(), + userPreferredLoginNameCol.identifier(), + userPreferredLoginNameInstanceIDCol.identifier(), + userPreferredLoginNameOwnerRemovedUserCol.identifier(), + userPreferredLoginNameOwnerRemovedPolicyCol.identifier(), + userPreferredLoginNameOwnerRemovedDomainCol.identifier(), + ).From(userPreferredLoginNameTable.identifier()). + Where(sq.Eq{ + userPreferredLoginNameIsPrimaryCol.identifier(): true, + }, + ).ToSql() +} + +func prepareUserQuery() (sq.SelectBuilder, func(*sql.Row) (*User, error)) { + loginNamesQuery, loginNamesArgs, err := prepareLoginNamesQuery() if err != nil { return sq.SelectBuilder{}, nil } - preferredLoginNameQuery, preferredLoginNameArgs, err := sq.Select( - userPreferredLoginNameUserIDCol.identifier(), - userPreferredLoginNameCol.identifier(), - userPreferredLoginNameInstanceIDCol.identifier()). - From(userPreferredLoginNameTable.identifier()). - Where( - sq.Eq{ - userPreferredLoginNameIsPrimaryCol.identifier(): true, - }). - ToSql() + preferredLoginNameQuery, preferredLoginNameArgs, err := preparePreferredLoginNamesQuery() if err != nil { return sq.SelectBuilder{}, nil } @@ -651,7 +720,8 @@ func prepareUserQuery() (sq.SelectBuilder, func(*sql.Row) (*User, error)) { LeftJoin(join(MachineUserIDCol, UserIDCol)). LeftJoin("("+loginNamesQuery+") AS "+userLoginNamesTable.alias+" ON "+ userLoginNamesUserIDCol.identifier()+" = "+UserIDCol.identifier()+" AND "+ - userLoginNamesInstanceIDCol.identifier()+" = "+UserInstanceIDCol.identifier()). + userLoginNamesInstanceIDCol.identifier()+" = "+UserInstanceIDCol.identifier(), + loginNamesArgs...). LeftJoin("("+preferredLoginNameQuery+") AS "+userPreferredLoginNameTable.alias+" ON "+ userPreferredLoginNameUserIDCol.identifier()+" = "+UserIDCol.identifier()+" AND "+ userPreferredLoginNameInstanceIDCol.identifier()+" = "+UserInstanceIDCol.identifier(), @@ -902,26 +972,11 @@ func preparePhoneQuery() (sq.SelectBuilder, func(*sql.Row) (*Phone, error)) { } func prepareNotifyUserQuery() (sq.SelectBuilder, func(*sql.Row) (*NotifyUser, error)) { - loginNamesQuery, _, err := sq.Select( - userLoginNamesUserIDCol.identifier(), - "ARRAY_AGG("+userLoginNamesNameCol.identifier()+") AS "+userLoginNamesListCol.name, - userLoginNamesInstanceIDCol.identifier()). - From(userLoginNamesTable.identifier()). - GroupBy(userLoginNamesUserIDCol.identifier(), userLoginNamesInstanceIDCol.identifier()). - ToSql() + loginNamesQuery, loginNamesArgs, err := prepareLoginNamesQuery() if err != nil { return sq.SelectBuilder{}, nil } - preferredLoginNameQuery, preferredLoginNameArgs, err := sq.Select( - userPreferredLoginNameUserIDCol.identifier(), - userPreferredLoginNameCol.identifier(), - userPreferredLoginNameInstanceIDCol.identifier()). - From(userPreferredLoginNameTable.identifier()). - Where( - sq.Eq{ - userPreferredLoginNameIsPrimaryCol.identifier(): true, - }). - ToSql() + preferredLoginNameQuery, preferredLoginNameArgs, err := preparePreferredLoginNamesQuery() if err != nil { return sq.SelectBuilder{}, nil } @@ -957,7 +1012,8 @@ func prepareNotifyUserQuery() (sq.SelectBuilder, func(*sql.Row) (*NotifyUser, er LeftJoin(join(NotifyUserIDCol, UserIDCol)). LeftJoin("("+loginNamesQuery+") AS "+userLoginNamesTable.alias+" ON "+ userLoginNamesUserIDCol.identifier()+" = "+UserIDCol.identifier()+" AND "+ - userLoginNamesInstanceIDCol.identifier()+" = "+UserInstanceIDCol.identifier()). + userLoginNamesInstanceIDCol.identifier()+" = "+UserInstanceIDCol.identifier(), + loginNamesArgs...). LeftJoin("("+preferredLoginNameQuery+") AS "+userPreferredLoginNameTable.alias+" ON "+ userPreferredLoginNameUserIDCol.identifier()+" = "+UserIDCol.identifier()+" AND "+ userPreferredLoginNameInstanceIDCol.identifier()+" = "+UserInstanceIDCol.identifier(), @@ -1085,26 +1141,11 @@ func prepareUserUniqueQuery() (sq.SelectBuilder, func(*sql.Row) (bool, error)) { } func prepareUsersQuery() (sq.SelectBuilder, func(*sql.Rows) (*Users, error)) { - loginNamesQuery, _, err := sq.Select( - userLoginNamesUserIDCol.identifier(), - "ARRAY_AGG("+userLoginNamesNameCol.identifier()+") AS "+userLoginNamesListCol.name, - userLoginNamesInstanceIDCol.identifier()). - From(userLoginNamesTable.identifier()). - GroupBy(userLoginNamesUserIDCol.identifier(), userLoginNamesInstanceIDCol.identifier()). - ToSql() + loginNamesQuery, loginNamesArgs, err := prepareLoginNamesQuery() if err != nil { return sq.SelectBuilder{}, nil } - preferredLoginNameQuery, preferredLoginNameArgs, err := sq.Select( - userPreferredLoginNameUserIDCol.identifier(), - userPreferredLoginNameCol.identifier(), - userPreferredLoginNameInstanceIDCol.identifier()). - From(userPreferredLoginNameTable.identifier()). - Where( - sq.Eq{ - userPreferredLoginNameIsPrimaryCol.identifier(): true, - }). - ToSql() + preferredLoginNameQuery, preferredLoginNameArgs, err := preparePreferredLoginNamesQuery() if err != nil { return sq.SelectBuilder{}, nil } @@ -1140,7 +1181,8 @@ func prepareUsersQuery() (sq.SelectBuilder, func(*sql.Rows) (*Users, error)) { LeftJoin(join(MachineUserIDCol, UserIDCol)). LeftJoin("("+loginNamesQuery+") AS "+userLoginNamesTable.alias+" ON "+ userLoginNamesUserIDCol.identifier()+" = "+UserIDCol.identifier()+" AND "+ - userLoginNamesInstanceIDCol.identifier()+" = "+UserInstanceIDCol.identifier()). + userLoginNamesInstanceIDCol.identifier()+" = "+UserInstanceIDCol.identifier(), + loginNamesArgs...). LeftJoin("("+preferredLoginNameQuery+") AS "+userPreferredLoginNameTable.alias+" ON "+ userPreferredLoginNameUserIDCol.identifier()+" = "+UserIDCol.identifier()+" AND "+ userPreferredLoginNameInstanceIDCol.identifier()+" = "+UserInstanceIDCol.identifier(), diff --git a/internal/query/user_auth_method.go b/internal/query/user_auth_method.go index 2472100eef..9c97b5aa5c 100644 --- a/internal/query/user_auth_method.go +++ b/internal/query/user_auth_method.go @@ -58,6 +58,10 @@ var ( name: projection.UserAuthMethodTypeCol, table: userAuthMethodTable, } + UserAuthMethodColumnOwnerRemoved = Column{ + name: projection.UserAuthMethodOwnerRemovedCol, + table: userAuthMethodTable, + } ) type AuthMethods struct { @@ -82,12 +86,13 @@ type UserAuthMethodSearchQueries struct { Queries []SearchQuery } -func (q *Queries) SearchUserAuthMethods(ctx context.Context, queries *UserAuthMethodSearchQueries) (userAuthMethods *AuthMethods, err error) { +func (q *Queries) SearchUserAuthMethods(ctx context.Context, queries *UserAuthMethodSearchQueries, withOwnerRemoved bool) (userAuthMethods *AuthMethods, err error) { query, scan := prepareUserAuthMethodsQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - UserAuthMethodColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{UserAuthMethodColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + eq[UserAuthMethodColumnOwnerRemoved.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-j9NJd", "Errors.Query.InvalidRequest") } diff --git a/internal/query/user_auth_method_test.go b/internal/query/user_auth_method_test.go index cb0a8a389a..8c77f546c1 100644 --- a/internal/query/user_auth_method_test.go +++ b/internal/query/user_auth_method_test.go @@ -27,17 +27,17 @@ func Test_UserAuthMethodPrepares(t *testing.T) { prepare: prepareUserAuthMethodsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.user_auth_methods3.token_id,`+ - ` projections.user_auth_methods3.creation_date,`+ - ` projections.user_auth_methods3.change_date,`+ - ` projections.user_auth_methods3.resource_owner,`+ - ` projections.user_auth_methods3.user_id,`+ - ` projections.user_auth_methods3.sequence,`+ - ` projections.user_auth_methods3.name,`+ - ` projections.user_auth_methods3.state,`+ - ` projections.user_auth_methods3.method_type,`+ + regexp.QuoteMeta(`SELECT projections.user_auth_methods4.token_id,`+ + ` projections.user_auth_methods4.creation_date,`+ + ` projections.user_auth_methods4.change_date,`+ + ` projections.user_auth_methods4.resource_owner,`+ + ` projections.user_auth_methods4.user_id,`+ + ` projections.user_auth_methods4.sequence,`+ + ` projections.user_auth_methods4.name,`+ + ` projections.user_auth_methods4.state,`+ + ` projections.user_auth_methods4.method_type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.user_auth_methods3`), + ` FROM projections.user_auth_methods4`), nil, nil, ), @@ -49,17 +49,17 @@ func Test_UserAuthMethodPrepares(t *testing.T) { prepare: prepareUserAuthMethodsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.user_auth_methods3.token_id,`+ - ` projections.user_auth_methods3.creation_date,`+ - ` projections.user_auth_methods3.change_date,`+ - ` projections.user_auth_methods3.resource_owner,`+ - ` projections.user_auth_methods3.user_id,`+ - ` projections.user_auth_methods3.sequence,`+ - ` projections.user_auth_methods3.name,`+ - ` projections.user_auth_methods3.state,`+ - ` projections.user_auth_methods3.method_type,`+ + regexp.QuoteMeta(`SELECT projections.user_auth_methods4.token_id,`+ + ` projections.user_auth_methods4.creation_date,`+ + ` projections.user_auth_methods4.change_date,`+ + ` projections.user_auth_methods4.resource_owner,`+ + ` projections.user_auth_methods4.user_id,`+ + ` projections.user_auth_methods4.sequence,`+ + ` projections.user_auth_methods4.name,`+ + ` projections.user_auth_methods4.state,`+ + ` projections.user_auth_methods4.method_type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.user_auth_methods3`), + ` FROM projections.user_auth_methods4`), []string{ "token_id", "creation_date", @@ -111,17 +111,17 @@ func Test_UserAuthMethodPrepares(t *testing.T) { prepare: prepareUserAuthMethodsQuery, want: want{ sqlExpectations: mockQueries( - regexp.QuoteMeta(`SELECT projections.user_auth_methods3.token_id,`+ - ` projections.user_auth_methods3.creation_date,`+ - ` projections.user_auth_methods3.change_date,`+ - ` projections.user_auth_methods3.resource_owner,`+ - ` projections.user_auth_methods3.user_id,`+ - ` projections.user_auth_methods3.sequence,`+ - ` projections.user_auth_methods3.name,`+ - ` projections.user_auth_methods3.state,`+ - ` projections.user_auth_methods3.method_type,`+ + regexp.QuoteMeta(`SELECT projections.user_auth_methods4.token_id,`+ + ` projections.user_auth_methods4.creation_date,`+ + ` projections.user_auth_methods4.change_date,`+ + ` projections.user_auth_methods4.resource_owner,`+ + ` projections.user_auth_methods4.user_id,`+ + ` projections.user_auth_methods4.sequence,`+ + ` projections.user_auth_methods4.name,`+ + ` projections.user_auth_methods4.state,`+ + ` projections.user_auth_methods4.method_type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.user_auth_methods3`), + ` FROM projections.user_auth_methods4`), []string{ "token_id", "creation_date", @@ -195,17 +195,17 @@ func Test_UserAuthMethodPrepares(t *testing.T) { prepare: prepareUserAuthMethodsQuery, want: want{ sqlExpectations: mockQueryErr( - regexp.QuoteMeta(`SELECT projections.user_auth_methods3.token_id,`+ - ` projections.user_auth_methods3.creation_date,`+ - ` projections.user_auth_methods3.change_date,`+ - ` projections.user_auth_methods3.resource_owner,`+ - ` projections.user_auth_methods3.user_id,`+ - ` projections.user_auth_methods3.sequence,`+ - ` projections.user_auth_methods3.name,`+ - ` projections.user_auth_methods3.state,`+ - ` projections.user_auth_methods3.method_type,`+ + regexp.QuoteMeta(`SELECT projections.user_auth_methods4.token_id,`+ + ` projections.user_auth_methods4.creation_date,`+ + ` projections.user_auth_methods4.change_date,`+ + ` projections.user_auth_methods4.resource_owner,`+ + ` projections.user_auth_methods4.user_id,`+ + ` projections.user_auth_methods4.sequence,`+ + ` projections.user_auth_methods4.name,`+ + ` projections.user_auth_methods4.state,`+ + ` projections.user_auth_methods4.method_type,`+ ` COUNT(*) OVER ()`+ - ` FROM projections.user_auth_methods3`), + ` FROM projections.user_auth_methods4`), sql.ErrConnDone, ), err: func(err error) (error, bool) { diff --git a/internal/query/user_grant.go b/internal/query/user_grant.go index 596c17c431..9d806e36d0 100644 --- a/internal/query/user_grant.go +++ b/internal/query/user_grant.go @@ -190,9 +190,33 @@ var ( name: projection.UserGrantState, table: userGrantTable, } + UserGrantOwnerRemoved = Column{ + name: projection.UserGrantOwnerRemoved, + table: userGrantTable, + } + UserGrantUserOwnerRemoved = Column{ + name: projection.UserGrantUserOwnerRemoved, + table: userGrantTable, + } + UserGrantProjectOwnerRemoved = Column{ + name: projection.UserGrantProjectOwnerRemoved, + table: userGrantTable, + } + UserGrantGrantGrantedOrgRemoved = Column{ + name: projection.UserGrantGrantedOrgRemoved, + table: userGrantTable, + } ) -func (q *Queries) UserGrant(ctx context.Context, shouldTriggerBulk bool, queries ...SearchQuery) (*UserGrant, error) { +func addUserGrantWithoutOwnerRemoved(eq map[string]interface{}) { + eq[UserGrantOwnerRemoved.identifier()] = false + eq[UserGrantUserOwnerRemoved.identifier()] = false + eq[UserGrantProjectOwnerRemoved.identifier()] = false + eq[UserGrantGrantGrantedOrgRemoved.identifier()] = false + addLoginNameWithoutOwnerRemoved(eq) +} + +func (q *Queries) UserGrant(ctx context.Context, shouldTriggerBulk bool, withOwnerRemoved bool, queries ...SearchQuery) (*UserGrant, error) { if shouldTriggerBulk { projection.UserGrantProjection.Trigger(ctx) } @@ -201,10 +225,11 @@ func (q *Queries) UserGrant(ctx context.Context, shouldTriggerBulk bool, queries for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query. - Where(sq.Eq{ - UserGrantInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{UserGrantInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + addUserGrantWithoutOwnerRemoved(eq) + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Fa1KW", "Errors.Query.SQLStatement") } @@ -213,12 +238,13 @@ func (q *Queries) UserGrant(ctx context.Context, shouldTriggerBulk bool, queries return scan(row) } -func (q *Queries) UserGrants(ctx context.Context, queries *UserGrantsQueries) (*UserGrants, error) { +func (q *Queries) UserGrants(ctx context.Context, queries *UserGrantsQueries, withOwnerRemoved bool) (*UserGrants, error) { query, scan := prepareUserGrantsQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - UserGrantInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{UserGrantInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + if !withOwnerRemoved { + addUserGrantWithoutOwnerRemoved(eq) + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-wXnQR", "Errors.Query.SQLStatement") } diff --git a/internal/query/user_grant_test.go b/internal/query/user_grant_test.go index ab2cc6aa71..ef3df7be01 100644 --- a/internal/query/user_grant_test.go +++ b/internal/query/user_grant_test.go @@ -15,35 +15,35 @@ import ( var ( userGrantStmt = regexp.QuoteMeta( - "SELECT projections.user_grants2.id" + - ", projections.user_grants2.creation_date" + - ", projections.user_grants2.change_date" + - ", projections.user_grants2.sequence" + - ", projections.user_grants2.grant_id" + - ", projections.user_grants2.roles" + - ", projections.user_grants2.state" + - ", projections.user_grants2.user_id" + - ", projections.users5.username" + - ", projections.users5.type" + - ", projections.users5.resource_owner" + - ", projections.users5_humans.first_name" + - ", projections.users5_humans.last_name" + - ", projections.users5_humans.email" + - ", projections.users5_humans.display_name" + - ", projections.users5_humans.avatar_key" + - ", projections.login_names.login_name" + - ", projections.user_grants2.resource_owner" + + "SELECT projections.user_grants3.id" + + ", projections.user_grants3.creation_date" + + ", projections.user_grants3.change_date" + + ", projections.user_grants3.sequence" + + ", projections.user_grants3.grant_id" + + ", projections.user_grants3.roles" + + ", projections.user_grants3.state" + + ", projections.user_grants3.user_id" + + ", projections.users6.username" + + ", projections.users6.type" + + ", projections.users6.resource_owner" + + ", projections.users6_humans.first_name" + + ", projections.users6_humans.last_name" + + ", projections.users6_humans.email" + + ", projections.users6_humans.display_name" + + ", projections.users6_humans.avatar_key" + + ", projections.login_names2.login_name" + + ", projections.user_grants3.resource_owner" + ", projections.orgs.name" + ", projections.orgs.primary_domain" + - ", projections.user_grants2.project_id" + - ", projections.projects2.name" + - " FROM projections.user_grants2" + - " LEFT JOIN projections.users5 ON projections.user_grants2.user_id = projections.users5.id AND projections.user_grants2.instance_id = projections.users5.instance_id" + - " LEFT JOIN projections.users5_humans ON projections.user_grants2.user_id = projections.users5_humans.user_id AND projections.user_grants2.instance_id = projections.users5_humans.instance_id" + - " LEFT JOIN projections.orgs ON projections.user_grants2.resource_owner = projections.orgs.id AND projections.user_grants2.instance_id = projections.orgs.instance_id" + - " LEFT JOIN projections.projects2 ON projections.user_grants2.project_id = projections.projects2.id AND projections.user_grants2.instance_id = projections.projects2.instance_id" + - " LEFT JOIN projections.login_names ON projections.user_grants2.user_id = projections.login_names.user_id AND projections.user_grants2.instance_id = projections.login_names.instance_id" + - " WHERE projections.login_names.is_primary = $1") + ", projections.user_grants3.project_id" + + ", projections.projects3.name" + + " FROM projections.user_grants3" + + " LEFT JOIN projections.users6 ON projections.user_grants3.user_id = projections.users6.id AND projections.user_grants3.instance_id = projections.users6.instance_id" + + " LEFT JOIN projections.users6_humans ON projections.user_grants3.user_id = projections.users6_humans.user_id AND projections.user_grants3.instance_id = projections.users6_humans.instance_id" + + " LEFT JOIN projections.orgs ON projections.user_grants3.resource_owner = projections.orgs.id AND projections.user_grants3.instance_id = projections.orgs.instance_id" + + " LEFT JOIN projections.projects3 ON projections.user_grants3.project_id = projections.projects3.id AND projections.user_grants3.instance_id = projections.projects3.instance_id" + + " LEFT JOIN projections.login_names2 ON projections.user_grants3.user_id = projections.login_names2.user_id AND projections.user_grants3.instance_id = projections.login_names2.instance_id" + + " WHERE projections.login_names2.is_primary = $1") userGrantCols = []string{ "id", "creation_date", @@ -69,36 +69,36 @@ var ( "name", //project name } userGrantsStmt = regexp.QuoteMeta( - "SELECT projections.user_grants2.id" + - ", projections.user_grants2.creation_date" + - ", projections.user_grants2.change_date" + - ", projections.user_grants2.sequence" + - ", projections.user_grants2.grant_id" + - ", projections.user_grants2.roles" + - ", projections.user_grants2.state" + - ", projections.user_grants2.user_id" + - ", projections.users5.username" + - ", projections.users5.type" + - ", projections.users5.resource_owner" + - ", projections.users5_humans.first_name" + - ", projections.users5_humans.last_name" + - ", projections.users5_humans.email" + - ", projections.users5_humans.display_name" + - ", projections.users5_humans.avatar_key" + - ", projections.login_names.login_name" + - ", projections.user_grants2.resource_owner" + + "SELECT projections.user_grants3.id" + + ", projections.user_grants3.creation_date" + + ", projections.user_grants3.change_date" + + ", projections.user_grants3.sequence" + + ", projections.user_grants3.grant_id" + + ", projections.user_grants3.roles" + + ", projections.user_grants3.state" + + ", projections.user_grants3.user_id" + + ", projections.users6.username" + + ", projections.users6.type" + + ", projections.users6.resource_owner" + + ", projections.users6_humans.first_name" + + ", projections.users6_humans.last_name" + + ", projections.users6_humans.email" + + ", projections.users6_humans.display_name" + + ", projections.users6_humans.avatar_key" + + ", projections.login_names2.login_name" + + ", projections.user_grants3.resource_owner" + ", projections.orgs.name" + ", projections.orgs.primary_domain" + - ", projections.user_grants2.project_id" + - ", projections.projects2.name" + + ", projections.user_grants3.project_id" + + ", projections.projects3.name" + ", COUNT(*) OVER ()" + - " FROM projections.user_grants2" + - " LEFT JOIN projections.users5 ON projections.user_grants2.user_id = projections.users5.id AND projections.user_grants2.instance_id = projections.users5.instance_id" + - " LEFT JOIN projections.users5_humans ON projections.user_grants2.user_id = projections.users5_humans.user_id AND projections.user_grants2.instance_id = projections.users5_humans.instance_id" + - " LEFT JOIN projections.orgs ON projections.user_grants2.resource_owner = projections.orgs.id AND projections.user_grants2.instance_id = projections.orgs.instance_id" + - " LEFT JOIN projections.projects2 ON projections.user_grants2.project_id = projections.projects2.id AND projections.user_grants2.instance_id = projections.projects2.instance_id" + - " LEFT JOIN projections.login_names ON projections.user_grants2.user_id = projections.login_names.user_id AND projections.user_grants2.instance_id = projections.login_names.instance_id" + - " WHERE projections.login_names.is_primary = $1") + " FROM projections.user_grants3" + + " LEFT JOIN projections.users6 ON projections.user_grants3.user_id = projections.users6.id AND projections.user_grants3.instance_id = projections.users6.instance_id" + + " LEFT JOIN projections.users6_humans ON projections.user_grants3.user_id = projections.users6_humans.user_id AND projections.user_grants3.instance_id = projections.users6_humans.instance_id" + + " LEFT JOIN projections.orgs ON projections.user_grants3.resource_owner = projections.orgs.id AND projections.user_grants3.instance_id = projections.orgs.instance_id" + + " LEFT JOIN projections.projects3 ON projections.user_grants3.project_id = projections.projects3.id AND projections.user_grants3.instance_id = projections.projects3.instance_id" + + " LEFT JOIN projections.login_names2 ON projections.user_grants3.user_id = projections.login_names2.user_id AND projections.user_grants3.instance_id = projections.login_names2.instance_id" + + " WHERE projections.login_names2.is_primary = $1") userGrantsCols = append( userGrantCols, "count", diff --git a/internal/query/user_membership.go b/internal/query/user_membership.go index 995c1f4f0f..3620e95f8c 100644 --- a/internal/query/user_membership.go +++ b/internal/query/user_membership.go @@ -103,12 +103,10 @@ func (q *MembershipSearchQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder return query } -func (q *Queries) Memberships(ctx context.Context, queries *MembershipSearchQuery) (*Memberships, error) { - query, scan := prepareMembershipsQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - membershipInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() +func (q *Queries) Memberships(ctx context.Context, queries *MembershipSearchQuery, withOwnerRemoved bool) (*Memberships, error) { + query, queryArgs, scan := prepareMembershipsQuery(withOwnerRemoved) + eq := sq.Eq{membershipInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()} + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-T84X9", "Errors.Query.InvalidRequest") } @@ -116,8 +114,9 @@ func (q *Queries) Memberships(ctx context.Context, queries *MembershipSearchQuer if err != nil { return nil, err } + queryArgs = append(queryArgs, args...) - rows, err := q.client.QueryContext(ctx, stmt, args...) + rows, err := q.client.QueryContext(ctx, stmt, queryArgs...) if err != nil { return nil, errors.ThrowInternal(err, "QUERY-eAV2x", "Errors.Internal") } @@ -184,18 +183,42 @@ var ( table: membershipAlias, } - membershipFrom = "(" + - prepareOrgMember() + - " UNION ALL " + - prepareIAMMember() + - " UNION ALL " + - prepareProjectMember() + - " UNION ALL " + - prepareProjectGrantMember() + - ") AS " + membershipAlias.identifier() + membershipOwnerRemoved = Column{ + name: projection.MemberOwnerRemoved, + table: membershipAlias, + } + membershipOwnerRemovedUser = Column{ + name: projection.MemberUserOwnerRemoved, + table: membershipAlias, + } + membershipGrantedOrgRemoved = Column{ + name: projection.ProjectGrantMemberGrantedOrgRemoved, + table: membershipAlias, + } ) -func prepareMembershipsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Memberships, error)) { +func getMembershipFromQuery(withOwnerRemoved bool) (string, []interface{}) { + orgMembers, orgMembersArgs := prepareOrgMember(withOwnerRemoved) + iamMembers, iamMembersArgs := prepareIAMMember(withOwnerRemoved) + projectMembers, projectMembersArgs := prepareProjectMember(withOwnerRemoved) + projectGrantMembers, projectGrantMembersArgs := prepareProjectGrantMember(withOwnerRemoved) + args := make([]interface{}, 0) + args = append(append(append(append(args, orgMembersArgs...), iamMembersArgs...), projectMembersArgs...), projectGrantMembersArgs...) + + return "(" + + orgMembers + + " UNION ALL " + + iamMembers + + " UNION ALL " + + projectMembers + + " UNION ALL " + + projectGrantMembers + + ") AS " + membershipAlias.identifier(), + args +} + +func prepareMembershipsQuery(withOwnerRemoved bool) (sq.SelectBuilder, []interface{}, func(*sql.Rows) (*Memberships, error)) { + query, args := getMembershipFromQuery(withOwnerRemoved) return sq.Select( membershipUserID.identifier(), membershipRoles.identifier(), @@ -211,11 +234,12 @@ func prepareMembershipsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Memberships, ProjectColumnName.identifier(), OrgColumnName.identifier(), countColumn.identifier(), - ).From(membershipFrom). + ).From(query). LeftJoin(join(ProjectColumnID, membershipProjectID)). LeftJoin(join(OrgColumnID, membershipOrgID)). LeftJoin(join(ProjectGrantColumnGrantID, membershipGrantID)). PlaceholderFormat(sq.Dollar), + args, func(rows *sql.Rows) (*Memberships, error) { memberships := make([]*Membership, 0) var count uint64 @@ -293,8 +317,8 @@ func prepareMembershipsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Memberships, } } -func prepareOrgMember() string { - stmt, _ := sq.Select( +func prepareOrgMember(withOwnerRemoved bool) (string, []interface{}) { + builder := sq.Select( OrgMemberUserID.identifier(), OrgMemberRoles.identifier(), OrgMemberCreationDate.identifier(), @@ -306,12 +330,17 @@ func prepareOrgMember() string { "NULL::TEXT AS "+membershipIAMID.name, "NULL::TEXT AS "+membershipProjectID.name, "NULL::TEXT AS "+membershipGrantID.name, - ).From(orgMemberTable.identifier()).MustSql() - return stmt + ).From(orgMemberTable.identifier()) + if !withOwnerRemoved { + eq := sq.Eq{} + addOrgMemberWithoutOwnerRemoved(eq) + builder = builder.Where(eq) + } + return builder.MustSql() } -func prepareIAMMember() string { - stmt, _ := sq.Select( +func prepareIAMMember(withOwnerRemoved bool) (string, []interface{}) { + builder := sq.Select( InstanceMemberUserID.identifier(), InstanceMemberRoles.identifier(), InstanceMemberCreationDate.identifier(), @@ -323,12 +352,17 @@ func prepareIAMMember() string { InstanceMemberIAMID.identifier(), "NULL::TEXT AS "+membershipProjectID.name, "NULL::TEXT AS "+membershipGrantID.name, - ).From(instanceMemberTable.identifier()).MustSql() - return stmt + ).From(instanceMemberTable.identifier()) + if !withOwnerRemoved { + eq := sq.Eq{} + addIamMemberWithoutOwnerRemoved(eq) + builder = builder.Where(eq) + } + return builder.MustSql() } -func prepareProjectMember() string { - stmt, _ := sq.Select( +func prepareProjectMember(withOwnerRemoved bool) (string, []interface{}) { + builder := sq.Select( ProjectMemberUserID.identifier(), ProjectMemberRoles.identifier(), ProjectMemberCreationDate.identifier(), @@ -340,13 +374,17 @@ func prepareProjectMember() string { "NULL::TEXT AS "+membershipIAMID.name, ProjectMemberProjectID.identifier(), "NULL::TEXT AS "+membershipGrantID.name, - ).From(projectMemberTable.identifier()).MustSql() - - return stmt + ).From(projectMemberTable.identifier()) + if !withOwnerRemoved { + eq := sq.Eq{} + addProjectMemberWithoutOwnerRemoved(eq) + builder = builder.Where(eq) + } + return builder.MustSql() } -func prepareProjectGrantMember() string { - stmt, _ := sq.Select( +func prepareProjectGrantMember(withOwnerRemoved bool) (string, []interface{}) { + builder := sq.Select( ProjectGrantMemberUserID.identifier(), ProjectGrantMemberRoles.identifier(), ProjectGrantMemberCreationDate.identifier(), @@ -358,8 +396,11 @@ func prepareProjectGrantMember() string { "NULL::TEXT AS "+membershipIAMID.name, ProjectGrantMemberProjectID.identifier(), ProjectGrantMemberGrantID.identifier(), - ).From(projectGrantMemberTable.identifier()). - MustSql() - - return stmt + ).From(projectGrantMemberTable.identifier()) + if !withOwnerRemoved { + eq := sq.Eq{} + addProjectGrantMemberWithoutOwnerRemoved(eq) + builder = builder.Where(eq) + } + return builder.MustSql() } diff --git a/internal/query/user_membership_test.go b/internal/query/user_membership_test.go index df1e3bfb05..75ede35973 100644 --- a/internal/query/user_membership_test.go +++ b/internal/query/user_membership_test.go @@ -8,6 +8,8 @@ import ( "regexp" "testing" + sq "github.com/Masterminds/squirrel" + "github.com/zitadel/zitadel/internal/database" ) @@ -23,8 +25,8 @@ var ( ", memberships.id" + ", memberships.project_id" + ", memberships.grant_id" + - ", projections.project_grants2.granted_org_id" + - ", projections.projects2.name" + + ", projections.project_grants3.granted_org_id" + + ", projections.projects3.name" + ", projections.orgs.name" + ", COUNT(*) OVER ()" + " FROM (" + @@ -39,7 +41,8 @@ var ( ", NULL::TEXT AS id" + ", NULL::TEXT AS project_id" + ", NULL::TEXT AS grant_id" + - " FROM projections.org_members2 AS members" + + " FROM projections.org_members3 AS members" + + " WHERE members.owner_removed = $1 AND members.user_owner_removed = $2" + " UNION ALL " + "SELECT members.user_id" + ", members.roles" + @@ -52,7 +55,8 @@ var ( ", members.id" + ", NULL::TEXT AS project_id" + ", NULL::TEXT AS grant_id" + - " FROM projections.instance_members2 AS members" + + " FROM projections.instance_members3 AS members" + + " WHERE members.owner_removed = $3 AND members.user_owner_removed = $4" + " UNION ALL " + "SELECT members.user_id" + ", members.roles" + @@ -65,7 +69,8 @@ var ( ", NULL::TEXT AS id" + ", members.project_id" + ", NULL::TEXT AS grant_id" + - " FROM projections.project_members2 AS members" + + " FROM projections.project_members3 AS members" + + " WHERE members.owner_removed = $5 AND members.user_owner_removed = $6" + " UNION ALL " + "SELECT members.user_id" + ", members.roles" + @@ -78,11 +83,12 @@ var ( ", NULL::TEXT AS id" + ", members.project_id" + ", members.grant_id" + - " FROM projections.project_grant_members2 AS members" + + " FROM projections.project_grant_members3 AS members" + + " WHERE members.granted_org_removed = $7 AND members.owner_removed = $8 AND members.user_owner_removed = $9" + ") AS memberships" + - " LEFT JOIN projections.projects2 ON memberships.project_id = projections.projects2.id AND memberships.instance_id = projections.projects2.instance_id" + + " LEFT JOIN projections.projects3 ON memberships.project_id = projections.projects3.id AND memberships.instance_id = projections.projects3.instance_id" + " LEFT JOIN projections.orgs ON memberships.org_id = projections.orgs.id AND memberships.instance_id = projections.orgs.instance_id" + - " LEFT JOIN projections.project_grants2 ON memberships.grant_id = projections.project_grants2.grant_id AND memberships.instance_id = projections.project_grants2.instance_id") + " LEFT JOIN projections.project_grants3 ON memberships.grant_id = projections.project_grants3.grant_id AND memberships.instance_id = projections.project_grants3.instance_id") membershipCols = []string{ "user_id", "roles", @@ -114,7 +120,7 @@ func Test_MembershipPrepares(t *testing.T) { }{ { name: "prepareMembershipsQuery no result", - prepare: prepareMembershipsQuery, + prepare: prepareMembershipWrapper(false), want: want{ sqlExpectations: mockQueries( membershipsStmt, @@ -126,7 +132,7 @@ func Test_MembershipPrepares(t *testing.T) { }, { name: "prepareMembershipsQuery one org member", - prepare: prepareMembershipsQuery, + prepare: prepareMembershipWrapper(false), want: want{ sqlExpectations: mockQueries( membershipsStmt, @@ -169,7 +175,7 @@ func Test_MembershipPrepares(t *testing.T) { }, { name: "prepareMembershipsQuery one instance member", - prepare: prepareMembershipsQuery, + prepare: prepareMembershipWrapper(false), want: want{ sqlExpectations: mockQueries( membershipsStmt, @@ -212,7 +218,7 @@ func Test_MembershipPrepares(t *testing.T) { }, { name: "prepareMembershipsQuery one project member", - prepare: prepareMembershipsQuery, + prepare: prepareMembershipWrapper(false), want: want{ sqlExpectations: mockQueries( membershipsStmt, @@ -255,7 +261,7 @@ func Test_MembershipPrepares(t *testing.T) { }, { name: "prepareMembershipsQuery one project grant member", - prepare: prepareMembershipsQuery, + prepare: prepareMembershipWrapper(false), want: want{ sqlExpectations: mockQueries( membershipsStmt, @@ -303,7 +309,7 @@ func Test_MembershipPrepares(t *testing.T) { }, { name: "prepareMembershipsQuery one for each member type", - prepare: prepareMembershipsQuery, + prepare: prepareMembershipWrapper(false), want: want{ sqlExpectations: mockQueries( membershipsStmt, @@ -423,7 +429,7 @@ func Test_MembershipPrepares(t *testing.T) { }, { name: "prepareMembershipsQuery sql err", - prepare: prepareMembershipsQuery, + prepare: prepareMembershipWrapper(false), want: want{ sqlExpectations: mockQueryErr( membershipsStmt, @@ -445,3 +451,10 @@ func Test_MembershipPrepares(t *testing.T) { }) } } + +func prepareMembershipWrapper(withOwnerRemoved bool) func() (sq.SelectBuilder, func(*sql.Rows) (*Memberships, error)) { + builder, _, fun := prepareMembershipsQuery(withOwnerRemoved) + return func() (sq.SelectBuilder, func(*sql.Rows) (*Memberships, error)) { + return builder, fun + } +} diff --git a/internal/query/user_metadata.go b/internal/query/user_metadata.go index 3fa69a5c3c..4dc5812511 100644 --- a/internal/query/user_metadata.go +++ b/internal/query/user_metadata.go @@ -70,9 +70,13 @@ var ( name: projection.UserMetadataColumnValue, table: userMetadataTable, } + UserMetadataOwnerRemovedCol = Column{ + name: projection.UserMetadataColumnOwnerRemoved, + table: userMetadataTable, + } ) -func (q *Queries) GetUserMetadataByKey(ctx context.Context, shouldTriggerBulk bool, userID, key string, queries ...SearchQuery) (*UserMetadata, error) { +func (q *Queries) GetUserMetadataByKey(ctx context.Context, shouldTriggerBulk bool, userID, key string, withOwnerRemoved bool, queries ...SearchQuery) (*UserMetadata, error) { if shouldTriggerBulk { projection.UserMetadataProjection.Trigger(ctx) } @@ -81,12 +85,15 @@ func (q *Queries) GetUserMetadataByKey(ctx context.Context, shouldTriggerBulk bo for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where( - sq.Eq{ - UserMetadataUserIDCol.identifier(): userID, - UserMetadataKeyCol.identifier(): key, - UserMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{ + UserMetadataUserIDCol.identifier(): userID, + UserMetadataKeyCol.identifier(): key, + UserMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[UserMetadataOwnerRemovedCol.identifier()] = false + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-aDGG2", "Errors.Query.SQLStatment") } @@ -95,18 +102,20 @@ func (q *Queries) GetUserMetadataByKey(ctx context.Context, shouldTriggerBulk bo return scan(row) } -func (q *Queries) SearchUserMetadata(ctx context.Context, shouldTriggerBulk bool, userID string, queries *UserMetadataSearchQueries) (*UserMetadataList, error) { +func (q *Queries) SearchUserMetadata(ctx context.Context, shouldTriggerBulk bool, userID string, queries *UserMetadataSearchQueries, withOwnerRemoved bool) (*UserMetadataList, error) { if shouldTriggerBulk { projection.UserMetadataProjection.Trigger(ctx) } query, scan := prepareUserMetadataListQuery() - stmt, args, err := queries.toQuery(query).Where( - sq.Eq{ - UserMetadataUserIDCol.identifier(): userID, - UserMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), - }). - ToSql() + eq := sq.Eq{ + UserMetadataUserIDCol.identifier(): userID, + UserMetadataInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[UserMetadataOwnerRemovedCol.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Egbgd", "Errors.Query.SQLStatment") } diff --git a/internal/query/user_metadata_test.go b/internal/query/user_metadata_test.go index 969eee33ee..ba372fd78a 100644 --- a/internal/query/user_metadata_test.go +++ b/internal/query/user_metadata_test.go @@ -12,13 +12,13 @@ import ( ) var ( - userMetadataQuery = `SELECT projections.user_metadata3.creation_date,` + - ` projections.user_metadata3.change_date,` + - ` projections.user_metadata3.resource_owner,` + - ` projections.user_metadata3.sequence,` + - ` projections.user_metadata3.key,` + - ` projections.user_metadata3.value` + - ` FROM projections.user_metadata3` + userMetadataQuery = `SELECT projections.user_metadata4.creation_date,` + + ` projections.user_metadata4.change_date,` + + ` projections.user_metadata4.resource_owner,` + + ` projections.user_metadata4.sequence,` + + ` projections.user_metadata4.key,` + + ` projections.user_metadata4.value` + + ` FROM projections.user_metadata4` userMetadataCols = []string{ "creation_date", "change_date", @@ -27,14 +27,14 @@ var ( "key", "value", } - userMetadataListQuery = `SELECT projections.user_metadata3.creation_date,` + - ` projections.user_metadata3.change_date,` + - ` projections.user_metadata3.resource_owner,` + - ` projections.user_metadata3.sequence,` + - ` projections.user_metadata3.key,` + - ` projections.user_metadata3.value,` + + userMetadataListQuery = `SELECT projections.user_metadata4.creation_date,` + + ` projections.user_metadata4.change_date,` + + ` projections.user_metadata4.resource_owner,` + + ` projections.user_metadata4.sequence,` + + ` projections.user_metadata4.key,` + + ` projections.user_metadata4.value,` + ` COUNT(*) OVER ()` + - ` FROM projections.user_metadata3` + ` FROM projections.user_metadata4` userMetadataListCols = []string{ "creation_date", "change_date", diff --git a/internal/query/user_personal_access_token.go b/internal/query/user_personal_access_token.go index 5b1eeee966..9cff5a4368 100644 --- a/internal/query/user_personal_access_token.go +++ b/internal/query/user_personal_access_token.go @@ -57,6 +57,10 @@ var ( name: projection.PersonalAccessTokenColumnSequence, table: personalAccessTokensTable, } + PersonalAccessTokenColumnOwnerRemoved = Column{ + name: projection.PersonalAccessTokenColumnOwnerRemoved, + table: personalAccessTokensTable, + } ) type PersonalAccessTokens struct { @@ -81,7 +85,7 @@ type PersonalAccessTokenSearchQueries struct { Queries []SearchQuery } -func (q *Queries) PersonalAccessTokenByID(ctx context.Context, shouldTriggerBulk bool, id string, queries ...SearchQuery) (*PersonalAccessToken, error) { +func (q *Queries) PersonalAccessTokenByID(ctx context.Context, shouldTriggerBulk bool, id string, withOwnerRemoved bool, queries ...SearchQuery) (*PersonalAccessToken, error) { if shouldTriggerBulk { projection.PersonalAccessTokenProjection.Trigger(ctx) } @@ -90,10 +94,14 @@ func (q *Queries) PersonalAccessTokenByID(ctx context.Context, shouldTriggerBulk for _, q := range queries { query = q.toQuery(query) } - stmt, args, err := query.Where(sq.Eq{ + eq := sq.Eq{ PersonalAccessTokenColumnID.identifier(): id, PersonalAccessTokenColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + } + if !withOwnerRemoved { + eq[PersonalAccessTokenColumnOwnerRemoved.identifier()] = false + } + stmt, args, err := query.Where(eq).ToSql() if err != nil { return nil, errors.ThrowInternal(err, "QUERY-Dgfb4", "Errors.Query.SQLStatment") } @@ -102,12 +110,15 @@ func (q *Queries) PersonalAccessTokenByID(ctx context.Context, shouldTriggerBulk return scan(row) } -func (q *Queries) SearchPersonalAccessTokens(ctx context.Context, queries *PersonalAccessTokenSearchQueries) (personalAccessTokens *PersonalAccessTokens, err error) { +func (q *Queries) SearchPersonalAccessTokens(ctx context.Context, queries *PersonalAccessTokenSearchQueries, withOwnerRemoved bool) (personalAccessTokens *PersonalAccessTokens, err error) { query, scan := preparePersonalAccessTokensQuery() - stmt, args, err := queries.toQuery(query). - Where(sq.Eq{ - PersonalAccessTokenColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), - }).ToSql() + eq := sq.Eq{ + PersonalAccessTokenColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + } + if !withOwnerRemoved { + eq[PersonalAccessTokenColumnOwnerRemoved.identifier()] = false + } + stmt, args, err := queries.toQuery(query).Where(eq).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-Hjw2w", "Errors.Query.InvalidRequest") } diff --git a/internal/query/user_personal_access_token_test.go b/internal/query/user_personal_access_token_test.go index 72631b471b..3105d14b00 100644 --- a/internal/query/user_personal_access_token_test.go +++ b/internal/query/user_personal_access_token_test.go @@ -15,15 +15,15 @@ import ( var ( personalAccessTokenStmt = regexp.QuoteMeta( - "SELECT projections.personal_access_tokens2.id," + - " projections.personal_access_tokens2.creation_date," + - " projections.personal_access_tokens2.change_date," + - " projections.personal_access_tokens2.resource_owner," + - " projections.personal_access_tokens2.sequence," + - " projections.personal_access_tokens2.user_id," + - " projections.personal_access_tokens2.expiration," + - " projections.personal_access_tokens2.scopes" + - " FROM projections.personal_access_tokens2") + "SELECT projections.personal_access_tokens3.id," + + " projections.personal_access_tokens3.creation_date," + + " projections.personal_access_tokens3.change_date," + + " projections.personal_access_tokens3.resource_owner," + + " projections.personal_access_tokens3.sequence," + + " projections.personal_access_tokens3.user_id," + + " projections.personal_access_tokens3.expiration," + + " projections.personal_access_tokens3.scopes" + + " FROM projections.personal_access_tokens3") personalAccessTokenCols = []string{ "id", "creation_date", @@ -35,16 +35,16 @@ var ( "scopes", } personalAccessTokensStmt = regexp.QuoteMeta( - "SELECT projections.personal_access_tokens2.id," + - " projections.personal_access_tokens2.creation_date," + - " projections.personal_access_tokens2.change_date," + - " projections.personal_access_tokens2.resource_owner," + - " projections.personal_access_tokens2.sequence," + - " projections.personal_access_tokens2.user_id," + - " projections.personal_access_tokens2.expiration," + - " projections.personal_access_tokens2.scopes," + + "SELECT projections.personal_access_tokens3.id," + + " projections.personal_access_tokens3.creation_date," + + " projections.personal_access_tokens3.change_date," + + " projections.personal_access_tokens3.resource_owner," + + " projections.personal_access_tokens3.sequence," + + " projections.personal_access_tokens3.user_id," + + " projections.personal_access_tokens3.expiration," + + " projections.personal_access_tokens3.scopes," + " COUNT(*) OVER ()" + - " FROM projections.personal_access_tokens2") + " FROM projections.personal_access_tokens3") personalAccessTokensCols = []string{ "id", "creation_date", diff --git a/internal/query/user_test.go b/internal/query/user_test.go index 56d5267c0d..b6159339e9 100644 --- a/internal/query/user_test.go +++ b/internal/query/user_test.go @@ -17,45 +17,47 @@ import ( ) var ( - userQuery = `SELECT projections.users5.id,` + - ` projections.users5.creation_date,` + - ` projections.users5.change_date,` + - ` projections.users5.resource_owner,` + - ` projections.users5.sequence,` + - ` projections.users5.state,` + - ` projections.users5.type,` + - ` projections.users5.username,` + + loginNamesQuery = `SELECT login_names.user_id, ARRAY_AGG(login_names.login_name)::TEXT[] AS loginnames, login_names.instance_id, login_names.user_owner_removed, login_names.policy_owner_removed, login_names.domain_owner_removed` + + ` FROM projections.login_names2 AS login_names` + + ` GROUP BY login_names.user_id, login_names.instance_id, login_names.user_owner_removed, login_names.policy_owner_removed, login_names.domain_owner_removed` + preferredLoginNameQuery = `SELECT preferred_login_name.user_id, preferred_login_name.login_name, preferred_login_name.instance_id, preferred_login_name.user_owner_removed, preferred_login_name.policy_owner_removed, preferred_login_name.domain_owner_removed` + + ` FROM projections.login_names2 AS preferred_login_name` + + ` WHERE preferred_login_name.is_primary = $1` + userQuery = `SELECT projections.users6.id,` + + ` projections.users6.creation_date,` + + ` projections.users6.change_date,` + + ` projections.users6.resource_owner,` + + ` projections.users6.sequence,` + + ` projections.users6.state,` + + ` projections.users6.type,` + + ` projections.users6.username,` + ` login_names.loginnames,` + ` preferred_login_name.login_name,` + - ` projections.users5_humans.user_id,` + - ` projections.users5_humans.first_name,` + - ` projections.users5_humans.last_name,` + - ` projections.users5_humans.nick_name,` + - ` projections.users5_humans.display_name,` + - ` projections.users5_humans.preferred_language,` + - ` projections.users5_humans.gender,` + - ` projections.users5_humans.avatar_key,` + - ` projections.users5_humans.email,` + - ` projections.users5_humans.is_email_verified,` + - ` projections.users5_humans.phone,` + - ` projections.users5_humans.is_phone_verified,` + - ` projections.users5_machines.user_id,` + - ` projections.users5_machines.name,` + - ` projections.users5_machines.description,` + + ` projections.users6_humans.user_id,` + + ` projections.users6_humans.first_name,` + + ` projections.users6_humans.last_name,` + + ` projections.users6_humans.nick_name,` + + ` projections.users6_humans.display_name,` + + ` projections.users6_humans.preferred_language,` + + ` projections.users6_humans.gender,` + + ` projections.users6_humans.avatar_key,` + + ` projections.users6_humans.email,` + + ` projections.users6_humans.is_email_verified,` + + ` projections.users6_humans.phone,` + + ` projections.users6_humans.is_phone_verified,` + + ` projections.users6_machines.user_id,` + + ` projections.users6_machines.name,` + + ` projections.users6_machines.description,` + ` COUNT(*) OVER ()` + - ` FROM projections.users5` + - ` LEFT JOIN projections.users5_humans ON projections.users5.id = projections.users5_humans.user_id AND projections.users5.instance_id = projections.users5_humans.instance_id` + - ` LEFT JOIN projections.users5_machines ON projections.users5.id = projections.users5_machines.user_id AND projections.users5.instance_id = projections.users5_machines.instance_id` + + ` FROM projections.users6` + + ` LEFT JOIN projections.users6_humans ON projections.users6.id = projections.users6_humans.user_id AND projections.users6.instance_id = projections.users6_humans.instance_id` + + ` LEFT JOIN projections.users6_machines ON projections.users6.id = projections.users6_machines.user_id AND projections.users6.instance_id = projections.users6_machines.instance_id` + ` LEFT JOIN` + - ` (SELECT login_names.user_id, ARRAY_AGG(login_names.login_name) AS loginnames, login_names.instance_id` + - ` FROM projections.login_names AS login_names` + - ` GROUP BY login_names.user_id, login_names.instance_id) AS login_names` + - ` ON login_names.user_id = projections.users5.id AND login_names.instance_id = projections.users5.instance_id` + + ` (` + loginNamesQuery + `) AS login_names` + + ` ON login_names.user_id = projections.users6.id AND login_names.instance_id = projections.users6.instance_id` + ` LEFT JOIN` + - ` (SELECT preferred_login_name.user_id, preferred_login_name.login_name, preferred_login_name.instance_id` + - ` FROM projections.login_names AS preferred_login_name` + - ` WHERE preferred_login_name.is_primary = $1) AS preferred_login_name` + - ` ON preferred_login_name.user_id = projections.users5.id AND preferred_login_name.instance_id = projections.users5.instance_id` + ` (` + preferredLoginNameQuery + `) AS preferred_login_name` + + ` ON preferred_login_name.user_id = projections.users6.id AND preferred_login_name.instance_id = projections.users6.instance_id` userCols = []string{ "id", "creation_date", @@ -86,21 +88,21 @@ var ( "description", "count", } - profileQuery = `SELECT projections.users5.id,` + - ` projections.users5.creation_date,` + - ` projections.users5.change_date,` + - ` projections.users5.resource_owner,` + - ` projections.users5.sequence,` + - ` projections.users5_humans.user_id,` + - ` projections.users5_humans.first_name,` + - ` projections.users5_humans.last_name,` + - ` projections.users5_humans.nick_name,` + - ` projections.users5_humans.display_name,` + - ` projections.users5_humans.preferred_language,` + - ` projections.users5_humans.gender,` + - ` projections.users5_humans.avatar_key` + - ` FROM projections.users5` + - ` LEFT JOIN projections.users5_humans ON projections.users5.id = projections.users5_humans.user_id AND projections.users5.instance_id = projections.users5_humans.instance_id` + profileQuery = `SELECT projections.users6.id,` + + ` projections.users6.creation_date,` + + ` projections.users6.change_date,` + + ` projections.users6.resource_owner,` + + ` projections.users6.sequence,` + + ` projections.users6_humans.user_id,` + + ` projections.users6_humans.first_name,` + + ` projections.users6_humans.last_name,` + + ` projections.users6_humans.nick_name,` + + ` projections.users6_humans.display_name,` + + ` projections.users6_humans.preferred_language,` + + ` projections.users6_humans.gender,` + + ` projections.users6_humans.avatar_key` + + ` FROM projections.users6` + + ` LEFT JOIN projections.users6_humans ON projections.users6.id = projections.users6_humans.user_id AND projections.users6.instance_id = projections.users6_humans.instance_id` profileCols = []string{ "id", "creation_date", @@ -116,16 +118,16 @@ var ( "gender", "avatar_key", } - emailQuery = `SELECT projections.users5.id,` + - ` projections.users5.creation_date,` + - ` projections.users5.change_date,` + - ` projections.users5.resource_owner,` + - ` projections.users5.sequence,` + - ` projections.users5_humans.user_id,` + - ` projections.users5_humans.email,` + - ` projections.users5_humans.is_email_verified` + - ` FROM projections.users5` + - ` LEFT JOIN projections.users5_humans ON projections.users5.id = projections.users5_humans.user_id AND projections.users5.instance_id = projections.users5_humans.instance_id` + emailQuery = `SELECT projections.users6.id,` + + ` projections.users6.creation_date,` + + ` projections.users6.change_date,` + + ` projections.users6.resource_owner,` + + ` projections.users6.sequence,` + + ` projections.users6_humans.user_id,` + + ` projections.users6_humans.email,` + + ` projections.users6_humans.is_email_verified` + + ` FROM projections.users6` + + ` LEFT JOIN projections.users6_humans ON projections.users6.id = projections.users6_humans.user_id AND projections.users6.instance_id = projections.users6_humans.instance_id` emailCols = []string{ "id", "creation_date", @@ -136,16 +138,16 @@ var ( "email", "is_email_verified", } - phoneQuery = `SELECT projections.users5.id,` + - ` projections.users5.creation_date,` + - ` projections.users5.change_date,` + - ` projections.users5.resource_owner,` + - ` projections.users5.sequence,` + - ` projections.users5_humans.user_id,` + - ` projections.users5_humans.phone,` + - ` projections.users5_humans.is_phone_verified` + - ` FROM projections.users5` + - ` LEFT JOIN projections.users5_humans ON projections.users5.id = projections.users5_humans.user_id AND projections.users5.instance_id = projections.users5_humans.instance_id` + phoneQuery = `SELECT projections.users6.id,` + + ` projections.users6.creation_date,` + + ` projections.users6.change_date,` + + ` projections.users6.resource_owner,` + + ` projections.users6.sequence,` + + ` projections.users6_humans.user_id,` + + ` projections.users6_humans.phone,` + + ` projections.users6_humans.is_phone_verified` + + ` FROM projections.users6` + + ` LEFT JOIN projections.users6_humans ON projections.users6.id = projections.users6_humans.user_id AND projections.users6.instance_id = projections.users6_humans.instance_id` phoneCols = []string{ "id", "creation_date", @@ -156,14 +158,14 @@ var ( "phone", "is_phone_verified", } - userUniqueQuery = `SELECT projections.users5.id,` + - ` projections.users5.state,` + - ` projections.users5.username,` + - ` projections.users5_humans.user_id,` + - ` projections.users5_humans.email,` + - ` projections.users5_humans.is_email_verified` + - ` FROM projections.users5` + - ` LEFT JOIN projections.users5_humans ON projections.users5.id = projections.users5_humans.user_id AND projections.users5.instance_id = projections.users5_humans.instance_id` + userUniqueQuery = `SELECT projections.users6.id,` + + ` projections.users6.state,` + + ` projections.users6.username,` + + ` projections.users6_humans.user_id,` + + ` projections.users6_humans.email,` + + ` projections.users6_humans.is_email_verified` + + ` FROM projections.users6` + + ` LEFT JOIN projections.users6_humans ON projections.users6.id = projections.users6_humans.user_id AND projections.users6.instance_id = projections.users6_humans.instance_id` userUniqueCols = []string{ "id", "state", @@ -172,44 +174,40 @@ var ( "email", "is_email_verified", } - notifyUserQuery = `SELECT projections.users5.id,` + - ` projections.users5.creation_date,` + - ` projections.users5.change_date,` + - ` projections.users5.resource_owner,` + - ` projections.users5.sequence,` + - ` projections.users5.state,` + - ` projections.users5.type,` + - ` projections.users5.username,` + + notifyUserQuery = `SELECT projections.users6.id,` + + ` projections.users6.creation_date,` + + ` projections.users6.change_date,` + + ` projections.users6.resource_owner,` + + ` projections.users6.sequence,` + + ` projections.users6.state,` + + ` projections.users6.type,` + + ` projections.users6.username,` + ` login_names.loginnames,` + ` preferred_login_name.login_name,` + - ` projections.users5_humans.user_id,` + - ` projections.users5_humans.first_name,` + - ` projections.users5_humans.last_name,` + - ` projections.users5_humans.nick_name,` + - ` projections.users5_humans.display_name,` + - ` projections.users5_humans.preferred_language,` + - ` projections.users5_humans.gender,` + - ` projections.users5_humans.avatar_key,` + - ` projections.users5_notifications.user_id,` + - ` projections.users5_notifications.last_email,` + - ` projections.users5_notifications.verified_email,` + - ` projections.users5_notifications.last_phone,` + - ` projections.users5_notifications.verified_phone,` + - ` projections.users5_notifications.password_set,` + + ` projections.users6_humans.user_id,` + + ` projections.users6_humans.first_name,` + + ` projections.users6_humans.last_name,` + + ` projections.users6_humans.nick_name,` + + ` projections.users6_humans.display_name,` + + ` projections.users6_humans.preferred_language,` + + ` projections.users6_humans.gender,` + + ` projections.users6_humans.avatar_key,` + + ` projections.users6_notifications.user_id,` + + ` projections.users6_notifications.last_email,` + + ` projections.users6_notifications.verified_email,` + + ` projections.users6_notifications.last_phone,` + + ` projections.users6_notifications.verified_phone,` + + ` projections.users6_notifications.password_set,` + ` COUNT(*) OVER ()` + - ` FROM projections.users5` + - ` LEFT JOIN projections.users5_humans ON projections.users5.id = projections.users5_humans.user_id AND projections.users5.instance_id = projections.users5_humans.instance_id` + - ` LEFT JOIN projections.users5_notifications ON projections.users5.id = projections.users5_notifications.user_id AND projections.users5.instance_id = projections.users5_notifications.instance_id` + + ` FROM projections.users6` + + ` LEFT JOIN projections.users6_humans ON projections.users6.id = projections.users6_humans.user_id AND projections.users6.instance_id = projections.users6_humans.instance_id` + + ` LEFT JOIN projections.users6_notifications ON projections.users6.id = projections.users6_notifications.user_id AND projections.users6.instance_id = projections.users6_notifications.instance_id` + ` LEFT JOIN` + - ` (SELECT login_names.user_id, ARRAY_AGG(login_names.login_name) AS loginnames, login_names.instance_id` + - ` FROM projections.login_names AS login_names` + - ` GROUP BY login_names.user_id, login_names.instance_id) AS login_names` + - ` ON login_names.user_id = projections.users5.id AND login_names.instance_id = projections.users5.instance_id` + + ` (` + loginNamesQuery + `) AS login_names` + + ` ON login_names.user_id = projections.users6.id AND login_names.instance_id = projections.users6.instance_id` + ` LEFT JOIN` + - ` (SELECT preferred_login_name.user_id, preferred_login_name.login_name, preferred_login_name.instance_id` + - ` FROM projections.login_names AS preferred_login_name` + - ` WHERE preferred_login_name.is_primary = $1) AS preferred_login_name` + - ` ON preferred_login_name.user_id = projections.users5.id AND preferred_login_name.instance_id = projections.users5.instance_id` + ` (` + preferredLoginNameQuery + `) AS preferred_login_name` + + ` ON preferred_login_name.user_id = projections.users6.id AND preferred_login_name.instance_id = projections.users6.instance_id` notifyUserCols = []string{ "id", "creation_date", @@ -239,45 +237,41 @@ var ( "password_set", "count", } - usersQuery = `SELECT projections.users5.id,` + - ` projections.users5.creation_date,` + - ` projections.users5.change_date,` + - ` projections.users5.resource_owner,` + - ` projections.users5.sequence,` + - ` projections.users5.state,` + - ` projections.users5.type,` + - ` projections.users5.username,` + + usersQuery = `SELECT projections.users6.id,` + + ` projections.users6.creation_date,` + + ` projections.users6.change_date,` + + ` projections.users6.resource_owner,` + + ` projections.users6.sequence,` + + ` projections.users6.state,` + + ` projections.users6.type,` + + ` projections.users6.username,` + ` login_names.loginnames,` + ` preferred_login_name.login_name,` + - ` projections.users5_humans.user_id,` + - ` projections.users5_humans.first_name,` + - ` projections.users5_humans.last_name,` + - ` projections.users5_humans.nick_name,` + - ` projections.users5_humans.display_name,` + - ` projections.users5_humans.preferred_language,` + - ` projections.users5_humans.gender,` + - ` projections.users5_humans.avatar_key,` + - ` projections.users5_humans.email,` + - ` projections.users5_humans.is_email_verified,` + - ` projections.users5_humans.phone,` + - ` projections.users5_humans.is_phone_verified,` + - ` projections.users5_machines.user_id,` + - ` projections.users5_machines.name,` + - ` projections.users5_machines.description,` + + ` projections.users6_humans.user_id,` + + ` projections.users6_humans.first_name,` + + ` projections.users6_humans.last_name,` + + ` projections.users6_humans.nick_name,` + + ` projections.users6_humans.display_name,` + + ` projections.users6_humans.preferred_language,` + + ` projections.users6_humans.gender,` + + ` projections.users6_humans.avatar_key,` + + ` projections.users6_humans.email,` + + ` projections.users6_humans.is_email_verified,` + + ` projections.users6_humans.phone,` + + ` projections.users6_humans.is_phone_verified,` + + ` projections.users6_machines.user_id,` + + ` projections.users6_machines.name,` + + ` projections.users6_machines.description,` + ` COUNT(*) OVER ()` + - ` FROM projections.users5` + - ` LEFT JOIN projections.users5_humans ON projections.users5.id = projections.users5_humans.user_id AND projections.users5.instance_id = projections.users5_humans.instance_id` + - ` LEFT JOIN projections.users5_machines ON projections.users5.id = projections.users5_machines.user_id AND projections.users5.instance_id = projections.users5_machines.instance_id` + + ` FROM projections.users6` + + ` LEFT JOIN projections.users6_humans ON projections.users6.id = projections.users6_humans.user_id AND projections.users6.instance_id = projections.users6_humans.instance_id` + + ` LEFT JOIN projections.users6_machines ON projections.users6.id = projections.users6_machines.user_id AND projections.users6.instance_id = projections.users6_machines.instance_id` + ` LEFT JOIN` + - ` (SELECT login_names.user_id, ARRAY_AGG(login_names.login_name) AS loginnames, login_names.instance_id` + - ` FROM projections.login_names AS login_names` + - ` GROUP BY login_names.user_id, login_names.instance_id) AS login_names` + - ` ON login_names.user_id = projections.users5.id AND login_names.instance_id = projections.users5.instance_id` + + ` (` + loginNamesQuery + `) AS login_names` + + ` ON login_names.user_id = projections.users6.id AND login_names.instance_id = projections.users6.instance_id` + ` LEFT JOIN` + - ` (SELECT preferred_login_name.user_id, preferred_login_name.login_name, preferred_login_name.instance_id` + - ` FROM projections.login_names AS preferred_login_name` + - ` WHERE preferred_login_name.is_primary = $1) AS preferred_login_name` + - ` ON preferred_login_name.user_id = projections.users5.id AND preferred_login_name.instance_id = projections.users5.instance_id` + ` (` + preferredLoginNameQuery + `) AS preferred_login_name` + + ` ON preferred_login_name.user_id = projections.users6.id AND preferred_login_name.instance_id = projections.users6.instance_id` usersCols = []string{ "id", "creation_date", diff --git a/internal/query/zitadel_permission.go b/internal/query/zitadel_permission.go index f274783a0e..fdcde7bc13 100644 --- a/internal/query/zitadel_permission.go +++ b/internal/query/zitadel_permission.go @@ -22,7 +22,7 @@ func (q *Queries) MyZitadelPermissions(ctx context.Context, orgID, userID string } memberships, err := q.Memberships(ctx, &MembershipSearchQuery{ Queries: []SearchQuery{userIDQuery, Or(orgIDsQuery, grantedOrgIDQuery)}, - }) + }, false) if err != nil { return nil, err } diff --git a/internal/repository/org/eventstore.go b/internal/repository/org/eventstore.go index 38a9ccb9d0..895afc827e 100644 --- a/internal/repository/org/eventstore.go +++ b/internal/repository/org/eventstore.go @@ -9,6 +9,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(OrgChangedEventType, OrgChangedEventMapper). RegisterFilterEventMapper(OrgDeactivatedEventType, OrgDeactivatedEventMapper). RegisterFilterEventMapper(OrgReactivatedEventType, OrgReactivatedEventMapper). + RegisterFilterEventMapper(OrgRemovedEventType, OrgRemovedEventMapper). RegisterFilterEventMapper(OrgDomainAddedEventType, DomainAddedEventMapper). RegisterFilterEventMapper(OrgDomainVerificationAddedEventType, DomainVerificationAddedEventMapper). RegisterFilterEventMapper(OrgDomainVerificationFailedEventType, DomainVerificationFailedEventMapper). diff --git a/internal/repository/org/org.go b/internal/repository/org/org.go index 0bd04365c8..7657bef49c 100644 --- a/internal/repository/org/org.go +++ b/internal/repository/org/org.go @@ -4,9 +4,12 @@ import ( "context" "encoding/json" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/repository" + "github.com/zitadel/zitadel/internal/repository/project" + "github.com/zitadel/zitadel/internal/repository/user" ) const ( @@ -169,24 +172,49 @@ func OrgReactivatedEventMapper(event *repository.Event) (eventstore.Event, error type OrgRemovedEvent struct { eventstore.BaseEvent `json:"-"` name string + usernames []string + loginMustBeDomain bool + domains []string + externalIDPs []*domain.UserIDPLink + samlEntityIDs []string } func (e *OrgRemovedEvent) Data() interface{} { - return e + return nil } func (e *OrgRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return []*eventstore.EventUniqueConstraint{NewRemoveOrgNameUniqueConstraint(e.name)} + constraints := []*eventstore.EventUniqueConstraint{ + NewRemoveOrgNameUniqueConstraint(e.name), + } + for _, name := range e.usernames { + constraints = append(constraints, user.NewRemoveUsernameUniqueConstraint(name, e.Aggregate().ID, e.loginMustBeDomain)) + } + for _, domain := range e.domains { + constraints = append(constraints, NewRemoveOrgDomainUniqueConstraint(domain)) + } + for _, idp := range e.externalIDPs { + constraints = append(constraints, user.NewRemoveUserIDPLinkUniqueConstraint(idp.IDPConfigID, idp.ExternalUserID)) + } + for _, entityID := range e.samlEntityIDs { + constraints = append(constraints, project.NewRemoveSAMLConfigEntityIDUniqueConstraint(entityID)) + } + return constraints } -func NewOrgRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name string) *OrgRemovedEvent { +func NewOrgRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name string, usernames []string, loginMustBeDomain bool, domains []string, externalIDPs []*domain.UserIDPLink, samlEntityIDs []string) *OrgRemovedEvent { return &OrgRemovedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, aggregate, OrgRemovedEventType, ), - name: name, + name: name, + usernames: usernames, + domains: domains, + externalIDPs: externalIDPs, + samlEntityIDs: samlEntityIDs, + loginMustBeDomain: loginMustBeDomain, } } diff --git a/internal/repository/user/human.go b/internal/repository/user/human.go index f537837f43..3d72241569 100644 --- a/internal/repository/user/human.go +++ b/internal/repository/user/human.go @@ -5,13 +5,13 @@ import ( "encoding/json" "time" - "github.com/zitadel/zitadel/internal/eventstore" + "golang.org/x/text/language" "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" + "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/repository" - "golang.org/x/text/language" ) const ( diff --git a/internal/user/model/external_idp_view.go b/internal/user/model/external_idp_view.go index a0968cf640..2225f7676c 100644 --- a/internal/user/model/external_idp_view.go +++ b/internal/user/model/external_idp_view.go @@ -36,6 +36,7 @@ const ( ExternalIDPSearchKeyIdpConfigID ExternalIDPSearchKeyResourceOwner ExternalIDPSearchKeyInstanceID + ExternalIDPSearchKeyOwnerRemoved ) type ExternalIDPSearchQuery struct { diff --git a/internal/user/model/user_session_view.go b/internal/user/model/user_session_view.go index ad06d095cc..f610eaa03a 100644 --- a/internal/user/model/user_session_view.go +++ b/internal/user/model/user_session_view.go @@ -46,6 +46,7 @@ const ( UserSessionSearchKeyState UserSessionSearchKeyResourceOwner UserSessionSearchKeyInstanceID + UserSessionSearchKeyOwnerRemoved ) type UserSessionSearchQuery struct { diff --git a/internal/user/model/user_view.go b/internal/user/model/user_view.go index 9de08fddfd..672e18aef1 100644 --- a/internal/user/model/user_view.go +++ b/internal/user/model/user_view.go @@ -94,6 +94,7 @@ const ( UserSearchKeyType UserSearchKeyPreferredLoginName UserSearchKeyInstanceID + UserSearchOwnerRemoved ) type UserSearchQuery struct { diff --git a/internal/user/repository/view/external_idp_view.go b/internal/user/repository/view/external_idp_view.go index 28da8e5c17..4a64557f80 100644 --- a/internal/user/repository/view/external_idp_view.go +++ b/internal/user/repository/view/external_idp_view.go @@ -28,7 +28,12 @@ func ExternalIDPByExternalUserIDAndIDPConfigID(db *gorm.DB, table, externalUserI Method: domain.SearchMethodEquals, Value: instanceID, } - query := repository.PrepareGetByQuery(table, userIDQuery, idpConfigIDQuery, instanceIDQuery) + ownerRemovedQuery := &model.ExternalIDPSearchQuery{ + Key: usr_model.ExternalIDPSearchKeyOwnerRemoved, + Method: domain.SearchMethodEquals, + Value: false, + } + query := repository.PrepareGetByQuery(table, userIDQuery, idpConfigIDQuery, instanceIDQuery, ownerRemovedQuery) err := query(db, user) if caos_errs.IsNotFound(err) { return nil, caos_errs.ThrowNotFound(nil, "VIEW-Mso9f", "Errors.ExternalIDP.NotFound") @@ -58,7 +63,12 @@ func ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(db *gorm.DB, tabl Method: domain.SearchMethodEquals, Value: instanceID, } - query := repository.PrepareGetByQuery(table, userIDQuery, idpConfigIDQuery, resourceOwnerQuery, instanceIDQuery) + ownerRemovedQuery := &model.ExternalIDPSearchQuery{ + Key: usr_model.ExternalIDPSearchKeyOwnerRemoved, + Method: domain.SearchMethodEquals, + Value: false, + } + query := repository.PrepareGetByQuery(table, userIDQuery, idpConfigIDQuery, resourceOwnerQuery, instanceIDQuery, ownerRemovedQuery) err := query(db, user) if caos_errs.IsNotFound(err) { return nil, caos_errs.ThrowNotFound(nil, "VIEW-Sf8sd", "Errors.ExternalIDP.NotFound") @@ -78,8 +88,13 @@ func ExternalIDPsByIDPConfigID(db *gorm.DB, table, idpConfigID, instanceID strin Method: domain.SearchMethodEquals, Value: instanceID, } + ownerRemovedQuery := &usr_model.ExternalIDPSearchQuery{ + Key: usr_model.ExternalIDPSearchKeyOwnerRemoved, + Method: domain.SearchMethodEquals, + Value: false, + } query := repository.PrepareSearchQuery(table, model.ExternalIDPSearchRequest{ - Queries: []*usr_model.ExternalIDPSearchQuery{orgIDQuery, instanceIDQuery}, + Queries: []*usr_model.ExternalIDPSearchQuery{orgIDQuery, instanceIDQuery, ownerRemovedQuery}, }) _, err := query(db, &externalIDPs) return externalIDPs, err @@ -120,3 +135,13 @@ func DeleteInstanceExternalIDPs(db *gorm.DB, table, instanceID string) error { delete := repository.PrepareDeleteByKey(table, model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyInstanceID), instanceID) return delete(db) } + +func UpdateOrgOwnerRemovedExternalIDPs(db *gorm.DB, table, instanceID, aggID string) error { + update := repository.PrepareUpdateByKeys(table, + model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyOwnerRemoved), + true, + repository.Key{Key: model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyInstanceID), Value: instanceID}, + repository.Key{Key: model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyResourceOwner), Value: aggID}, + ) + return update(db) +} diff --git a/internal/user/repository/view/model/external_idp_query.go b/internal/user/repository/view/model/external_idp_query.go index 2f2d304364..d6f193cb7d 100644 --- a/internal/user/repository/view/model/external_idp_query.go +++ b/internal/user/repository/view/model/external_idp_query.go @@ -61,6 +61,8 @@ func (key ExternalIDPSearchKey) ToColumnName() string { return ExternalIDPKeyResourceOwner case usr_model.ExternalIDPSearchKeyInstanceID: return ExternalIDPKeyInstanceID + case usr_model.ExternalIDPSearchKeyOwnerRemoved: + return ExternalIDPKeyOwnerRemoved default: return "" } diff --git a/internal/user/repository/view/model/external_idps.go b/internal/user/repository/view/model/external_idps.go index 79e2a572cb..e8b810d7a9 100644 --- a/internal/user/repository/view/model/external_idps.go +++ b/internal/user/repository/view/model/external_idps.go @@ -18,6 +18,7 @@ const ( ExternalIDPKeyIDPConfigID = "idp_config_id" ExternalIDPKeyResourceOwner = "resource_owner" ExternalIDPKeyInstanceID = "instance_id" + ExternalIDPKeyOwnerRemoved = "owner_removed" ) type ExternalIDPView struct { diff --git a/internal/user/repository/view/model/user.go b/internal/user/repository/view/model/user.go index af00f1eaaa..3d3693aad9 100644 --- a/internal/user/repository/view/model/user.go +++ b/internal/user/repository/view/model/user.go @@ -32,6 +32,7 @@ const ( UserKeyPreferredLoginName = "preferred_login_name" UserKeyType = "user_type" UserKeyInstanceID = "instance_id" + UserKeyOwnerRemoved = "owner_removed" ) type userType string diff --git a/internal/user/repository/view/model/user_query.go b/internal/user/repository/view/model/user_query.go index 7f8f5fbb7d..c44af5e59b 100644 --- a/internal/user/repository/view/model/user_query.go +++ b/internal/user/repository/view/model/user_query.go @@ -77,6 +77,8 @@ func (key UserSearchKey) ToColumnName() string { return UserKeyType case usr_model.UserSearchKeyInstanceID: return UserKeyInstanceID + case usr_model.UserSearchOwnerRemoved: + return UserKeyOwnerRemoved default: return "" } diff --git a/internal/user/repository/view/model/user_session.go b/internal/user/repository/view/model/user_session.go index 9896691b0e..98689590ce 100644 --- a/internal/user/repository/view/model/user_session.go +++ b/internal/user/repository/view/model/user_session.go @@ -21,6 +21,7 @@ const ( UserSessionKeyState = "state" UserSessionKeyResourceOwner = "resource_owner" UserSessionKeyInstanceID = "instance_id" + UserSessionKeyOwnerRemoved = "owner_removed" ) type UserSessionView struct { diff --git a/internal/user/repository/view/model/user_session_query.go b/internal/user/repository/view/model/user_session_query.go index 4e1d91daf7..c5d20ce8ed 100644 --- a/internal/user/repository/view/model/user_session_query.go +++ b/internal/user/repository/view/model/user_session_query.go @@ -61,6 +61,8 @@ func (key UserSessionSearchKey) ToColumnName() string { return UserSessionKeyResourceOwner case usr_model.UserSessionSearchKeyInstanceID: return UserSessionKeyInstanceID + case usr_model.UserSessionSearchKeyOwnerRemoved: + return UserSessionKeyOwnerRemoved default: return "" } diff --git a/internal/user/repository/view/refresh_token_view.go b/internal/user/repository/view/refresh_token_view.go index 168d4e7715..98715cab6c 100644 --- a/internal/user/repository/view/refresh_token_view.go +++ b/internal/user/repository/view/refresh_token_view.go @@ -90,12 +90,26 @@ func DeleteUserRefreshTokens(db *gorm.DB, table, userID, instanceID string) erro return delete(db) } -func DeleteApplicationRefreshTokens(db *gorm.DB, table string, appIDs []string) error { - delete := repository.PrepareDeleteByKey(table, usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyApplicationID), appIDs) +func DeleteApplicationRefreshTokens(db *gorm.DB, table string, instanceID string, appIDs []string) error { + delete := repository.PrepareDeleteByKeys(table, + repository.Key{Key: usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyInstanceID), Value: instanceID}, + repository.Key{Key: usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyApplicationID), Value: appIDs}, + ) + return delete(db) +} + +func DeleteOrgRefreshTokens(db *gorm.DB, table string, instanceID, orgID string) error { + delete := repository.PrepareDeleteByKeys(table, + repository.Key{Key: usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyInstanceID), Value: instanceID}, + repository.Key{Key: usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyResourceOwner), Value: orgID}, + ) return delete(db) } func DeleteInstanceRefreshTokens(db *gorm.DB, table string, instanceID string) error { - delete := repository.PrepareDeleteByKey(table, usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyInstanceID), instanceID) + 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 e24a8f671a..6aaed26e33 100644 --- a/internal/user/repository/view/token_view.go +++ b/internal/user/repository/view/token_view.go @@ -64,8 +64,8 @@ func PutTokens(db *gorm.DB, table string, tokens ...*usr_model.TokenView) error func DeleteToken(db *gorm.DB, table, tokenID, instanceID string) error { delete := repository.PrepareDeleteByKeys(table, - repository.Key{usr_model.TokenSearchKey(model.TokenSearchKeyTokenID), tokenID}, - repository.Key{usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), instanceID}, + repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyTokenID), Value: tokenID}, + repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), Value: instanceID}, ) return delete(db) } @@ -81,29 +81,40 @@ func DeleteSessionTokens(db *gorm.DB, table, agentID, userID, instanceID string) func DeleteUserTokens(db *gorm.DB, table, userID, instanceID string) error { delete := repository.PrepareDeleteByKeys(table, - repository.Key{usr_model.TokenSearchKey(model.TokenSearchKeyUserID), userID}, - repository.Key{usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), instanceID}, + repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyUserID), Value: userID}, + repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), Value: instanceID}, ) return delete(db) } func DeleteTokensFromRefreshToken(db *gorm.DB, table, refreshTokenID, instanceID string) error { delete := repository.PrepareDeleteByKeys(table, - repository.Key{usr_model.TokenSearchKey(model.TokenSearchKeyRefreshTokenID), refreshTokenID}, - repository.Key{usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), instanceID}, + repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyRefreshTokenID), Value: refreshTokenID}, + repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), Value: instanceID}, ) return delete(db) } func DeleteApplicationTokens(db *gorm.DB, table, instanceID string, appIDs []string) error { delete := repository.PrepareDeleteByKeys(table, - repository.Key{usr_model.TokenSearchKey(model.TokenSearchKeyApplicationID), appIDs}, - repository.Key{usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), instanceID}, + repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyApplicationID), Value: appIDs}, + repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), Value: instanceID}, ) return delete(db) } func DeleteInstanceTokens(db *gorm.DB, table, instanceID string) error { - delete := repository.PrepareDeleteByKey(table, usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), instanceID) + delete := repository.PrepareDeleteByKey(table, + usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), + instanceID, + ) + return delete(db) +} + +func DeleteOrgTokens(db *gorm.DB, table, instanceID, orgID string) error { + delete := repository.PrepareDeleteByKeys(table, + repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyResourceOwner), Value: orgID}, + repository.Key{Key: usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), Value: 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 cc6dbf80bb..7b75c31d3c 100644 --- a/internal/user/repository/view/user_session_view.go +++ b/internal/user/repository/view/user_session_view.go @@ -120,13 +120,24 @@ func PutUserSessions(db *gorm.DB, table string, sessions ...*model.UserSessionVi func DeleteUserSessions(db *gorm.DB, table, userID, instanceID string) error { delete := repository.PrepareDeleteByKeys(table, - repository.Key{model.UserSessionSearchKey(usr_model.UserSessionSearchKeyUserID), userID}, - repository.Key{model.UserSessionSearchKey(usr_model.UserSessionSearchKeyInstanceID), instanceID}, + repository.Key{Key: model.UserSessionSearchKey(usr_model.UserSessionSearchKeyUserID), Value: userID}, + repository.Key{Key: model.UserSessionSearchKey(usr_model.UserSessionSearchKeyInstanceID), Value: instanceID}, ) return delete(db) } func DeleteInstanceUserSessions(db *gorm.DB, table, instanceID string) error { - delete := repository.PrepareDeleteByKey(table, model.UserSessionSearchKey(usr_model.UserSessionSearchKeyInstanceID), instanceID) + delete := repository.PrepareDeleteByKey(table, + model.UserSessionSearchKey(usr_model.UserSessionSearchKeyInstanceID), + instanceID, + ) + return delete(db) +} + +func DeleteOrgUserSessions(db *gorm.DB, table, instanceID, orgID string) error { + delete := repository.PrepareDeleteByKeys(table, + repository.Key{Key: model.UserSessionSearchKey(usr_model.UserSessionSearchKeyResourceOwner), Value: orgID}, + repository.Key{Key: model.UserSessionSearchKey(usr_model.UserSessionSearchKeyInstanceID), Value: instanceID}, + ) return delete(db) } diff --git a/internal/user/repository/view/user_view.go b/internal/user/repository/view/user_view.go index d0d2d0e71d..f70fcf393e 100644 --- a/internal/user/repository/view/user_view.go +++ b/internal/user/repository/view/user_view.go @@ -23,7 +23,12 @@ func UserByID(db *gorm.DB, table, userID, instanceID string) (*model.UserView, e Method: domain.SearchMethodEquals, Value: instanceID, } - query := repository.PrepareGetByQuery(table, userIDQuery, instanceIDQuery) + ownerRemovedQuery := &model.UserSearchQuery{ + Key: usr_model.UserSearchOwnerRemoved, + Method: domain.SearchMethodEquals, + Value: false, + } + query := repository.PrepareGetByQuery(table, userIDQuery, instanceIDQuery, ownerRemovedQuery) err := query(db, user) if caos_errs.IsNotFound(err) { return nil, caos_errs.ThrowNotFound(nil, "VIEW-sj8Sw", "Errors.User.NotFound") @@ -44,7 +49,12 @@ func UserByUserName(db *gorm.DB, table, userName, instanceID string) (*model.Use Method: domain.SearchMethodEquals, Value: instanceID, } - query := repository.PrepareGetByQuery(table, userNameQuery, instanceIDQuery) + ownerRemovedQuery := &model.UserSearchQuery{ + Key: usr_model.UserSearchOwnerRemoved, + Method: domain.SearchMethodEquals, + Value: false, + } + query := repository.PrepareGetByQuery(table, userNameQuery, instanceIDQuery, ownerRemovedQuery) err := query(db, user) if caos_errs.IsNotFound(err) { return nil, caos_errs.ThrowNotFound(nil, "VIEW-Lso9s", "Errors.User.NotFound") @@ -65,7 +75,12 @@ func UserByLoginName(db *gorm.DB, table, loginName, instanceID string) (*model.U Method: domain.SearchMethodEquals, Value: instanceID, } - query := repository.PrepareGetByQuery(table, loginNameQuery, instanceIDQuery) + ownerRemovedQuery := &model.UserSearchQuery{ + Key: usr_model.UserSearchOwnerRemoved, + Method: domain.SearchMethodEquals, + Value: false, + } + query := repository.PrepareGetByQuery(table, loginNameQuery, instanceIDQuery, ownerRemovedQuery) err := query(db, user) if caos_errs.IsNotFound(err) { return nil, caos_errs.ThrowNotFound(nil, "VIEW-AD4qs", "Errors.User.NotFound") @@ -91,7 +106,12 @@ func UserByLoginNameAndResourceOwner(db *gorm.DB, table, loginName, resourceOwne Method: domain.SearchMethodEquals, Value: instanceID, } - query := repository.PrepareGetByQuery(table, loginNameQuery, resourceOwnerQuery, instanceIDQuery) + ownerRemovedQuery := &model.UserSearchQuery{ + Key: usr_model.UserSearchOwnerRemoved, + Method: domain.SearchMethodEquals, + Value: false, + } + query := repository.PrepareGetByQuery(table, loginNameQuery, resourceOwnerQuery, instanceIDQuery, ownerRemovedQuery) err := query(db, user) if caos_errs.IsNotFound(err) { return nil, caos_errs.ThrowNotFound(nil, "VIEW-AD4qs", "Errors.User.NotFoundOnOrg") @@ -112,8 +132,13 @@ func UsersByOrgID(db *gorm.DB, table, orgID, instanceID string) ([]*model.UserVi Method: domain.SearchMethodEquals, Value: instanceID, } + ownerRemovedQuery := &usr_model.UserSearchQuery{ + Key: usr_model.UserSearchOwnerRemoved, + Method: domain.SearchMethodEquals, + Value: false, + } query := repository.PrepareSearchQuery(table, model.UserSearchRequest{ - Queries: []*usr_model.UserSearchQuery{orgIDQuery, instanceIDQuery}, + Queries: []*usr_model.UserSearchQuery{orgIDQuery, instanceIDQuery, ownerRemovedQuery}, }) _, err := query(db, &users) return users, err @@ -134,8 +159,13 @@ func UserIDsByDomain(db *gorm.DB, table, orgDomain, instanceID string) ([]string Method: domain.SearchMethodEquals, Value: instanceID, } + ownerRemovedQuery := &usr_model.UserSearchQuery{ + Key: usr_model.UserSearchOwnerRemoved, + Method: domain.SearchMethodEquals, + Value: false, + } query := repository.PrepareSearchQuery(table, model.UserSearchRequest{ - Queries: []*usr_model.UserSearchQuery{orgIDQuery, instanceIDQuery}, + Queries: []*usr_model.UserSearchQuery{orgIDQuery, instanceIDQuery, ownerRemovedQuery}, }) _, err := query(db, &ids) if err != nil { @@ -163,6 +193,7 @@ func GetGlobalUserByLoginName(db *gorm.DB, table, loginName, instanceID string) query := repository.PrepareGetByQuery(table, &model.UserSearchQuery{Key: usr_model.UserSearchKeyLoginNames, Value: loginName, Method: domain.SearchMethodListContains}, &model.UserSearchQuery{Key: usr_model.UserSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals}, + &model.UserSearchQuery{Key: usr_model.UserSearchOwnerRemoved, Value: false, Method: domain.SearchMethodEquals}, ) err := query(db, user) if caos_errs.IsNotFound(err) { @@ -209,3 +240,13 @@ func DeleteInstanceUsers(db *gorm.DB, table, instanceID string) error { delete := repository.PrepareDeleteByKey(table, model.UserSearchKey(usr_model.UserSearchKeyInstanceID), instanceID) return delete(db) } + +func UpdateOrgOwnerRemovedUsers(db *gorm.DB, table, instanceID, aggID string) error { + update := repository.PrepareUpdateByKeys(table, + model.UserSearchKey(usr_model.UserSearchOwnerRemoved), + true, + repository.Key{Key: model.UserSearchKey(usr_model.UserSearchKeyInstanceID), Value: instanceID}, + repository.Key{Key: model.UserSearchKey(usr_model.UserSearchKeyResourceOwner), Value: aggID}, + ) + return update(db) +} diff --git a/internal/view/repository/requests.go b/internal/view/repository/requests.go index 29f28b25a9..a624643c46 100644 --- a/internal/view/repository/requests.go +++ b/internal/view/repository/requests.go @@ -109,6 +109,22 @@ func PrepareDeleteByKey(table string, key ColumnKey, id interface{}) func(db *go } } +func PrepareUpdateByKeys(table string, column ColumnKey, value interface{}, keys ...Key) func(db *gorm.DB) error { + return func(db *gorm.DB) error { + for _, key := range keys { + db = db.Table(table). + Where(fmt.Sprintf("%s = ?", key.Key.ToColumnName()), key.Value) + } + err := db. + Update(column.ToColumnName(), value). + Error + if err != nil { + return caos_errs.ThrowInternal(err, "VIEW-ps099xj", "could not update object") + } + return nil + } +} + type Key struct { Key ColumnKey Value interface{} diff --git a/internal/view/repository/requests_test.go b/internal/view/repository/requests_test.go index a933c77bd1..46c4e1532f 100644 --- a/internal/view/repository/requests_test.go +++ b/internal/view/repository/requests_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/jinzhu/gorm" + "github.com/zitadel/zitadel/internal/domain" caos_errs "github.com/zitadel/zitadel/internal/errors" ) diff --git a/proto/zitadel/management.proto b/proto/zitadel/management.proto index e74863a896..4bf22edb65 100644 --- a/proto/zitadel/management.proto +++ b/proto/zitadel/management.proto @@ -841,6 +841,18 @@ service ManagementService { }; } + // Sets the state of my organisation and all its resource (Users, Projects, Grants to and from the org) to removed + // Users of this organisation will not be able login + rpc RemoveOrg(RemoveOrgRequest) returns (RemoveOrgResponse) { + option (google.api.http) = { + delete: "/orgs/me" + }; + + option (zitadel.v1.auth_option) = { + permission: "org.delete" + }; + } + // Sets a org metadata by key rpc SetOrgMetadata(SetOrgMetadataRequest) returns (SetOrgMetadataResponse) { option (google.api.http) = { @@ -3678,6 +3690,12 @@ message ReactivateOrgResponse { zitadel.v1.ObjectDetails details = 1; } +message RemoveOrgRequest {} + +message RemoveOrgResponse { + zitadel.v1.ObjectDetails details = 1; +} + message ListOrgDomainsRequest { //list limitations and ordering zitadel.v1.ListQuery query = 1; diff --git a/proto/zitadel/org.proto b/proto/zitadel/org.proto index 88c4e42c4f..ef278724c6 100644 --- a/proto/zitadel/org.proto +++ b/proto/zitadel/org.proto @@ -36,6 +36,7 @@ enum OrgState { ORG_STATE_UNSPECIFIED = 0; ORG_STATE_ACTIVE = 1; ORG_STATE_INACTIVE = 2; + ORG_STATE_REMOVED = 3; } message Domain {