diff --git a/cmd/setup/67.go b/cmd/setup/67.go new file mode 100644 index 000000000..9859a6db1 --- /dev/null +++ b/cmd/setup/67.go @@ -0,0 +1,27 @@ +package setup + +import ( + "context" + _ "embed" + + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/eventstore" +) + +var ( + //go:embed 67.sql + syncMemberRoleFields string +) + +type SyncMemberRoleFields struct { + dbClient *database.DB +} + +func (mig *SyncMemberRoleFields) Execute(ctx context.Context, _ eventstore.Event) error { + _, err := mig.dbClient.ExecContext(ctx, syncMemberRoleFields) + return err +} + +func (mig *SyncMemberRoleFields) String() string { + return "67_sync_member_role_fields" +} diff --git a/cmd/setup/67.sql b/cmd/setup/67.sql new file mode 100644 index 000000000..ac5a060b0 --- /dev/null +++ b/cmd/setup/67.sql @@ -0,0 +1,71 @@ +-- Make sure no other transaction is writing to fields table. +-- Will block transactions with events that modify the fields table. +-- SELECT is still possible during this time. +LOCK TABLE eventstore.fields IN SHARE ROW EXCLUSIVE MODE; + +DELETE FROM eventstore.fields + WHERE object_type IN ( + 'instance_member_role', + 'org_member_role', + 'project_member_role' + ); + +INSERT INTO eventstore.fields( + instance_id, + resource_owner, + aggregate_type, + aggregate_id, + object_type, + object_id, + object_revision, + field_name, + value, + value_must_be_unique, + should_index +) + +SELECT + instance_id, + resource_owner, + 'instance' as aggregate_type, + id as aggregate_id, + 'instance_member_role' as object_type, + user_id as object_id, + 1::smallint as object_revision, + 'instance_role' as field_name, + to_jsonb(unnest(roles)) as value, + false as value_must_be_unique, + true as should_index +FROM projections.instance_members4 + +UNION ALL + +SELECT + instance_id, + resource_owner, + 'org' as aggregate_type, + org_id as aggregate_id, + 'org_member_role' as object_type, + user_id as object_id, + 1::smallint as object_revision, + 'org_role' as field_name, + to_jsonb(unnest(roles)) as value, + false as value_must_be_unique, + true as should_index +FROM projections.org_members4 + +UNION ALL + +SELECT + instance_id, + resource_owner, + 'project' as aggregate_type, + project_id as aggregate_id, + 'project_member_role' as object_type, + user_id as object_id, + 1::smallint as object_revision, + 'project_role' as field_name, + to_jsonb(unnest(roles)) as value, + false as value_must_be_unique, + true as should_index +FROM projections.project_members4; diff --git a/cmd/setup/config.go b/cmd/setup/config.go index ec22c5fd4..33a39c4fe 100644 --- a/cmd/setup/config.go +++ b/cmd/setup/config.go @@ -163,6 +163,7 @@ type Steps struct { s64ChangePushPosition *ChangePushPosition s65FixUserMetadata5Index *FixUserMetadata5Index s66SessionRecoveryCodeCheckedAt *SessionRecoveryCodeCheckedAt + s67SyncMemberRoleFields *SyncMemberRoleFields } func MustNewSteps(v *viper.Viper) *Steps { diff --git a/cmd/setup/setup.go b/cmd/setup/setup.go index e5bcd1268..76a1cd4d3 100644 --- a/cmd/setup/setup.go +++ b/cmd/setup/setup.go @@ -224,6 +224,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string) steps.s64ChangePushPosition = &ChangePushPosition{dbClient: dbClient} steps.s65FixUserMetadata5Index = &FixUserMetadata5Index{dbClient: dbClient} steps.s66SessionRecoveryCodeCheckedAt = &SessionRecoveryCodeCheckedAt{dbClient: dbClient} + steps.s67SyncMemberRoleFields = &SyncMemberRoleFields{dbClient: dbClient} err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil, nil) logging.OnError(err).Fatal("unable to start projections") @@ -340,6 +341,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string) steps.s48Apps7SAMLConfigsLoginVersion, steps.s59SetupWebkeys, // this step needs commands. steps.s66SessionRecoveryCodeCheckedAt, + steps.s67SyncMemberRoleFields, } { setupErr = executeMigration(ctx, eventstoreClient, step, "migration failed") if setupErr != nil {