From 217703395e86553f47aeb74e0ecaa847570abbdb Mon Sep 17 00:00:00 2001 From: Stefan Benz <46600784+stebenz@users.noreply.github.com> Date: Thu, 28 Mar 2024 07:21:21 +0100 Subject: [PATCH] feat: add user v2 pw change required information on query (#7603) * fix: add resource owner as query for user v2 ListUsers and clean up deprecated attribute * fix: add resource owner as query for user v2 ListUsers and clean up deprecated attribute * fix: add resource owner as query for user v2 ListUsers and clean up deprecated attribute * fix: review changes * fix: review changes * fix: review changes * fix: review changes * fix: add password change required to user v2 get and list * fix: update unit tests for query side with new column and projection * fix: change projection in setup steps * fix: change projection in setup steps * fix: remove setup step 25 * fix: add password_change_required into ListUsers response * fix: correct SetUserPassword parameters * fix: rollback to change setup instead of projection directly * fix: rollback to change setup instead of projection directly --------- Co-authored-by: Livio Spring --- cmd/setup/25.go | 8 +- cmd/setup/25.sql | 4 +- cmd/setup/config.go | 44 +-- cmd/setup/setup.go | 4 +- .../session/v2/session_integration_test.go | 6 +- internal/api/grpc/user/v2/query.go | 1 + .../grpc/user/v2/query_integration_test.go | 136 ++++++- internal/api/oidc/oidc_integration_test.go | 4 +- internal/integration/client.go | 9 +- internal/query/embed/userinfo_by_id.sql | 6 +- internal/query/iam_member_test.go | 26 +- internal/query/org_member_test.go | 32 +- internal/query/project_grant_member_test.go | 32 +- internal/query/project_member_test.go | 32 +- internal/query/projection/user.go | 43 ++- internal/query/projection/user_test.go | 254 ++++++++----- internal/query/sessions_test.go | 12 +- internal/query/user.go | 80 +++-- internal/query/user_auth_method_test.go | 22 +- internal/query/user_by_id.sql | 7 +- internal/query/user_by_login_name.sql | 7 +- internal/query/user_grant_test.go | 44 +-- internal/query/user_notify_by_id.sql | 6 +- internal/query/user_notify_by_login_name.sql | 6 +- internal/query/user_test.go | 339 +++++++++--------- .../repository/view/user_session_by_id.sql | 4 +- .../view/user_sessions_by_user_agent.sql | 4 +- proto/zitadel/user/v2beta/user.proto | 10 + 28 files changed, 723 insertions(+), 459 deletions(-) diff --git a/cmd/setup/25.go b/cmd/setup/25.go index 7a6ac6eccf..1747981468 100644 --- a/cmd/setup/25.go +++ b/cmd/setup/25.go @@ -13,15 +13,15 @@ var ( addLowerFieldsToVerifiedEmail string ) -type AddLowerFieldsToVerifiedEmail struct { +type User11AddLowerFieldsToVerifiedEmail struct { dbClient *database.DB } -func (mig *AddLowerFieldsToVerifiedEmail) Execute(ctx context.Context, _ eventstore.Event) error { +func (mig *User11AddLowerFieldsToVerifiedEmail) Execute(ctx context.Context, _ eventstore.Event) error { _, err := mig.dbClient.ExecContext(ctx, addLowerFieldsToVerifiedEmail) return err } -func (mig *AddLowerFieldsToVerifiedEmail) String() string { - return "25_add_lower_fields_to_verified_email" +func (mig *User11AddLowerFieldsToVerifiedEmail) String() string { + return "25_user11_add_lower_fields_to_verified_email" } diff --git a/cmd/setup/25.sql b/cmd/setup/25.sql index 59db819847..870c04ea66 100644 --- a/cmd/setup/25.sql +++ b/cmd/setup/25.sql @@ -1,2 +1,2 @@ -ALTER TABLE IF EXISTS projections.users10_notifications ADD COLUMN IF NOT EXISTS verified_email_lower TEXT GENERATED ALWAYS AS (lower(verified_email)) STORED; -CREATE INDEX IF NOT EXISTS users10_notifications_email_search ON projections.users10_notifications (instance_id, verified_email_lower); +ALTER TABLE IF EXISTS projections.users11_notifications ADD COLUMN IF NOT EXISTS verified_email_lower TEXT GENERATED ALWAYS AS (lower(verified_email)) STORED; +CREATE INDEX IF NOT EXISTS users11_notifications_email_search ON projections.users11_notifications (instance_id, verified_email_lower); \ No newline at end of file diff --git a/cmd/setup/config.go b/cmd/setup/config.go index 510999bcce..8c44f0b21a 100644 --- a/cmd/setup/config.go +++ b/cmd/setup/config.go @@ -82,28 +82,28 @@ func MustNewConfig(v *viper.Viper) *Config { } type Steps struct { - s1ProjectionTable *ProjectionTable - s2AssetsTable *AssetTable - FirstInstance *FirstInstance - s5LastFailed *LastFailed - s6OwnerRemoveColumns *OwnerRemoveColumns - s7LogstoreTables *LogstoreTables - s8AuthTokens *AuthTokenIndexes - CorrectCreationDate *CorrectCreationDate - s12AddOTPColumns *AddOTPColumns - s13FixQuotaProjection *FixQuotaConstraints - s14NewEventsTable *NewEventsTable - s15CurrentStates *CurrentProjectionState - s16UniqueConstraintsLower *UniqueConstraintToLower - s17AddOffsetToUniqueConstraints *AddOffsetToCurrentStates - s18AddLowerFieldsToLoginNames *AddLowerFieldsToLoginNames - s19AddCurrentStatesIndex *AddCurrentSequencesIndex - s20AddByUserSessionIndex *AddByUserIndexToSession - s21AddBlockFieldToLimits *AddBlockFieldToLimits - s22ActiveInstancesIndex *ActiveInstanceEvents - s23CorrectGlobalUniqueConstraints *CorrectGlobalUniqueConstraints - s24AddActorToAuthTokens *AddActorToAuthTokens - s25AddLowerFieldsToVerifiedEmail *AddLowerFieldsToVerifiedEmail + s1ProjectionTable *ProjectionTable + s2AssetsTable *AssetTable + FirstInstance *FirstInstance + s5LastFailed *LastFailed + s6OwnerRemoveColumns *OwnerRemoveColumns + s7LogstoreTables *LogstoreTables + s8AuthTokens *AuthTokenIndexes + CorrectCreationDate *CorrectCreationDate + s12AddOTPColumns *AddOTPColumns + s13FixQuotaProjection *FixQuotaConstraints + s14NewEventsTable *NewEventsTable + s15CurrentStates *CurrentProjectionState + s16UniqueConstraintsLower *UniqueConstraintToLower + s17AddOffsetToUniqueConstraints *AddOffsetToCurrentStates + s18AddLowerFieldsToLoginNames *AddLowerFieldsToLoginNames + s19AddCurrentStatesIndex *AddCurrentSequencesIndex + s20AddByUserSessionIndex *AddByUserIndexToSession + s21AddBlockFieldToLimits *AddBlockFieldToLimits + s22ActiveInstancesIndex *ActiveInstanceEvents + s23CorrectGlobalUniqueConstraints *CorrectGlobalUniqueConstraints + s24AddActorToAuthTokens *AddActorToAuthTokens + s25User11AddLowerFieldsToVerifiedEmail *User11AddLowerFieldsToVerifiedEmail } func MustNewSteps(v *viper.Viper) *Steps { diff --git a/cmd/setup/setup.go b/cmd/setup/setup.go index 16d7b62a7d..693ec81e32 100644 --- a/cmd/setup/setup.go +++ b/cmd/setup/setup.go @@ -137,7 +137,7 @@ func Setup(config *Config, steps *Steps, masterKey string) { steps.s22ActiveInstancesIndex = &ActiveInstanceEvents{dbClient: queryDBClient} steps.s23CorrectGlobalUniqueConstraints = &CorrectGlobalUniqueConstraints{dbClient: esPusherDBClient} steps.s24AddActorToAuthTokens = &AddActorToAuthTokens{dbClient: queryDBClient} - steps.s25AddLowerFieldsToVerifiedEmail = &AddLowerFieldsToVerifiedEmail{dbClient: esPusherDBClient} + steps.s25User11AddLowerFieldsToVerifiedEmail = &User11AddLowerFieldsToVerifiedEmail{dbClient: esPusherDBClient} err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil) logging.OnError(err).Fatal("unable to start projections") @@ -187,7 +187,7 @@ func Setup(config *Config, steps *Steps, masterKey string) { for _, step := range []migration.Migration{ steps.s18AddLowerFieldsToLoginNames, steps.s21AddBlockFieldToLimits, - steps.s25AddLowerFieldsToVerifiedEmail, + steps.s25User11AddLowerFieldsToVerifiedEmail, } { mustExecuteMigration(ctx, eventstoreClient, step, "migration failed") } diff --git a/internal/api/grpc/session/v2/session_integration_test.go b/internal/api/grpc/session/v2/session_integration_test.go index c2893c1b59..3b2ceebbfe 100644 --- a/internal/api/grpc/session/v2/session_integration_test.go +++ b/internal/api/grpc/session/v2/session_integration_test.go @@ -52,7 +52,7 @@ func TestMain(m *testing.M) { UserId: User.GetUserId(), VerificationCode: User.GetPhoneCode(), }) - Tester.SetUserPassword(CTX, User.GetUserId(), integration.UserPassword) + Tester.SetUserPassword(CTX, User.GetUserId(), integration.UserPassword, false) Tester.RegisterUserPasskey(CTX, User.GetUserId()) DeactivatedUser = Tester.CreateHumanUser(CTX) Tester.Client.UserV2.DeactivateUser(CTX, &user.DeactivateUserRequest{UserId: DeactivatedUser.GetUserId()}) @@ -717,11 +717,11 @@ func TestServer_DeleteSession_token(t *testing.T) { func TestServer_DeleteSession_own_session(t *testing.T) { // create two users for the test and a session each to get tokens for authorization user1 := Tester.CreateHumanUser(CTX) - Tester.SetUserPassword(CTX, user1.GetUserId(), integration.UserPassword) + Tester.SetUserPassword(CTX, user1.GetUserId(), integration.UserPassword, false) _, token1, _, _ := Tester.CreatePasswordSession(t, CTX, user1.GetUserId(), integration.UserPassword) user2 := Tester.CreateHumanUser(CTX) - Tester.SetUserPassword(CTX, user2.GetUserId(), integration.UserPassword) + Tester.SetUserPassword(CTX, user2.GetUserId(), integration.UserPassword, false) _, token2, _, _ := Tester.CreatePasswordSession(t, CTX, user2.GetUserId(), integration.UserPassword) // create a new session for the first user diff --git a/internal/api/grpc/user/v2/query.go b/internal/api/grpc/user/v2/query.go index 32cb2775f6..2d0798c2ce 100644 --- a/internal/api/grpc/user/v2/query.go +++ b/internal/api/grpc/user/v2/query.go @@ -101,6 +101,7 @@ func humanToPb(userQ *query.Human, assetPrefix, owner string) *user.HumanUser { Phone: string(userQ.Phone), IsVerified: userQ.IsPhoneVerified, }, + PasswordChangeRequired: userQ.PasswordChangeRequired, } } diff --git a/internal/api/grpc/user/v2/query_integration_test.go b/internal/api/grpc/user/v2/query_integration_test.go index 1d51b6d4e1..5d14249926 100644 --- a/internal/api/grpc/user/v2/query_integration_test.go +++ b/internal/api/grpc/user/v2/query_integration_test.go @@ -8,9 +8,8 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/muhlemmer/gu" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/timestamppb" @@ -102,6 +101,52 @@ func TestServer_GetUserByID(t *testing.T) { }, }, }, + { + name: "user by ID, passwordChangeRequired, ok", + args: args{ + IamCTX, + &user.GetUserByIDRequest{}, + func(ctx context.Context, username string, request *user.GetUserByIDRequest) error { + resp := Tester.CreateHumanUserVerified(ctx, orgResp.OrganizationId, username) + request.UserId = resp.GetUserId() + Tester.SetUserPassword(ctx, resp.GetUserId(), integration.UserPassword, true) + return nil + }, + }, + want: &user.GetUserByIDResponse{ + User: &user.User{ + State: user.UserState_USER_STATE_ACTIVE, + Username: "", + LoginNames: nil, + PreferredLoginName: "", + Type: &user.User_Human{ + Human: &user.HumanUser{ + Profile: &user.HumanProfile{ + GivenName: "Mickey", + FamilyName: "Mouse", + NickName: gu.Ptr("Mickey"), + DisplayName: gu.Ptr("Mickey Mouse"), + PreferredLanguage: gu.Ptr("nl"), + Gender: user.Gender_GENDER_MALE.Enum(), + AvatarUrl: "", + }, + Email: &user.HumanEmail{ + IsVerified: true, + }, + Phone: &user.HumanPhone{ + Phone: "+41791234567", + IsVerified: true, + }, + PasswordChangeRequired: true, + }, + }, + }, + Details: &object.Details{ + ChangeDate: timestamppb.Now(), + ResourceOwner: orgResp.OrganizationId, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -313,7 +358,11 @@ func TestServer_ListUsers(t *testing.T) { args: args{ IamCTX, 1, - &user.ListUsersRequest{}, + &user.ListUsersRequest{ + Queries: []*user.SearchQuery{ + OrganizationIdQuery(orgResp.OrganizationId), + }, + }, func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { infos := make([]userAttr, len(usernames)) userIDs := make([]string, len(usernames)) @@ -358,12 +407,72 @@ func TestServer_ListUsers(t *testing.T) { }, }, }, + { + name: "list user by id, passwordChangeRequired, ok", + args: args{ + IamCTX, + 1, + &user.ListUsersRequest{ + Queries: []*user.SearchQuery{ + OrganizationIdQuery(orgResp.OrganizationId), + }, + }, + func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { + infos := make([]userAttr, len(usernames)) + userIDs := make([]string, len(usernames)) + for i, username := range usernames { + resp := Tester.CreateHumanUserVerified(ctx, orgResp.OrganizationId, username) + userIDs[i] = resp.GetUserId() + Tester.SetUserPassword(ctx, resp.GetUserId(), integration.UserPassword, true) + infos[i] = userAttr{resp.GetUserId(), username} + } + request.Queries = append(request.Queries, InUserIDsQuery(userIDs)) + return infos, nil + }, + }, + want: &user.ListUsersResponse{ + Details: &object.ListDetails{ + TotalResult: 1, + Timestamp: timestamppb.Now(), + }, + SortingColumn: 0, + Result: []*user.User{ + { + State: user.UserState_USER_STATE_ACTIVE, + Type: &user.User_Human{ + Human: &user.HumanUser{ + Profile: &user.HumanProfile{ + GivenName: "Mickey", + FamilyName: "Mouse", + NickName: gu.Ptr("Mickey"), + DisplayName: gu.Ptr("Mickey Mouse"), + PreferredLanguage: gu.Ptr("nl"), + Gender: user.Gender_GENDER_MALE.Enum(), + }, + Email: &user.HumanEmail{ + IsVerified: true, + }, + Phone: &user.HumanPhone{ + Phone: "+41791234567", + IsVerified: true, + }, + PasswordChangeRequired: true, + }, + }, + }, + }, + }, + }, { name: "list user by id multiple, ok", args: args{ IamCTX, 3, - &user.ListUsersRequest{}, + &user.ListUsersRequest{ + Queries: []*user.SearchQuery{ + OrganizationIdQuery(orgResp.OrganizationId), + }, + }, func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { infos := make([]userAttr, len(usernames)) userIDs := make([]string, len(usernames)) @@ -455,7 +564,11 @@ func TestServer_ListUsers(t *testing.T) { args: args{ IamCTX, 1, - &user.ListUsersRequest{}, + &user.ListUsersRequest{ + Queries: []*user.SearchQuery{ + OrganizationIdQuery(orgResp.OrganizationId), + }, + }, func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { infos := make([]userAttr, len(usernames)) userIDs := make([]string, len(usernames)) @@ -505,7 +618,11 @@ func TestServer_ListUsers(t *testing.T) { args: args{ IamCTX, 1, - &user.ListUsersRequest{}, + &user.ListUsersRequest{ + Queries: []*user.SearchQuery{ + OrganizationIdQuery(orgResp.OrganizationId), + }, + }, func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { infos := make([]userAttr, len(usernames)) for i, username := range usernames { @@ -553,7 +670,11 @@ func TestServer_ListUsers(t *testing.T) { args: args{ IamCTX, 3, - &user.ListUsersRequest{}, + &user.ListUsersRequest{ + Queries: []*user.SearchQuery{ + OrganizationIdQuery(orgResp.OrganizationId), + }, + }, func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { infos := make([]userAttr, len(usernames)) for i, username := range usernames { @@ -644,6 +765,7 @@ func TestServer_ListUsers(t *testing.T) { IamCTX, 3, &user.ListUsersRequest{Queries: []*user.SearchQuery{ + OrganizationIdQuery(orgResp.OrganizationId), InUserEmailsQuery([]string{"notfound"}), }, }, diff --git a/internal/api/oidc/oidc_integration_test.go b/internal/api/oidc/oidc_integration_test.go index a5352a3b6e..1e6f8ed118 100644 --- a/internal/api/oidc/oidc_integration_test.go +++ b/internal/api/oidc/oidc_integration_test.go @@ -47,7 +47,7 @@ func TestMain(m *testing.M) { CTX, _ = Tester.WithAuthorization(ctx, integration.OrgOwner), errCtx User = Tester.CreateHumanUser(CTX) - Tester.SetUserPassword(CTX, User.GetUserId(), integration.UserPassword) + Tester.SetUserPassword(CTX, User.GetUserId(), integration.UserPassword, false) Tester.RegisterUserPasskey(CTX, User.GetUserId()) CTXLOGIN, _ = Tester.WithAuthorization(ctx, integration.Login), errCtx return m.Run() @@ -321,7 +321,7 @@ func Test_ZITADEL_API_terminated_session_user_disabled(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { disabledUser := Tester.CreateHumanUser(CTX) - Tester.SetUserPassword(CTX, disabledUser.GetUserId(), integration.UserPassword) + Tester.SetUserPassword(CTX, disabledUser.GetUserId(), integration.UserPassword, false) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope) sessionID, sessionToken, startTime, changeTime := Tester.CreatePasswordSession(t, CTXLOGIN, disabledUser.GetUserId(), integration.UserPassword) linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ diff --git a/internal/integration/client.go b/internal/integration/client.go index 257759b384..48e7dc4a10 100644 --- a/internal/integration/client.go +++ b/internal/integration/client.go @@ -277,10 +277,13 @@ func (s *Tester) RegisterUserU2F(ctx context.Context, userID string) { logging.OnError(err).Fatal("create user u2f") } -func (s *Tester) SetUserPassword(ctx context.Context, userID, password string) { +func (s *Tester) SetUserPassword(ctx context.Context, userID, password string, changeRequired bool) { _, err := s.Client.UserV2.SetPassword(ctx, &user.SetPasswordRequest{ - UserId: userID, - NewPassword: &user.Password{Password: password}, + UserId: userID, + NewPassword: &user.Password{ + Password: password, + ChangeRequired: changeRequired, + }, }) logging.OnError(err).Fatal("set user password") } diff --git a/internal/query/embed/userinfo_by_id.sql b/internal/query/embed/userinfo_by_id.sql index 8b887e8afa..58e0ae10dd 100644 --- a/internal/query/embed/userinfo_by_id.sql +++ b/internal/query/embed/userinfo_by_id.sql @@ -1,6 +1,6 @@ with usr as ( select u.id, u.creation_date, u.change_date, u.sequence, u.state, u.resource_owner, u.username, n.login_name as preferred_login_name - from projections.users10 u + from projections.users11 u left join projections.login_names3 n on u.id = n.user_id and u.instance_id = n.instance_id where u.id = $1 and u.instance_id = $2 @@ -9,7 +9,7 @@ with usr as ( human as ( select $1 as user_id, row_to_json(r) as human from ( select first_name, last_name, nick_name, display_name, avatar_key, preferred_language, gender, email, is_email_verified, phone, is_phone_verified - from projections.users10_humans + from projections.users11_humans where user_id = $1 and instance_id = $2 ) r @@ -17,7 +17,7 @@ human as ( machine as ( select $1 as user_id, row_to_json(r) as machine from ( select name, description - from projections.users10_machines + from projections.users11_machines where user_id = $1 and instance_id = $2 ) r diff --git a/internal/query/iam_member_test.go b/internal/query/iam_member_test.go index 8f1857eae9..074819b0c1 100644 --- a/internal/query/iam_member_test.go +++ b/internal/query/iam_member_test.go @@ -21,21 +21,21 @@ var ( ", members.user_id" + ", members.roles" + ", projections.login_names3.login_name" + - ", projections.users10_humans.email" + - ", projections.users10_humans.first_name" + - ", projections.users10_humans.last_name" + - ", projections.users10_humans.display_name" + - ", projections.users10_machines.name" + - ", projections.users10_humans.avatar_key" + - ", projections.users10.type" + + ", projections.users11_humans.email" + + ", projections.users11_humans.first_name" + + ", projections.users11_humans.last_name" + + ", projections.users11_humans.display_name" + + ", projections.users11_machines.name" + + ", projections.users11_humans.avatar_key" + + ", projections.users11.type" + ", COUNT(*) OVER () " + "FROM projections.instance_members4 AS members " + - "LEFT JOIN projections.users10_humans " + - "ON members.user_id = projections.users10_humans.user_id AND members.instance_id = projections.users10_humans.instance_id " + - "LEFT JOIN projections.users10_machines " + - "ON members.user_id = projections.users10_machines.user_id AND members.instance_id = projections.users10_machines.instance_id " + - "LEFT JOIN projections.users10 " + - "ON members.user_id = projections.users10.id AND members.instance_id = projections.users10.instance_id " + + "LEFT JOIN projections.users11_humans " + + "ON members.user_id = projections.users11_humans.user_id AND members.instance_id = projections.users11_humans.instance_id " + + "LEFT JOIN projections.users11_machines " + + "ON members.user_id = projections.users11_machines.user_id AND members.instance_id = projections.users11_machines.instance_id " + + "LEFT JOIN projections.users11 " + + "ON members.user_id = projections.users11.id AND members.instance_id = projections.users11.instance_id " + "LEFT JOIN projections.login_names3 " + "ON members.user_id = projections.login_names3.user_id AND members.instance_id = projections.login_names3.instance_id " + "AS OF SYSTEM TIME '-1 ms' " + diff --git a/internal/query/org_member_test.go b/internal/query/org_member_test.go index 37443d4dc9..6bbac65772 100644 --- a/internal/query/org_member_test.go +++ b/internal/query/org_member_test.go @@ -21,24 +21,24 @@ var ( ", members.user_id" + ", members.roles" + ", projections.login_names3.login_name" + - ", projections.users10_humans.email" + - ", projections.users10_humans.first_name" + - ", projections.users10_humans.last_name" + - ", projections.users10_humans.display_name" + - ", projections.users10_machines.name" + - ", projections.users10_humans.avatar_key" + - ", projections.users10.type" + + ", projections.users11_humans.email" + + ", projections.users11_humans.first_name" + + ", projections.users11_humans.last_name" + + ", projections.users11_humans.display_name" + + ", projections.users11_machines.name" + + ", projections.users11_humans.avatar_key" + + ", projections.users11.type" + ", COUNT(*) OVER () " + "FROM projections.org_members4 AS members " + - "LEFT JOIN projections.users10_humans " + - "ON members.user_id = projections.users10_humans.user_id " + - "AND members.instance_id = projections.users10_humans.instance_id " + - "LEFT JOIN projections.users10_machines " + - "ON members.user_id = projections.users10_machines.user_id " + - "AND members.instance_id = projections.users10_machines.instance_id " + - "LEFT JOIN projections.users10 " + - "ON members.user_id = projections.users10.id " + - "AND members.instance_id = projections.users10.instance_id " + + "LEFT JOIN projections.users11_humans " + + "ON members.user_id = projections.users11_humans.user_id " + + "AND members.instance_id = projections.users11_humans.instance_id " + + "LEFT JOIN projections.users11_machines " + + "ON members.user_id = projections.users11_machines.user_id " + + "AND members.instance_id = projections.users11_machines.instance_id " + + "LEFT JOIN projections.users11 " + + "ON members.user_id = projections.users11.id " + + "AND members.instance_id = projections.users11.instance_id " + "LEFT JOIN projections.login_names3 " + "ON members.user_id = projections.login_names3.user_id " + "AND members.instance_id = projections.login_names3.instance_id " + diff --git a/internal/query/project_grant_member_test.go b/internal/query/project_grant_member_test.go index 91cd210679..70cdfb7c6a 100644 --- a/internal/query/project_grant_member_test.go +++ b/internal/query/project_grant_member_test.go @@ -21,24 +21,24 @@ var ( ", members.user_id" + ", members.roles" + ", projections.login_names3.login_name" + - ", projections.users10_humans.email" + - ", projections.users10_humans.first_name" + - ", projections.users10_humans.last_name" + - ", projections.users10_humans.display_name" + - ", projections.users10_machines.name" + - ", projections.users10_humans.avatar_key" + - ", projections.users10.type" + + ", projections.users11_humans.email" + + ", projections.users11_humans.first_name" + + ", projections.users11_humans.last_name" + + ", projections.users11_humans.display_name" + + ", projections.users11_machines.name" + + ", projections.users11_humans.avatar_key" + + ", projections.users11.type" + ", COUNT(*) OVER () " + "FROM projections.project_grant_members4 AS members " + - "LEFT JOIN projections.users10_humans " + - "ON members.user_id = projections.users10_humans.user_id " + - "AND members.instance_id = projections.users10_humans.instance_id " + - "LEFT JOIN projections.users10_machines " + - "ON members.user_id = projections.users10_machines.user_id " + - "AND members.instance_id = projections.users10_machines.instance_id " + - "LEFT JOIN projections.users10 " + - "ON members.user_id = projections.users10.id " + - "AND members.instance_id = projections.users10.instance_id " + + "LEFT JOIN projections.users11_humans " + + "ON members.user_id = projections.users11_humans.user_id " + + "AND members.instance_id = projections.users11_humans.instance_id " + + "LEFT JOIN projections.users11_machines " + + "ON members.user_id = projections.users11_machines.user_id " + + "AND members.instance_id = projections.users11_machines.instance_id " + + "LEFT JOIN projections.users11 " + + "ON members.user_id = projections.users11.id " + + "AND members.instance_id = projections.users11.instance_id " + "LEFT JOIN projections.login_names3 " + "ON members.user_id = projections.login_names3.user_id " + "AND members.instance_id = projections.login_names3.instance_id " + diff --git a/internal/query/project_member_test.go b/internal/query/project_member_test.go index defec46d49..4e7fe0b6e0 100644 --- a/internal/query/project_member_test.go +++ b/internal/query/project_member_test.go @@ -21,24 +21,24 @@ var ( ", members.user_id" + ", members.roles" + ", projections.login_names3.login_name" + - ", projections.users10_humans.email" + - ", projections.users10_humans.first_name" + - ", projections.users10_humans.last_name" + - ", projections.users10_humans.display_name" + - ", projections.users10_machines.name" + - ", projections.users10_humans.avatar_key" + - ", projections.users10.type" + + ", projections.users11_humans.email" + + ", projections.users11_humans.first_name" + + ", projections.users11_humans.last_name" + + ", projections.users11_humans.display_name" + + ", projections.users11_machines.name" + + ", projections.users11_humans.avatar_key" + + ", projections.users11.type" + ", COUNT(*) OVER () " + "FROM projections.project_members4 AS members " + - "LEFT JOIN projections.users10_humans " + - "ON members.user_id = projections.users10_humans.user_id " + - "AND members.instance_id = projections.users10_humans.instance_id " + - "LEFT JOIN projections.users10_machines " + - "ON members.user_id = projections.users10_machines.user_id " + - "AND members.instance_id = projections.users10_machines.instance_id " + - "LEFT JOIN projections.users10 " + - "ON members.user_id = projections.users10.id " + - "AND members.instance_id = projections.users10.instance_id " + + "LEFT JOIN projections.users11_humans " + + "ON members.user_id = projections.users11_humans.user_id " + + "AND members.instance_id = projections.users11_humans.instance_id " + + "LEFT JOIN projections.users11_machines " + + "ON members.user_id = projections.users11_machines.user_id " + + "AND members.instance_id = projections.users11_machines.instance_id " + + "LEFT JOIN projections.users11 " + + "ON members.user_id = projections.users11.id " + + "AND members.instance_id = projections.users11.instance_id " + "LEFT JOIN projections.login_names3 " + "ON members.user_id = projections.login_names3.user_id " + "AND members.instance_id = projections.login_names3.instance_id " + diff --git a/internal/query/projection/user.go b/internal/query/projection/user.go index ab1c158bb9..0a75abc368 100644 --- a/internal/query/projection/user.go +++ b/internal/query/projection/user.go @@ -15,7 +15,7 @@ import ( ) const ( - UserTable = "projections.users10" + UserTable = "projections.users11" UserHumanTable = UserTable + "_" + UserHumanSuffix UserMachineTable = UserTable + "_" + UserMachineSuffix UserNotifyTable = UserTable + "_" + UserNotifySuffix @@ -30,9 +30,10 @@ const ( UserUsernameCol = "username" UserTypeCol = "type" - UserHumanSuffix = "humans" - HumanUserIDCol = "user_id" - HumanUserInstanceIDCol = "instance_id" + UserHumanSuffix = "humans" + HumanUserIDCol = "user_id" + HumanUserInstanceIDCol = "instance_id" + HumanPasswordChangeRequired = "password_change_required" // profile HumanFirstNameCol = "first_name" @@ -113,6 +114,7 @@ func (*userProjection) Init() *old_handler.Check { handler.NewColumn(HumanIsEmailVerifiedCol, handler.ColumnTypeBool, handler.Default(false)), handler.NewColumn(HumanPhoneCol, handler.ColumnTypeText, handler.Nullable()), handler.NewColumn(HumanIsPhoneVerifiedCol, handler.ColumnTypeBool, handler.Nullable()), + handler.NewColumn(HumanPasswordChangeRequired, handler.ColumnTypeBool), }, handler.NewPrimaryKey(HumanUserInstanceIDCol, HumanUserIDCol), UserHumanSuffix, @@ -342,6 +344,7 @@ func (p *userProjection) reduceHumanAdded(event eventstore.Event) (*handler.Stat handler.NewCol(HumanGenderCol, &sql.NullInt16{Int16: int16(e.Gender), Valid: e.Gender.Specified()}), handler.NewCol(HumanEmailCol, e.EmailAddress), handler.NewCol(HumanPhoneCol, &sql.NullString{String: string(e.PhoneNumber), Valid: e.PhoneNumber != ""}), + handler.NewCol(HumanPasswordChangeRequired, e.ChangeRequired), }, handler.WithTableSuffix(UserHumanSuffix), ), @@ -390,6 +393,7 @@ func (p *userProjection) reduceHumanRegistered(event eventstore.Event) (*handler handler.NewCol(HumanGenderCol, &sql.NullInt16{Int16: int16(e.Gender), Valid: e.Gender.Specified()}), handler.NewCol(HumanEmailCol, e.EmailAddress), handler.NewCol(HumanPhoneCol, &sql.NullString{String: string(e.PhoneNumber), Valid: e.PhoneNumber != ""}), + handler.NewCol(HumanPasswordChangeRequired, e.ChangeRequired), }, handler.WithTableSuffix(UserHumanSuffix), ), @@ -904,17 +908,28 @@ func (p *userProjection) reduceHumanPasswordChanged(event eventstore.Event) (*ha if !ok { return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-jqXUY", "reduce.wrong.event.type %s", user.HumanPasswordChangedType) } - - return handler.NewUpdateStatement( + return handler.NewMultiStatement( e, - []handler.Column{ - handler.NewCol(NotifyPasswordSetCol, true), - }, - []handler.Condition{ - handler.NewCond(NotifyUserIDCol, e.Aggregate().ID), - handler.NewCond(NotifyInstanceIDCol, e.Aggregate().InstanceID), - }, - handler.WithTableSuffix(UserNotifySuffix), + handler.AddUpdateStatement( + []handler.Column{ + handler.NewCol(HumanPasswordChangeRequired, e.ChangeRequired), + }, + []handler.Condition{ + handler.NewCond(HumanUserIDCol, e.Aggregate().ID), + handler.NewCond(HumanUserInstanceIDCol, e.Aggregate().InstanceID), + }, + handler.WithTableSuffix(UserHumanSuffix), + ), + handler.AddUpdateStatement( + []handler.Column{ + handler.NewCol(NotifyPasswordSetCol, true), + }, + []handler.Condition{ + handler.NewCond(NotifyUserIDCol, e.Aggregate().ID), + handler.NewCond(NotifyInstanceIDCol, e.Aggregate().InstanceID), + }, + handler.WithTableSuffix(UserNotifySuffix), + ), ), nil } diff --git a/internal/query/projection/user_test.go b/internal/query/projection/user_test.go index 9aaec46cf0..2ef6caff93 100644 --- a/internal/query/projection/user_test.go +++ b/internal/query/projection/user_test.go @@ -40,7 +40,8 @@ func TestUserProjection_reduces(t *testing.T) { "preferredLanguage": "ch-DE", "gender": 1, "email": "email@zitadel.com", - "phone": "+41 00 000 00 00" + "phone": "+41 00 000 00 00", + "changeRequired": true }`), ), user.HumanAddedEventMapper), }, @@ -51,7 +52,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users10 (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.users11 (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{}, @@ -65,7 +66,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users10_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.users11_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone, password_change_required) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -77,10 +78,11 @@ func TestUserProjection_reduces(t *testing.T) { &sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true}, domain.EmailAddress("email@zitadel.com"), &sql.NullString{String: "+41 00 000 00 00", Valid: true}, + true, }, }, { - expectedStmt: "INSERT INTO projections.users10_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users11_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -120,7 +122,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users10 (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.users11 (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{}, @@ -134,7 +136,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users10_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.users11_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone, password_change_required) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -146,10 +148,11 @@ func TestUserProjection_reduces(t *testing.T) { &sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true}, domain.EmailAddress("email@zitadel.com"), &sql.NullString{String: "+41 00 000 00 00", Valid: true}, + false, }, }, { - expectedStmt: "INSERT INTO projections.users10_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users11_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -184,7 +187,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users10 (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.users11 (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{}, @@ -198,7 +201,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users10_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.users11_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone, password_change_required) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -210,10 +213,11 @@ func TestUserProjection_reduces(t *testing.T) { &sql.NullInt16{}, domain.EmailAddress("email@zitadel.com"), &sql.NullString{}, + false, }, }, { - expectedStmt: "INSERT INTO projections.users10_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users11_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -242,7 +246,8 @@ func TestUserProjection_reduces(t *testing.T) { "preferredLanguage": "ch-DE", "gender": 1, "email": "email@zitadel.com", - "phone": "+41 00 000 00 00" + "phone": "+41 00 000 00 00", + "changeRequired": true }`), ), user.HumanRegisteredEventMapper), }, @@ -253,7 +258,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users10 (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.users11 (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{}, @@ -267,7 +272,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users10_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.users11_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone, password_change_required) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -279,10 +284,11 @@ func TestUserProjection_reduces(t *testing.T) { &sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true}, domain.EmailAddress("email@zitadel.com"), &sql.NullString{String: "+41 00 000 00 00", Valid: true}, + true, }, }, { - expectedStmt: "INSERT INTO projections.users10_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users11_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -322,7 +328,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users10 (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.users11 (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{}, @@ -336,7 +342,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users10_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.users11_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone, password_change_required) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -348,10 +354,11 @@ func TestUserProjection_reduces(t *testing.T) { &sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true}, domain.EmailAddress("email@zitadel.com"), &sql.NullString{String: "+41 00 000 00 00", Valid: true}, + false, }, }, { - expectedStmt: "INSERT INTO projections.users10_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users11_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -386,7 +393,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users10 (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.users11 (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{}, @@ -400,7 +407,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users10_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.users11_humans (user_id, instance_id, first_name, last_name, nick_name, display_name, preferred_language, gender, email, phone, password_change_required) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -412,10 +419,11 @@ func TestUserProjection_reduces(t *testing.T) { &sql.NullInt16{}, domain.EmailAddress("email@zitadel.com"), &sql.NullString{}, + false, }, }, { - expectedStmt: "INSERT INTO projections.users10_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users11_notifications (user_id, instance_id, last_email, last_phone, password_set) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -445,7 +453,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ domain.UserStateInitial, "agg-id", @@ -473,7 +481,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ domain.UserStateInitial, "agg-id", @@ -501,7 +509,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ domain.UserStateActive, "agg-id", @@ -529,7 +537,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11 SET state = $1 WHERE (id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ domain.UserStateActive, "agg-id", @@ -557,7 +565,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users11 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, domain.UserStateLocked, @@ -587,7 +595,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users11 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, domain.UserStateActive, @@ -617,7 +625,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users11 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, domain.UserStateInactive, @@ -647,7 +655,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users11 SET (change_date, state, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, domain.UserStateActive, @@ -677,7 +685,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.users10 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.users11 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -706,7 +714,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users11 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, "username", @@ -738,7 +746,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.users11 SET (change_date, username, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)", expectedArgs: []interface{}{ anyArg{}, "id@temporary.domain", @@ -775,7 +783,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -784,7 +792,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_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.users11_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", @@ -824,7 +832,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -833,7 +841,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_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.users11_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", @@ -868,7 +876,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -877,7 +885,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ domain.PhoneNumber("+41 00 000 00 00"), false, @@ -886,7 +894,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_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", @@ -916,7 +924,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -925,7 +933,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ domain.PhoneNumber("+41 00 000 00 00"), false, @@ -934,7 +942,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_notifications SET last_phone = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_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", @@ -962,7 +970,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -971,7 +979,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ nil, nil, @@ -980,7 +988,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ nil, nil, @@ -1009,7 +1017,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1018,7 +1026,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11_humans SET (phone, is_phone_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ nil, nil, @@ -1027,7 +1035,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11_notifications SET (last_phone, verified_phone) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ nil, nil, @@ -1056,7 +1064,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1065,7 +1073,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ true, "agg-id", @@ -1073,7 +1081,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "UPDATE projections.users11_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1100,7 +1108,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1109,7 +1117,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_humans SET is_phone_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ true, "agg-id", @@ -1117,7 +1125,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "UPDATE projections.users11_notifications SET verified_phone = last_phone WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1146,7 +1154,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1155,7 +1163,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ domain.EmailAddress("email@zitadel.com"), false, @@ -1164,7 +1172,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_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", @@ -1194,7 +1202,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1203,7 +1211,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11_humans SET (email, is_email_verified) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ domain.EmailAddress("email@zitadel.com"), false, @@ -1212,7 +1220,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_notifications SET last_email = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_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", @@ -1240,7 +1248,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1249,7 +1257,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ true, "agg-id", @@ -1257,7 +1265,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "UPDATE projections.users11_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1284,7 +1292,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1293,7 +1301,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_humans SET is_email_verified = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ true, "agg-id", @@ -1301,7 +1309,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)", + expectedStmt: "UPDATE projections.users11_notifications SET verified_email = last_email WHERE (user_id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1330,7 +1338,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1339,7 +1347,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "users/agg-id/avatar", "agg-id", @@ -1367,7 +1375,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1376,7 +1384,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_humans SET avatar_key = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ nil, "agg-id", @@ -1387,6 +1395,82 @@ func TestUserProjection_reduces(t *testing.T) { }, }, }, + { + name: "reduceHumanPasswordChanged", + args: args{ + event: getEvent( + testEvent( + user.HumanPasswordChangedType, + user.AggregateType, + []byte(`{ + "changeRequired": true + }`), + ), user.HumanPasswordChangedEventMapper), + }, + reduce: (&userProjection{}).reduceHumanPasswordChanged, + want: wantReduce{ + aggregateType: user.AggregateType, + sequence: 15, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.users11_humans SET password_change_required = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedArgs: []interface{}{ + true, + "agg-id", + "instance-id", + }, + }, + { + expectedStmt: "UPDATE projections.users11_notifications SET password_set = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedArgs: []interface{}{ + true, + "agg-id", + "instance-id", + }, + }, + }, + }, + }, + }, + { + name: "reduceHumanPasswordChanged, false", + args: args{ + event: getEvent( + testEvent( + user.HumanPasswordChangedType, + user.AggregateType, + []byte(`{ + "changeRequired": false + }`), + ), user.HumanPasswordChangedEventMapper), + }, + reduce: (&userProjection{}).reduceHumanPasswordChanged, + want: wantReduce{ + aggregateType: user.AggregateType, + sequence: 15, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.users11_humans SET password_change_required = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedArgs: []interface{}{ + false, + "agg-id", + "instance-id", + }, + }, + { + expectedStmt: "UPDATE projections.users11_notifications SET password_set = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedArgs: []interface{}{ + true, + "agg-id", + "instance-id", + }, + }, + }, + }, + }, + }, { name: "reduceMachineAddedEvent no description", args: args{ @@ -1407,7 +1491,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users10 (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.users11 (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{}, @@ -1421,7 +1505,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users10_machines (user_id, instance_id, name, description, access_token_type) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users11_machines (user_id, instance_id, name, description, access_token_type) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1455,7 +1539,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.users10 (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.users11 (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{}, @@ -1469,7 +1553,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "INSERT INTO projections.users10_machines (user_id, instance_id, name, description, access_token_type) VALUES ($1, $2, $3, $4, $5)", + expectedStmt: "INSERT INTO projections.users11_machines (user_id, instance_id, name, description, access_token_type) VALUES ($1, $2, $3, $4, $5)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -1502,7 +1586,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1511,7 +1595,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_machines SET (name, description) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11_machines SET (name, description) = ($1, $2) WHERE (user_id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ "machine-name", "description", @@ -1542,7 +1626,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1551,7 +1635,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_machines SET name = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_machines SET name = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "machine-name", "agg-id", @@ -1581,7 +1665,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1590,7 +1674,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_machines SET description = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_machines SET description = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ "description", "agg-id", @@ -1639,7 +1723,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1648,7 +1732,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_machines SET secret = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_machines SET secret = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ &crypto.CryptoValue{ CryptoType: crypto.TypeHash, @@ -1680,7 +1764,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.users10 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", + expectedStmt: "UPDATE projections.users11 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -1689,7 +1773,7 @@ func TestUserProjection_reduces(t *testing.T) { }, }, { - expectedStmt: "UPDATE projections.users10_machines SET secret = $1 WHERE (user_id = $2) AND (instance_id = $3)", + expectedStmt: "UPDATE projections.users11_machines SET secret = $1 WHERE (user_id = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ nil, "agg-id", @@ -1717,7 +1801,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.users10 WHERE (instance_id = $1) AND (resource_owner = $2)", + expectedStmt: "DELETE FROM projections.users11 WHERE (instance_id = $1) AND (resource_owner = $2)", expectedArgs: []interface{}{ "instance-id", "agg-id", @@ -1744,7 +1828,7 @@ func TestUserProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.users10 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.users11 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/sessions_test.go b/internal/query/sessions_test.go index 711e952323..6f6a330e03 100644 --- a/internal/query/sessions_test.go +++ b/internal/query/sessions_test.go @@ -31,7 +31,7 @@ var ( ` projections.sessions8.user_resource_owner,` + ` projections.sessions8.user_checked_at,` + ` projections.login_names3.login_name,` + - ` projections.users10_humans.display_name,` + + ` projections.users11_humans.display_name,` + ` projections.sessions8.password_checked_at,` + ` projections.sessions8.intent_checked_at,` + ` projections.sessions8.webauthn_checked_at,` + @@ -48,8 +48,8 @@ var ( ` projections.sessions8.expiration` + ` FROM projections.sessions8` + ` LEFT JOIN projections.login_names3 ON projections.sessions8.user_id = projections.login_names3.user_id AND projections.sessions8.instance_id = projections.login_names3.instance_id` + - ` LEFT JOIN projections.users10_humans ON projections.sessions8.user_id = projections.users10_humans.user_id AND projections.sessions8.instance_id = projections.users10_humans.instance_id` + - ` LEFT JOIN projections.users10 ON projections.sessions8.user_id = projections.users10.id AND projections.sessions8.instance_id = projections.users10.instance_id` + + ` LEFT JOIN projections.users11_humans ON projections.sessions8.user_id = projections.users11_humans.user_id AND projections.sessions8.instance_id = projections.users11_humans.instance_id` + + ` LEFT JOIN projections.users11 ON projections.sessions8.user_id = projections.users11.id AND projections.sessions8.instance_id = projections.users11.instance_id` + ` AS OF SYSTEM TIME '-1 ms'`) expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions8.id,` + ` projections.sessions8.creation_date,` + @@ -62,7 +62,7 @@ var ( ` projections.sessions8.user_resource_owner,` + ` projections.sessions8.user_checked_at,` + ` projections.login_names3.login_name,` + - ` projections.users10_humans.display_name,` + + ` projections.users11_humans.display_name,` + ` projections.sessions8.password_checked_at,` + ` projections.sessions8.intent_checked_at,` + ` projections.sessions8.webauthn_checked_at,` + @@ -75,8 +75,8 @@ var ( ` COUNT(*) OVER ()` + ` FROM projections.sessions8` + ` LEFT JOIN projections.login_names3 ON projections.sessions8.user_id = projections.login_names3.user_id AND projections.sessions8.instance_id = projections.login_names3.instance_id` + - ` LEFT JOIN projections.users10_humans ON projections.sessions8.user_id = projections.users10_humans.user_id AND projections.sessions8.instance_id = projections.users10_humans.instance_id` + - ` LEFT JOIN projections.users10 ON projections.sessions8.user_id = projections.users10.id AND projections.sessions8.instance_id = projections.users10.instance_id` + + ` LEFT JOIN projections.users11_humans ON projections.sessions8.user_id = projections.users11_humans.user_id AND projections.sessions8.instance_id = projections.users11_humans.instance_id` + + ` LEFT JOIN projections.users11 ON projections.sessions8.user_id = projections.users11.id AND projections.sessions8.instance_id = projections.users11.instance_id` + ` AS OF SYSTEM TIME '-1 ms'`) sessionCols = []string{ diff --git a/internal/query/user.go b/internal/query/user.go index 9367dca35b..a6bfaedf0f 100644 --- a/internal/query/user.go +++ b/internal/query/user.go @@ -42,17 +42,18 @@ type User struct { } type Human struct { - FirstName string `json:"first_name,omitempty"` - LastName string `json:"last_name,omitempty"` - NickName string `json:"nick_name,omitempty"` - DisplayName string `json:"display_name,omitempty"` - AvatarKey string `json:"avatar_key,omitempty"` - PreferredLanguage language.Tag `json:"preferred_language,omitempty"` - Gender domain.Gender `json:"gender,omitempty"` - Email domain.EmailAddress `json:"email,omitempty"` - IsEmailVerified bool `json:"is_email_verified,omitempty"` - Phone domain.PhoneNumber `json:"phone,omitempty"` - IsPhoneVerified bool `json:"is_phone_verified,omitempty"` + FirstName string `json:"first_name,omitempty"` + LastName string `json:"last_name,omitempty"` + NickName string `json:"nick_name,omitempty"` + DisplayName string `json:"display_name,omitempty"` + AvatarKey string `json:"avatar_key,omitempty"` + PreferredLanguage language.Tag `json:"preferred_language,omitempty"` + Gender domain.Gender `json:"gender,omitempty"` + Email domain.EmailAddress `json:"email,omitempty"` + IsEmailVerified bool `json:"is_email_verified,omitempty"` + Phone domain.PhoneNumber `json:"phone,omitempty"` + IsPhoneVerified bool `json:"is_phone_verified,omitempty"` + PasswordChangeRequired bool `json:"password_change_required,omitempty"` } type Profile struct { @@ -275,6 +276,11 @@ var ( name: projection.HumanIsPhoneVerifiedCol, table: humanTable, } + + HumanPasswordChangeRequiredCol = Column{ + name: projection.HumanPasswordChangeRequired, + table: humanTable, + } ) var ( @@ -816,6 +822,7 @@ func scanUser(row *sql.Row) (*User, error) { isEmailVerified := sql.NullBool{} phone := sql.NullString{} isPhoneVerified := sql.NullBool{} + passwordChangeRequired := sql.NullBool{} machineID := sql.NullString{} name := sql.NullString{} @@ -846,6 +853,7 @@ func scanUser(row *sql.Row) (*User, error) { &isEmailVerified, &phone, &isPhoneVerified, + &passwordChangeRequired, &machineID, &name, &description, @@ -865,17 +873,18 @@ func scanUser(row *sql.Row) (*User, error) { if humanID.Valid { u.Human = &Human{ - FirstName: firstName.String, - LastName: lastName.String, - NickName: nickName.String, - DisplayName: displayName.String, - AvatarKey: avatarKey.String, - PreferredLanguage: language.Make(preferredLanguage.String), - Gender: domain.Gender(gender.Int32), - Email: domain.EmailAddress(email.String), - IsEmailVerified: isEmailVerified.Bool, - Phone: domain.PhoneNumber(phone.String), - IsPhoneVerified: isPhoneVerified.Bool, + FirstName: firstName.String, + LastName: lastName.String, + NickName: nickName.String, + DisplayName: displayName.String, + AvatarKey: avatarKey.String, + PreferredLanguage: language.Make(preferredLanguage.String), + Gender: domain.Gender(gender.Int32), + Email: domain.EmailAddress(email.String), + IsEmailVerified: isEmailVerified.Bool, + Phone: domain.PhoneNumber(phone.String), + IsPhoneVerified: isPhoneVerified.Bool, + PasswordChangeRequired: passwordChangeRequired.Bool, } } else if machineID.Valid { u.Machine = &Machine{ @@ -920,6 +929,7 @@ func prepareUserQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder HumanIsEmailVerifiedCol.identifier(), HumanPhoneCol.identifier(), HumanIsPhoneVerifiedCol.identifier(), + HumanPasswordChangeRequiredCol.identifier(), MachineUserIDCol.identifier(), MachineNameCol.identifier(), MachineDescriptionCol.identifier(), @@ -1306,6 +1316,7 @@ func prepareUsersQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilde HumanIsEmailVerifiedCol.identifier(), HumanPhoneCol.identifier(), HumanIsPhoneVerifiedCol.identifier(), + HumanPasswordChangeRequiredCol.identifier(), MachineUserIDCol.identifier(), MachineNameCol.identifier(), MachineDescriptionCol.identifier(), @@ -1344,6 +1355,7 @@ func prepareUsersQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilde isEmailVerified := sql.NullBool{} phone := sql.NullString{} isPhoneVerified := sql.NullBool{} + passwordChangeRequired := sql.NullBool{} machineID := sql.NullString{} name := sql.NullString{} @@ -1374,6 +1386,7 @@ func prepareUsersQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilde &isEmailVerified, &phone, &isPhoneVerified, + &passwordChangeRequired, &machineID, &name, &description, @@ -1392,17 +1405,18 @@ func prepareUsersQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilde if humanID.Valid { u.Human = &Human{ - FirstName: firstName.String, - LastName: lastName.String, - NickName: nickName.String, - DisplayName: displayName.String, - AvatarKey: avatarKey.String, - PreferredLanguage: language.Make(preferredLanguage.String), - Gender: domain.Gender(gender.Int32), - Email: domain.EmailAddress(email.String), - IsEmailVerified: isEmailVerified.Bool, - Phone: domain.PhoneNumber(phone.String), - IsPhoneVerified: isPhoneVerified.Bool, + FirstName: firstName.String, + LastName: lastName.String, + NickName: nickName.String, + DisplayName: displayName.String, + AvatarKey: avatarKey.String, + PreferredLanguage: language.Make(preferredLanguage.String), + Gender: domain.Gender(gender.Int32), + Email: domain.EmailAddress(email.String), + IsEmailVerified: isEmailVerified.Bool, + Phone: domain.PhoneNumber(phone.String), + IsPhoneVerified: isPhoneVerified.Bool, + PasswordChangeRequired: passwordChangeRequired.Bool, } } else if machineID.Valid { u.Machine = &Machine{ diff --git a/internal/query/user_auth_method_test.go b/internal/query/user_auth_method_test.go index c78bf85699..66433c208f 100644 --- a/internal/query/user_auth_method_test.go +++ b/internal/query/user_auth_method_test.go @@ -39,38 +39,38 @@ var ( "method_type", "count", } - prepareActiveAuthMethodTypesStmt = `SELECT projections.users10_notifications.password_set,` + + prepareActiveAuthMethodTypesStmt = `SELECT projections.users11_notifications.password_set,` + ` auth_method_types.method_type,` + ` user_idps_count.count` + - ` FROM projections.users10` + - ` LEFT JOIN projections.users10_notifications ON projections.users10.id = projections.users10_notifications.user_id AND projections.users10.instance_id = projections.users10_notifications.instance_id` + + ` FROM projections.users11` + + ` LEFT JOIN projections.users11_notifications ON projections.users11.id = projections.users11_notifications.user_id AND projections.users11.instance_id = projections.users11_notifications.instance_id` + ` LEFT JOIN (SELECT DISTINCT(auth_method_types.method_type), auth_method_types.user_id, auth_method_types.instance_id FROM projections.user_auth_methods4 AS auth_method_types` + ` WHERE auth_method_types.state = $1) AS auth_method_types` + - ` ON auth_method_types.user_id = projections.users10.id AND auth_method_types.instance_id = projections.users10.instance_id` + + ` ON auth_method_types.user_id = projections.users11.id AND auth_method_types.instance_id = projections.users11.instance_id` + ` LEFT JOIN (SELECT user_idps_count.user_id, user_idps_count.instance_id, COUNT(user_idps_count.user_id) AS count FROM projections.idp_user_links3 AS user_idps_count` + ` GROUP BY user_idps_count.user_id, user_idps_count.instance_id) AS user_idps_count` + - ` ON user_idps_count.user_id = projections.users10.id AND user_idps_count.instance_id = projections.users10.instance_id` + + ` ON user_idps_count.user_id = projections.users11.id AND user_idps_count.instance_id = projections.users11.instance_id` + ` AS OF SYSTEM TIME '-1 ms` prepareActiveAuthMethodTypesCols = []string{ "password_set", "method_type", "idps_count", } - prepareAuthMethodTypesRequiredStmt = `SELECT projections.users10_notifications.password_set,` + + prepareAuthMethodTypesRequiredStmt = `SELECT projections.users11_notifications.password_set,` + ` auth_method_types.method_type,` + ` user_idps_count.count,` + ` auth_methods_force_mfa.force_mfa,` + ` auth_methods_force_mfa.force_mfa_local_only` + - ` FROM projections.users10` + - ` LEFT JOIN projections.users10_notifications ON projections.users10.id = projections.users10_notifications.user_id AND projections.users10.instance_id = projections.users10_notifications.instance_id` + + ` FROM projections.users11` + + ` LEFT JOIN projections.users11_notifications ON projections.users11.id = projections.users11_notifications.user_id AND projections.users11.instance_id = projections.users11_notifications.instance_id` + ` LEFT JOIN (SELECT DISTINCT(auth_method_types.method_type), auth_method_types.user_id, auth_method_types.instance_id FROM projections.user_auth_methods4 AS auth_method_types` + ` WHERE auth_method_types.state = $1) AS auth_method_types` + - ` ON auth_method_types.user_id = projections.users10.id AND auth_method_types.instance_id = projections.users10.instance_id` + + ` ON auth_method_types.user_id = projections.users11.id AND auth_method_types.instance_id = projections.users11.instance_id` + ` LEFT JOIN (SELECT user_idps_count.user_id, user_idps_count.instance_id, COUNT(user_idps_count.user_id) AS count FROM projections.idp_user_links3 AS user_idps_count` + ` GROUP BY user_idps_count.user_id, user_idps_count.instance_id) AS user_idps_count` + - ` ON user_idps_count.user_id = projections.users10.id AND user_idps_count.instance_id = projections.users10.instance_id` + + ` ON user_idps_count.user_id = projections.users11.id AND user_idps_count.instance_id = projections.users11.instance_id` + ` LEFT JOIN (SELECT auth_methods_force_mfa.force_mfa, auth_methods_force_mfa.force_mfa_local_only, auth_methods_force_mfa.instance_id, auth_methods_force_mfa.aggregate_id FROM projections.login_policies5 AS auth_methods_force_mfa ORDER BY auth_methods_force_mfa.is_default) AS auth_methods_force_mfa` + - ` ON (auth_methods_force_mfa.aggregate_id = projections.users10.instance_id OR auth_methods_force_mfa.aggregate_id = projections.users10.resource_owner) AND auth_methods_force_mfa.instance_id = projections.users10.instance_id` + + ` ON (auth_methods_force_mfa.aggregate_id = projections.users11.instance_id OR auth_methods_force_mfa.aggregate_id = projections.users11.resource_owner) AND auth_methods_force_mfa.instance_id = projections.users11.instance_id` + ` AS OF SYSTEM TIME '-1 ms ` prepareAuthMethodTypesRequiredCols = []string{ diff --git a/internal/query/user_by_id.sql b/internal/query/user_by_id.sql index 8f1113de06..de96daab80 100644 --- a/internal/query/user_by_id.sql +++ b/internal/query/user_by_id.sql @@ -58,20 +58,21 @@ SELECT , h.is_email_verified , h.phone , h.is_phone_verified + , h.password_change_required , m.user_id , m.name , m.description , m.secret , m.access_token_type , count(*) OVER () -FROM projections.users10 u +FROM projections.users11 u LEFT JOIN - projections.users10_humans h + projections.users11_humans h ON u.id = h.user_id AND u.instance_id = h.instance_id LEFT JOIN - projections.users10_machines m + projections.users11_machines m ON u.id = m.user_id AND u.instance_id = m.instance_id diff --git a/internal/query/user_by_login_name.sql b/internal/query/user_by_login_name.sql index cf25638fa6..08f46aa105 100644 --- a/internal/query/user_by_login_name.sql +++ b/internal/query/user_by_login_name.sql @@ -94,6 +94,7 @@ SELECT , h.is_email_verified , h.phone , h.is_phone_verified + , h.password_change_required , m.user_id , m.name , m.description @@ -102,17 +103,17 @@ SELECT , count(*) OVER () FROM found_users fu JOIN - projections.users10 u + projections.users11 u ON fu.id = u.id AND fu.instance_id = u.instance_id LEFT JOIN - projections.users10_humans h + projections.users11_humans h ON fu.id = h.user_id AND fu.instance_id = h.instance_id LEFT JOIN - projections.users10_machines m + projections.users11_machines m ON fu.id = m.user_id AND fu.instance_id = m.instance_id diff --git a/internal/query/user_grant_test.go b/internal/query/user_grant_test.go index bf600b4333..c1753c34af 100644 --- a/internal/query/user_grant_test.go +++ b/internal/query/user_grant_test.go @@ -23,14 +23,14 @@ var ( ", projections.user_grants5.roles" + ", projections.user_grants5.state" + ", projections.user_grants5.user_id" + - ", projections.users10.username" + - ", projections.users10.type" + - ", projections.users10.resource_owner" + - ", projections.users10_humans.first_name" + - ", projections.users10_humans.last_name" + - ", projections.users10_humans.email" + - ", projections.users10_humans.display_name" + - ", projections.users10_humans.avatar_key" + + ", projections.users11.username" + + ", projections.users11.type" + + ", projections.users11.resource_owner" + + ", projections.users11_humans.first_name" + + ", projections.users11_humans.last_name" + + ", projections.users11_humans.email" + + ", projections.users11_humans.display_name" + + ", projections.users11_humans.avatar_key" + ", projections.login_names3.login_name" + ", projections.user_grants5.resource_owner" + ", projections.orgs1.name" + @@ -41,11 +41,11 @@ var ( ", granted_orgs.name" + ", granted_orgs.primary_domain" + " FROM projections.user_grants5" + - " LEFT JOIN projections.users10 ON projections.user_grants5.user_id = projections.users10.id AND projections.user_grants5.instance_id = projections.users10.instance_id" + - " LEFT JOIN projections.users10_humans ON projections.user_grants5.user_id = projections.users10_humans.user_id AND projections.user_grants5.instance_id = projections.users10_humans.instance_id" + + " LEFT JOIN projections.users11 ON projections.user_grants5.user_id = projections.users11.id AND projections.user_grants5.instance_id = projections.users11.instance_id" + + " LEFT JOIN projections.users11_humans ON projections.user_grants5.user_id = projections.users11_humans.user_id AND projections.user_grants5.instance_id = projections.users11_humans.instance_id" + " LEFT JOIN projections.orgs1 ON projections.user_grants5.resource_owner = projections.orgs1.id AND projections.user_grants5.instance_id = projections.orgs1.instance_id" + " LEFT JOIN projections.projects4 ON projections.user_grants5.project_id = projections.projects4.id AND projections.user_grants5.instance_id = projections.projects4.instance_id" + - " LEFT JOIN projections.orgs1 AS granted_orgs ON projections.users10.resource_owner = granted_orgs.id AND projections.users10.instance_id = granted_orgs.instance_id" + + " LEFT JOIN projections.orgs1 AS granted_orgs ON projections.users11.resource_owner = granted_orgs.id AND projections.users11.instance_id = granted_orgs.instance_id" + " LEFT JOIN projections.login_names3 ON projections.user_grants5.user_id = projections.login_names3.user_id AND projections.user_grants5.instance_id = projections.login_names3.instance_id" + ` AS OF SYSTEM TIME '-1 ms' ` + " WHERE projections.login_names3.is_primary = $1") @@ -85,14 +85,14 @@ var ( ", projections.user_grants5.roles" + ", projections.user_grants5.state" + ", projections.user_grants5.user_id" + - ", projections.users10.username" + - ", projections.users10.type" + - ", projections.users10.resource_owner" + - ", projections.users10_humans.first_name" + - ", projections.users10_humans.last_name" + - ", projections.users10_humans.email" + - ", projections.users10_humans.display_name" + - ", projections.users10_humans.avatar_key" + + ", projections.users11.username" + + ", projections.users11.type" + + ", projections.users11.resource_owner" + + ", projections.users11_humans.first_name" + + ", projections.users11_humans.last_name" + + ", projections.users11_humans.email" + + ", projections.users11_humans.display_name" + + ", projections.users11_humans.avatar_key" + ", projections.login_names3.login_name" + ", projections.user_grants5.resource_owner" + ", projections.orgs1.name" + @@ -104,11 +104,11 @@ var ( ", granted_orgs.primary_domain" + ", COUNT(*) OVER ()" + " FROM projections.user_grants5" + - " LEFT JOIN projections.users10 ON projections.user_grants5.user_id = projections.users10.id AND projections.user_grants5.instance_id = projections.users10.instance_id" + - " LEFT JOIN projections.users10_humans ON projections.user_grants5.user_id = projections.users10_humans.user_id AND projections.user_grants5.instance_id = projections.users10_humans.instance_id" + + " LEFT JOIN projections.users11 ON projections.user_grants5.user_id = projections.users11.id AND projections.user_grants5.instance_id = projections.users11.instance_id" + + " LEFT JOIN projections.users11_humans ON projections.user_grants5.user_id = projections.users11_humans.user_id AND projections.user_grants5.instance_id = projections.users11_humans.instance_id" + " LEFT JOIN projections.orgs1 ON projections.user_grants5.resource_owner = projections.orgs1.id AND projections.user_grants5.instance_id = projections.orgs1.instance_id" + " LEFT JOIN projections.projects4 ON projections.user_grants5.project_id = projections.projects4.id AND projections.user_grants5.instance_id = projections.projects4.instance_id" + - " LEFT JOIN projections.orgs1 AS granted_orgs ON projections.users10.resource_owner = granted_orgs.id AND projections.users10.instance_id = granted_orgs.instance_id" + + " LEFT JOIN projections.orgs1 AS granted_orgs ON projections.users11.resource_owner = granted_orgs.id AND projections.users11.instance_id = granted_orgs.instance_id" + " LEFT JOIN projections.login_names3 ON projections.user_grants5.user_id = projections.login_names3.user_id AND projections.user_grants5.instance_id = projections.login_names3.instance_id" + ` AS OF SYSTEM TIME '-1 ms' ` + " WHERE projections.login_names3.is_primary = $1") diff --git a/internal/query/user_notify_by_id.sql b/internal/query/user_notify_by_id.sql index 1087a1316b..84c4b93e0b 100644 --- a/internal/query/user_notify_by_id.sql +++ b/internal/query/user_notify_by_id.sql @@ -62,14 +62,14 @@ SELECT , n.verified_phone , n.password_set , count(*) OVER () -FROM projections.users10 u +FROM projections.users11 u LEFT JOIN - projections.users10_humans h + projections.users11_humans h ON u.id = h.user_id AND u.instance_id = h.instance_id LEFT JOIN - projections.users10_notifications n + projections.users11_notifications n ON u.id = n.user_id AND u.instance_id = n.instance_id diff --git a/internal/query/user_notify_by_login_name.sql b/internal/query/user_notify_by_login_name.sql index 1347e6cb3c..34e699ee8a 100644 --- a/internal/query/user_notify_by_login_name.sql +++ b/internal/query/user_notify_by_login_name.sql @@ -99,17 +99,17 @@ SELECT , count(*) OVER () FROM found_users fu JOIN - projections.users10 u + projections.users11 u ON fu.id = u.id AND fu.instance_id = u.instance_id LEFT JOIN - projections.users10_humans h + projections.users11_humans h ON fu.id = h.user_id AND fu.instance_id = h.instance_id LEFT JOIN - projections.users10_notifications n + projections.users11_notifications n ON fu.id = n.user_id AND fu.instance_id = n.instance_id diff --git a/internal/query/user_test.go b/internal/query/user_test.go index ff3c98faa4..0119fe1c13 100644 --- a/internal/query/user_test.go +++ b/internal/query/user_test.go @@ -148,43 +148,44 @@ var ( preferredLoginNameQuery = `SELECT preferred_login_name.user_id, preferred_login_name.login_name, preferred_login_name.instance_id` + ` FROM projections.login_names3 AS preferred_login_name` + ` WHERE preferred_login_name.is_primary = $1` - userQuery = `SELECT projections.users10.id,` + - ` projections.users10.creation_date,` + - ` projections.users10.change_date,` + - ` projections.users10.resource_owner,` + - ` projections.users10.sequence,` + - ` projections.users10.state,` + - ` projections.users10.type,` + - ` projections.users10.username,` + + userQuery = `SELECT projections.users11.id,` + + ` projections.users11.creation_date,` + + ` projections.users11.change_date,` + + ` projections.users11.resource_owner,` + + ` projections.users11.sequence,` + + ` projections.users11.state,` + + ` projections.users11.type,` + + ` projections.users11.username,` + ` login_names.loginnames,` + ` preferred_login_name.login_name,` + - ` projections.users10_humans.user_id,` + - ` projections.users10_humans.first_name,` + - ` projections.users10_humans.last_name,` + - ` projections.users10_humans.nick_name,` + - ` projections.users10_humans.display_name,` + - ` projections.users10_humans.preferred_language,` + - ` projections.users10_humans.gender,` + - ` projections.users10_humans.avatar_key,` + - ` projections.users10_humans.email,` + - ` projections.users10_humans.is_email_verified,` + - ` projections.users10_humans.phone,` + - ` projections.users10_humans.is_phone_verified,` + - ` projections.users10_machines.user_id,` + - ` projections.users10_machines.name,` + - ` projections.users10_machines.description,` + - ` projections.users10_machines.secret,` + - ` projections.users10_machines.access_token_type,` + + ` projections.users11_humans.user_id,` + + ` projections.users11_humans.first_name,` + + ` projections.users11_humans.last_name,` + + ` projections.users11_humans.nick_name,` + + ` projections.users11_humans.display_name,` + + ` projections.users11_humans.preferred_language,` + + ` projections.users11_humans.gender,` + + ` projections.users11_humans.avatar_key,` + + ` projections.users11_humans.email,` + + ` projections.users11_humans.is_email_verified,` + + ` projections.users11_humans.phone,` + + ` projections.users11_humans.is_phone_verified,` + + ` projections.users11_humans.password_change_required,` + + ` projections.users11_machines.user_id,` + + ` projections.users11_machines.name,` + + ` projections.users11_machines.description,` + + ` projections.users11_machines.secret,` + + ` projections.users11_machines.access_token_type,` + ` COUNT(*) OVER ()` + - ` FROM projections.users10` + - ` LEFT JOIN projections.users10_humans ON projections.users10.id = projections.users10_humans.user_id AND projections.users10.instance_id = projections.users10_humans.instance_id` + - ` LEFT JOIN projections.users10_machines ON projections.users10.id = projections.users10_machines.user_id AND projections.users10.instance_id = projections.users10_machines.instance_id` + + ` FROM projections.users11` + + ` LEFT JOIN projections.users11_humans ON projections.users11.id = projections.users11_humans.user_id AND projections.users11.instance_id = projections.users11_humans.instance_id` + + ` LEFT JOIN projections.users11_machines ON projections.users11.id = projections.users11_machines.user_id AND projections.users11.instance_id = projections.users11_machines.instance_id` + ` LEFT JOIN` + ` (` + loginNamesQuery + `) AS login_names` + - ` ON login_names.user_id = projections.users10.id AND login_names.instance_id = projections.users10.instance_id` + + ` ON login_names.user_id = projections.users11.id AND login_names.instance_id = projections.users11.instance_id` + ` LEFT JOIN` + ` (` + preferredLoginNameQuery + `) AS preferred_login_name` + - ` ON preferred_login_name.user_id = projections.users10.id AND preferred_login_name.instance_id = projections.users10.instance_id` + + ` ON preferred_login_name.user_id = projections.users11.id AND preferred_login_name.instance_id = projections.users11.instance_id` + ` AS OF SYSTEM TIME '-1 ms'` userCols = []string{ "id", @@ -210,6 +211,7 @@ var ( "is_email_verified", "phone", "is_phone_verified", + "password_change_required", // machine "user_id", "name", @@ -218,21 +220,21 @@ var ( "access_token_type", "count", } - profileQuery = `SELECT projections.users10.id,` + - ` projections.users10.creation_date,` + - ` projections.users10.change_date,` + - ` projections.users10.resource_owner,` + - ` projections.users10.sequence,` + - ` projections.users10_humans.user_id,` + - ` projections.users10_humans.first_name,` + - ` projections.users10_humans.last_name,` + - ` projections.users10_humans.nick_name,` + - ` projections.users10_humans.display_name,` + - ` projections.users10_humans.preferred_language,` + - ` projections.users10_humans.gender,` + - ` projections.users10_humans.avatar_key` + - ` FROM projections.users10` + - ` LEFT JOIN projections.users10_humans ON projections.users10.id = projections.users10_humans.user_id AND projections.users10.instance_id = projections.users10_humans.instance_id` + + profileQuery = `SELECT projections.users11.id,` + + ` projections.users11.creation_date,` + + ` projections.users11.change_date,` + + ` projections.users11.resource_owner,` + + ` projections.users11.sequence,` + + ` projections.users11_humans.user_id,` + + ` projections.users11_humans.first_name,` + + ` projections.users11_humans.last_name,` + + ` projections.users11_humans.nick_name,` + + ` projections.users11_humans.display_name,` + + ` projections.users11_humans.preferred_language,` + + ` projections.users11_humans.gender,` + + ` projections.users11_humans.avatar_key` + + ` FROM projections.users11` + + ` LEFT JOIN projections.users11_humans ON projections.users11.id = projections.users11_humans.user_id AND projections.users11.instance_id = projections.users11_humans.instance_id` + ` AS OF SYSTEM TIME '-1 ms'` profileCols = []string{ "id", @@ -249,16 +251,16 @@ var ( "gender", "avatar_key", } - emailQuery = `SELECT projections.users10.id,` + - ` projections.users10.creation_date,` + - ` projections.users10.change_date,` + - ` projections.users10.resource_owner,` + - ` projections.users10.sequence,` + - ` projections.users10_humans.user_id,` + - ` projections.users10_humans.email,` + - ` projections.users10_humans.is_email_verified` + - ` FROM projections.users10` + - ` LEFT JOIN projections.users10_humans ON projections.users10.id = projections.users10_humans.user_id AND projections.users10.instance_id = projections.users10_humans.instance_id` + + emailQuery = `SELECT projections.users11.id,` + + ` projections.users11.creation_date,` + + ` projections.users11.change_date,` + + ` projections.users11.resource_owner,` + + ` projections.users11.sequence,` + + ` projections.users11_humans.user_id,` + + ` projections.users11_humans.email,` + + ` projections.users11_humans.is_email_verified` + + ` FROM projections.users11` + + ` LEFT JOIN projections.users11_humans ON projections.users11.id = projections.users11_humans.user_id AND projections.users11.instance_id = projections.users11_humans.instance_id` + ` AS OF SYSTEM TIME '-1 ms'` emailCols = []string{ "id", @@ -270,16 +272,16 @@ var ( "email", "is_email_verified", } - phoneQuery = `SELECT projections.users10.id,` + - ` projections.users10.creation_date,` + - ` projections.users10.change_date,` + - ` projections.users10.resource_owner,` + - ` projections.users10.sequence,` + - ` projections.users10_humans.user_id,` + - ` projections.users10_humans.phone,` + - ` projections.users10_humans.is_phone_verified` + - ` FROM projections.users10` + - ` LEFT JOIN projections.users10_humans ON projections.users10.id = projections.users10_humans.user_id AND projections.users10.instance_id = projections.users10_humans.instance_id` + + phoneQuery = `SELECT projections.users11.id,` + + ` projections.users11.creation_date,` + + ` projections.users11.change_date,` + + ` projections.users11.resource_owner,` + + ` projections.users11.sequence,` + + ` projections.users11_humans.user_id,` + + ` projections.users11_humans.phone,` + + ` projections.users11_humans.is_phone_verified` + + ` FROM projections.users11` + + ` LEFT JOIN projections.users11_humans ON projections.users11.id = projections.users11_humans.user_id AND projections.users11.instance_id = projections.users11_humans.instance_id` + ` AS OF SYSTEM TIME '-1 ms'` phoneCols = []string{ "id", @@ -291,14 +293,14 @@ var ( "phone", "is_phone_verified", } - userUniqueQuery = `SELECT projections.users10.id,` + - ` projections.users10.state,` + - ` projections.users10.username,` + - ` projections.users10_humans.user_id,` + - ` projections.users10_humans.email,` + - ` projections.users10_humans.is_email_verified` + - ` FROM projections.users10` + - ` LEFT JOIN projections.users10_humans ON projections.users10.id = projections.users10_humans.user_id AND projections.users10.instance_id = projections.users10_humans.instance_id` + + userUniqueQuery = `SELECT projections.users11.id,` + + ` projections.users11.state,` + + ` projections.users11.username,` + + ` projections.users11_humans.user_id,` + + ` projections.users11_humans.email,` + + ` projections.users11_humans.is_email_verified` + + ` FROM projections.users11` + + ` LEFT JOIN projections.users11_humans ON projections.users11.id = projections.users11_humans.user_id AND projections.users11.instance_id = projections.users11_humans.instance_id` + ` AS OF SYSTEM TIME '-1 ms'` userUniqueCols = []string{ "id", @@ -308,40 +310,40 @@ var ( "email", "is_email_verified", } - notifyUserQuery = `SELECT projections.users10.id,` + - ` projections.users10.creation_date,` + - ` projections.users10.change_date,` + - ` projections.users10.resource_owner,` + - ` projections.users10.sequence,` + - ` projections.users10.state,` + - ` projections.users10.type,` + - ` projections.users10.username,` + + notifyUserQuery = `SELECT projections.users11.id,` + + ` projections.users11.creation_date,` + + ` projections.users11.change_date,` + + ` projections.users11.resource_owner,` + + ` projections.users11.sequence,` + + ` projections.users11.state,` + + ` projections.users11.type,` + + ` projections.users11.username,` + ` login_names.loginnames,` + ` preferred_login_name.login_name,` + - ` projections.users10_humans.user_id,` + - ` projections.users10_humans.first_name,` + - ` projections.users10_humans.last_name,` + - ` projections.users10_humans.nick_name,` + - ` projections.users10_humans.display_name,` + - ` projections.users10_humans.preferred_language,` + - ` projections.users10_humans.gender,` + - ` projections.users10_humans.avatar_key,` + - ` projections.users10_notifications.user_id,` + - ` projections.users10_notifications.last_email,` + - ` projections.users10_notifications.verified_email,` + - ` projections.users10_notifications.last_phone,` + - ` projections.users10_notifications.verified_phone,` + - ` projections.users10_notifications.password_set,` + + ` projections.users11_humans.user_id,` + + ` projections.users11_humans.first_name,` + + ` projections.users11_humans.last_name,` + + ` projections.users11_humans.nick_name,` + + ` projections.users11_humans.display_name,` + + ` projections.users11_humans.preferred_language,` + + ` projections.users11_humans.gender,` + + ` projections.users11_humans.avatar_key,` + + ` projections.users11_notifications.user_id,` + + ` projections.users11_notifications.last_email,` + + ` projections.users11_notifications.verified_email,` + + ` projections.users11_notifications.last_phone,` + + ` projections.users11_notifications.verified_phone,` + + ` projections.users11_notifications.password_set,` + ` COUNT(*) OVER ()` + - ` FROM projections.users10` + - ` LEFT JOIN projections.users10_humans ON projections.users10.id = projections.users10_humans.user_id AND projections.users10.instance_id = projections.users10_humans.instance_id` + - ` LEFT JOIN projections.users10_notifications ON projections.users10.id = projections.users10_notifications.user_id AND projections.users10.instance_id = projections.users10_notifications.instance_id` + + ` FROM projections.users11` + + ` LEFT JOIN projections.users11_humans ON projections.users11.id = projections.users11_humans.user_id AND projections.users11.instance_id = projections.users11_humans.instance_id` + + ` LEFT JOIN projections.users11_notifications ON projections.users11.id = projections.users11_notifications.user_id AND projections.users11.instance_id = projections.users11_notifications.instance_id` + ` LEFT JOIN` + ` (` + loginNamesQuery + `) AS login_names` + - ` ON login_names.user_id = projections.users10.id AND login_names.instance_id = projections.users10.instance_id` + + ` ON login_names.user_id = projections.users11.id AND login_names.instance_id = projections.users11.instance_id` + ` LEFT JOIN` + ` (` + preferredLoginNameQuery + `) AS preferred_login_name` + - ` ON preferred_login_name.user_id = projections.users10.id AND preferred_login_name.instance_id = projections.users10.instance_id` + + ` ON preferred_login_name.user_id = projections.users11.id AND preferred_login_name.instance_id = projections.users11.instance_id` + ` AS OF SYSTEM TIME '-1 ms'` notifyUserCols = []string{ "id", @@ -372,43 +374,44 @@ var ( "password_set", "count", } - usersQuery = `SELECT projections.users10.id,` + - ` projections.users10.creation_date,` + - ` projections.users10.change_date,` + - ` projections.users10.resource_owner,` + - ` projections.users10.sequence,` + - ` projections.users10.state,` + - ` projections.users10.type,` + - ` projections.users10.username,` + + usersQuery = `SELECT projections.users11.id,` + + ` projections.users11.creation_date,` + + ` projections.users11.change_date,` + + ` projections.users11.resource_owner,` + + ` projections.users11.sequence,` + + ` projections.users11.state,` + + ` projections.users11.type,` + + ` projections.users11.username,` + ` login_names.loginnames,` + ` preferred_login_name.login_name,` + - ` projections.users10_humans.user_id,` + - ` projections.users10_humans.first_name,` + - ` projections.users10_humans.last_name,` + - ` projections.users10_humans.nick_name,` + - ` projections.users10_humans.display_name,` + - ` projections.users10_humans.preferred_language,` + - ` projections.users10_humans.gender,` + - ` projections.users10_humans.avatar_key,` + - ` projections.users10_humans.email,` + - ` projections.users10_humans.is_email_verified,` + - ` projections.users10_humans.phone,` + - ` projections.users10_humans.is_phone_verified,` + - ` projections.users10_machines.user_id,` + - ` projections.users10_machines.name,` + - ` projections.users10_machines.description,` + - ` projections.users10_machines.secret,` + - ` projections.users10_machines.access_token_type,` + + ` projections.users11_humans.user_id,` + + ` projections.users11_humans.first_name,` + + ` projections.users11_humans.last_name,` + + ` projections.users11_humans.nick_name,` + + ` projections.users11_humans.display_name,` + + ` projections.users11_humans.preferred_language,` + + ` projections.users11_humans.gender,` + + ` projections.users11_humans.avatar_key,` + + ` projections.users11_humans.email,` + + ` projections.users11_humans.is_email_verified,` + + ` projections.users11_humans.phone,` + + ` projections.users11_humans.is_phone_verified,` + + ` projections.users11_humans.password_change_required,` + + ` projections.users11_machines.user_id,` + + ` projections.users11_machines.name,` + + ` projections.users11_machines.description,` + + ` projections.users11_machines.secret,` + + ` projections.users11_machines.access_token_type,` + ` COUNT(*) OVER ()` + - ` FROM projections.users10` + - ` LEFT JOIN projections.users10_humans ON projections.users10.id = projections.users10_humans.user_id AND projections.users10.instance_id = projections.users10_humans.instance_id` + - ` LEFT JOIN projections.users10_machines ON projections.users10.id = projections.users10_machines.user_id AND projections.users10.instance_id = projections.users10_machines.instance_id` + + ` FROM projections.users11` + + ` LEFT JOIN projections.users11_humans ON projections.users11.id = projections.users11_humans.user_id AND projections.users11.instance_id = projections.users11_humans.instance_id` + + ` LEFT JOIN projections.users11_machines ON projections.users11.id = projections.users11_machines.user_id AND projections.users11.instance_id = projections.users11_machines.instance_id` + ` LEFT JOIN` + ` (` + loginNamesQuery + `) AS login_names` + - ` ON login_names.user_id = projections.users10.id AND login_names.instance_id = projections.users10.instance_id` + + ` ON login_names.user_id = projections.users11.id AND login_names.instance_id = projections.users11.instance_id` + ` LEFT JOIN` + ` (` + preferredLoginNameQuery + `) AS preferred_login_name` + - ` ON preferred_login_name.user_id = projections.users10.id AND preferred_login_name.instance_id = projections.users10.instance_id` + + ` ON preferred_login_name.user_id = projections.users11.id AND preferred_login_name.instance_id = projections.users11.instance_id` + ` AS OF SYSTEM TIME '-1 ms'` usersCols = []string{ "id", @@ -434,6 +437,7 @@ var ( "is_email_verified", "phone", "is_phone_verified", + "password_change_required", // machine "user_id", "name", @@ -504,6 +508,7 @@ func Test_UserPrepares(t *testing.T) { true, "phone", true, + true, // machine nil, nil, @@ -526,17 +531,18 @@ func Test_UserPrepares(t *testing.T) { LoginNames: database.TextArray[string]{"login_name1", "login_name2"}, PreferredLoginName: "login_name1", Human: &Human{ - FirstName: "first_name", - LastName: "last_name", - NickName: "nick_name", - DisplayName: "display_name", - AvatarKey: "avatar_key", - PreferredLanguage: language.German, - Gender: domain.GenderUnspecified, - Email: "email", - IsEmailVerified: true, - Phone: "phone", - IsPhoneVerified: true, + FirstName: "first_name", + LastName: "last_name", + NickName: "nick_name", + DisplayName: "display_name", + AvatarKey: "avatar_key", + PreferredLanguage: language.German, + Gender: domain.GenderUnspecified, + Email: "email", + IsEmailVerified: true, + Phone: "phone", + IsPhoneVerified: true, + PasswordChangeRequired: true, }, }, }, @@ -571,6 +577,7 @@ func Test_UserPrepares(t *testing.T) { nil, nil, nil, + nil, // machine "id", "name", @@ -631,6 +638,7 @@ func Test_UserPrepares(t *testing.T) { nil, nil, nil, + nil, // machine "id", "name", @@ -1222,6 +1230,7 @@ func Test_UserPrepares(t *testing.T) { true, "phone", true, + true, // machine nil, nil, @@ -1249,17 +1258,18 @@ func Test_UserPrepares(t *testing.T) { LoginNames: database.TextArray[string]{"login_name1", "login_name2"}, PreferredLoginName: "login_name1", Human: &Human{ - FirstName: "first_name", - LastName: "last_name", - NickName: "nick_name", - DisplayName: "display_name", - AvatarKey: "avatar_key", - PreferredLanguage: language.German, - Gender: domain.GenderUnspecified, - Email: "email", - IsEmailVerified: true, - Phone: "phone", - IsPhoneVerified: true, + FirstName: "first_name", + LastName: "last_name", + NickName: "nick_name", + DisplayName: "display_name", + AvatarKey: "avatar_key", + PreferredLanguage: language.German, + Gender: domain.GenderUnspecified, + Email: "email", + IsEmailVerified: true, + Phone: "phone", + IsPhoneVerified: true, + PasswordChangeRequired: true, }, }, }, @@ -1297,6 +1307,7 @@ func Test_UserPrepares(t *testing.T) { true, "phone", true, + true, // machine nil, nil, @@ -1328,6 +1339,7 @@ func Test_UserPrepares(t *testing.T) { nil, nil, nil, + nil, // machine "id", "name", @@ -1355,17 +1367,18 @@ func Test_UserPrepares(t *testing.T) { LoginNames: database.TextArray[string]{"login_name1", "login_name2"}, PreferredLoginName: "login_name1", Human: &Human{ - FirstName: "first_name", - LastName: "last_name", - NickName: "nick_name", - DisplayName: "display_name", - AvatarKey: "avatar_key", - PreferredLanguage: language.German, - Gender: domain.GenderUnspecified, - Email: "email", - IsEmailVerified: true, - Phone: "phone", - IsPhoneVerified: true, + FirstName: "first_name", + LastName: "last_name", + NickName: "nick_name", + DisplayName: "display_name", + AvatarKey: "avatar_key", + PreferredLanguage: language.German, + Gender: domain.GenderUnspecified, + Email: "email", + IsEmailVerified: true, + Phone: "phone", + IsPhoneVerified: true, + PasswordChangeRequired: true, }, }, { diff --git a/internal/user/repository/view/user_session_by_id.sql b/internal/user/repository/view/user_session_by_id.sql index 334369125b..0f9d8c04e9 100644 --- a/internal/user/repository/view/user_session_by_id.sql +++ b/internal/user/repository/view/user_session_by_id.sql @@ -19,8 +19,8 @@ SELECT s.creation_date, s.sequence, s.instance_id FROM auth.user_sessions s - LEFT JOIN projections.users10 u ON s.user_id = u.id AND s.instance_id = u.instance_id - LEFT JOIN projections.users10_humans h ON s.user_id = h.user_id AND s.instance_id = h.instance_id + LEFT JOIN projections.users11 u ON s.user_id = u.id AND s.instance_id = u.instance_id + LEFT JOIN projections.users11_humans h ON s.user_id = h.user_id AND s.instance_id = h.instance_id LEFT JOIN projections.login_names3 l ON s.user_id = l.user_id AND s.instance_id = l.instance_id AND l.is_primary = true WHERE (s.user_agent_id = $1) AND (s.user_id = $2) diff --git a/internal/user/repository/view/user_sessions_by_user_agent.sql b/internal/user/repository/view/user_sessions_by_user_agent.sql index f3fc06b377..1adb11f44c 100644 --- a/internal/user/repository/view/user_sessions_by_user_agent.sql +++ b/internal/user/repository/view/user_sessions_by_user_agent.sql @@ -19,8 +19,8 @@ SELECT s.creation_date, s.sequence, s.instance_id FROM auth.user_sessions s - LEFT JOIN projections.users10 u ON s.user_id = u.id AND s.instance_id = u.instance_id - LEFT JOIN projections.users10_humans h ON s.user_id = h.user_id AND s.instance_id = h.instance_id + LEFT JOIN projections.users11 u ON s.user_id = u.id AND s.instance_id = u.instance_id + LEFT JOIN projections.users11_humans h ON s.user_id = h.user_id AND s.instance_id = h.instance_id LEFT JOIN projections.login_names3 l ON s.user_id = l.user_id AND s.instance_id = l.instance_id AND l.is_primary = true WHERE (s.user_agent_id = $1) AND (s.instance_id = $2) diff --git a/proto/zitadel/user/v2beta/user.proto b/proto/zitadel/user/v2beta/user.proto index 9443dd5117..d74feca10e 100644 --- a/proto/zitadel/user/v2beta/user.proto +++ b/proto/zitadel/user/v2beta/user.proto @@ -134,34 +134,44 @@ message SetMetadataEntry { } message HumanUser { + // Unique identifier of the user. string user_id = 1 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; } ]; + // State of the user, for example active, inactive, locked, deleted, initial. UserState state = 2 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "current state of the user"; } ]; + // Username of the user, which can be globally unique or unique on organization level. string username = 3 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"minnie-mouse\""; } ]; + // Possible usable login names for the user. repeated string login_names = 4 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "[\"gigi@zitadel.com\", \"gigi@zitadel.zitadel.ch\"]"; } ]; + // Preferred login name of the user. string preferred_login_name = 5 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"gigi@zitadel.com\""; } ]; + // Profile information of the user. HumanProfile profile = 6; + // Email of the user, if defined. HumanEmail email = 7; + // Phone of the user, if defined. HumanPhone phone = 8; + // User is required to change the used password on the next login. + bool password_change_required = 9; } message User {