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 <livio.a@gmail.com>
This commit is contained in:
Stefan Benz 2024-03-28 07:21:21 +01:00 committed by GitHub
parent d26391a642
commit 217703395e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 723 additions and 459 deletions

View File

@ -13,15 +13,15 @@ var (
addLowerFieldsToVerifiedEmail string addLowerFieldsToVerifiedEmail string
) )
type AddLowerFieldsToVerifiedEmail struct { type User11AddLowerFieldsToVerifiedEmail struct {
dbClient *database.DB 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) _, err := mig.dbClient.ExecContext(ctx, addLowerFieldsToVerifiedEmail)
return err return err
} }
func (mig *AddLowerFieldsToVerifiedEmail) String() string { func (mig *User11AddLowerFieldsToVerifiedEmail) String() string {
return "25_add_lower_fields_to_verified_email" return "25_user11_add_lower_fields_to_verified_email"
} }

View File

@ -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; 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 users10_notifications_email_search ON projections.users10_notifications (instance_id, verified_email_lower); CREATE INDEX IF NOT EXISTS users11_notifications_email_search ON projections.users11_notifications (instance_id, verified_email_lower);

View File

@ -82,28 +82,28 @@ func MustNewConfig(v *viper.Viper) *Config {
} }
type Steps struct { type Steps struct {
s1ProjectionTable *ProjectionTable s1ProjectionTable *ProjectionTable
s2AssetsTable *AssetTable s2AssetsTable *AssetTable
FirstInstance *FirstInstance FirstInstance *FirstInstance
s5LastFailed *LastFailed s5LastFailed *LastFailed
s6OwnerRemoveColumns *OwnerRemoveColumns s6OwnerRemoveColumns *OwnerRemoveColumns
s7LogstoreTables *LogstoreTables s7LogstoreTables *LogstoreTables
s8AuthTokens *AuthTokenIndexes s8AuthTokens *AuthTokenIndexes
CorrectCreationDate *CorrectCreationDate CorrectCreationDate *CorrectCreationDate
s12AddOTPColumns *AddOTPColumns s12AddOTPColumns *AddOTPColumns
s13FixQuotaProjection *FixQuotaConstraints s13FixQuotaProjection *FixQuotaConstraints
s14NewEventsTable *NewEventsTable s14NewEventsTable *NewEventsTable
s15CurrentStates *CurrentProjectionState s15CurrentStates *CurrentProjectionState
s16UniqueConstraintsLower *UniqueConstraintToLower s16UniqueConstraintsLower *UniqueConstraintToLower
s17AddOffsetToUniqueConstraints *AddOffsetToCurrentStates s17AddOffsetToUniqueConstraints *AddOffsetToCurrentStates
s18AddLowerFieldsToLoginNames *AddLowerFieldsToLoginNames s18AddLowerFieldsToLoginNames *AddLowerFieldsToLoginNames
s19AddCurrentStatesIndex *AddCurrentSequencesIndex s19AddCurrentStatesIndex *AddCurrentSequencesIndex
s20AddByUserSessionIndex *AddByUserIndexToSession s20AddByUserSessionIndex *AddByUserIndexToSession
s21AddBlockFieldToLimits *AddBlockFieldToLimits s21AddBlockFieldToLimits *AddBlockFieldToLimits
s22ActiveInstancesIndex *ActiveInstanceEvents s22ActiveInstancesIndex *ActiveInstanceEvents
s23CorrectGlobalUniqueConstraints *CorrectGlobalUniqueConstraints s23CorrectGlobalUniqueConstraints *CorrectGlobalUniqueConstraints
s24AddActorToAuthTokens *AddActorToAuthTokens s24AddActorToAuthTokens *AddActorToAuthTokens
s25AddLowerFieldsToVerifiedEmail *AddLowerFieldsToVerifiedEmail s25User11AddLowerFieldsToVerifiedEmail *User11AddLowerFieldsToVerifiedEmail
} }
func MustNewSteps(v *viper.Viper) *Steps { func MustNewSteps(v *viper.Viper) *Steps {

View File

@ -137,7 +137,7 @@ func Setup(config *Config, steps *Steps, masterKey string) {
steps.s22ActiveInstancesIndex = &ActiveInstanceEvents{dbClient: queryDBClient} steps.s22ActiveInstancesIndex = &ActiveInstanceEvents{dbClient: queryDBClient}
steps.s23CorrectGlobalUniqueConstraints = &CorrectGlobalUniqueConstraints{dbClient: esPusherDBClient} steps.s23CorrectGlobalUniqueConstraints = &CorrectGlobalUniqueConstraints{dbClient: esPusherDBClient}
steps.s24AddActorToAuthTokens = &AddActorToAuthTokens{dbClient: queryDBClient} 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) err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil)
logging.OnError(err).Fatal("unable to start projections") 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{ for _, step := range []migration.Migration{
steps.s18AddLowerFieldsToLoginNames, steps.s18AddLowerFieldsToLoginNames,
steps.s21AddBlockFieldToLimits, steps.s21AddBlockFieldToLimits,
steps.s25AddLowerFieldsToVerifiedEmail, steps.s25User11AddLowerFieldsToVerifiedEmail,
} { } {
mustExecuteMigration(ctx, eventstoreClient, step, "migration failed") mustExecuteMigration(ctx, eventstoreClient, step, "migration failed")
} }

View File

@ -52,7 +52,7 @@ func TestMain(m *testing.M) {
UserId: User.GetUserId(), UserId: User.GetUserId(),
VerificationCode: User.GetPhoneCode(), VerificationCode: User.GetPhoneCode(),
}) })
Tester.SetUserPassword(CTX, User.GetUserId(), integration.UserPassword) Tester.SetUserPassword(CTX, User.GetUserId(), integration.UserPassword, false)
Tester.RegisterUserPasskey(CTX, User.GetUserId()) Tester.RegisterUserPasskey(CTX, User.GetUserId())
DeactivatedUser = Tester.CreateHumanUser(CTX) DeactivatedUser = Tester.CreateHumanUser(CTX)
Tester.Client.UserV2.DeactivateUser(CTX, &user.DeactivateUserRequest{UserId: DeactivatedUser.GetUserId()}) 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) { func TestServer_DeleteSession_own_session(t *testing.T) {
// create two users for the test and a session each to get tokens for authorization // create two users for the test and a session each to get tokens for authorization
user1 := Tester.CreateHumanUser(CTX) 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) _, token1, _, _ := Tester.CreatePasswordSession(t, CTX, user1.GetUserId(), integration.UserPassword)
user2 := Tester.CreateHumanUser(CTX) 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) _, token2, _, _ := Tester.CreatePasswordSession(t, CTX, user2.GetUserId(), integration.UserPassword)
// create a new session for the first user // create a new session for the first user

View File

@ -101,6 +101,7 @@ func humanToPb(userQ *query.Human, assetPrefix, owner string) *user.HumanUser {
Phone: string(userQ.Phone), Phone: string(userQ.Phone),
IsVerified: userQ.IsPhoneVerified, IsVerified: userQ.IsPhoneVerified,
}, },
PasswordChangeRequired: userQ.PasswordChangeRequired,
} }
} }

View File

@ -8,9 +8,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert"
"github.com/muhlemmer/gu" "github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/timestamppb" "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 { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -313,7 +358,11 @@ func TestServer_ListUsers(t *testing.T) {
args: args{ args: args{
IamCTX, IamCTX,
1, 1,
&user.ListUsersRequest{}, &user.ListUsersRequest{
Queries: []*user.SearchQuery{
OrganizationIdQuery(orgResp.OrganizationId),
},
},
func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) {
infos := make([]userAttr, len(usernames)) infos := make([]userAttr, len(usernames))
userIDs := make([]string, 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", name: "list user by id multiple, ok",
args: args{ args: args{
IamCTX, IamCTX,
3, 3,
&user.ListUsersRequest{}, &user.ListUsersRequest{
Queries: []*user.SearchQuery{
OrganizationIdQuery(orgResp.OrganizationId),
},
},
func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) {
infos := make([]userAttr, len(usernames)) infos := make([]userAttr, len(usernames))
userIDs := make([]string, len(usernames)) userIDs := make([]string, len(usernames))
@ -455,7 +564,11 @@ func TestServer_ListUsers(t *testing.T) {
args: args{ args: args{
IamCTX, IamCTX,
1, 1,
&user.ListUsersRequest{}, &user.ListUsersRequest{
Queries: []*user.SearchQuery{
OrganizationIdQuery(orgResp.OrganizationId),
},
},
func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) {
infos := make([]userAttr, len(usernames)) infos := make([]userAttr, len(usernames))
userIDs := make([]string, len(usernames)) userIDs := make([]string, len(usernames))
@ -505,7 +618,11 @@ func TestServer_ListUsers(t *testing.T) {
args: args{ args: args{
IamCTX, IamCTX,
1, 1,
&user.ListUsersRequest{}, &user.ListUsersRequest{
Queries: []*user.SearchQuery{
OrganizationIdQuery(orgResp.OrganizationId),
},
},
func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) {
infos := make([]userAttr, len(usernames)) infos := make([]userAttr, len(usernames))
for i, username := range usernames { for i, username := range usernames {
@ -553,7 +670,11 @@ func TestServer_ListUsers(t *testing.T) {
args: args{ args: args{
IamCTX, IamCTX,
3, 3,
&user.ListUsersRequest{}, &user.ListUsersRequest{
Queries: []*user.SearchQuery{
OrganizationIdQuery(orgResp.OrganizationId),
},
},
func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) { func(ctx context.Context, usernames []string, request *user.ListUsersRequest) ([]userAttr, error) {
infos := make([]userAttr, len(usernames)) infos := make([]userAttr, len(usernames))
for i, username := range usernames { for i, username := range usernames {
@ -644,6 +765,7 @@ func TestServer_ListUsers(t *testing.T) {
IamCTX, IamCTX,
3, 3,
&user.ListUsersRequest{Queries: []*user.SearchQuery{ &user.ListUsersRequest{Queries: []*user.SearchQuery{
OrganizationIdQuery(orgResp.OrganizationId),
InUserEmailsQuery([]string{"notfound"}), InUserEmailsQuery([]string{"notfound"}),
}, },
}, },

View File

@ -47,7 +47,7 @@ func TestMain(m *testing.M) {
CTX, _ = Tester.WithAuthorization(ctx, integration.OrgOwner), errCtx CTX, _ = Tester.WithAuthorization(ctx, integration.OrgOwner), errCtx
User = Tester.CreateHumanUser(CTX) User = Tester.CreateHumanUser(CTX)
Tester.SetUserPassword(CTX, User.GetUserId(), integration.UserPassword) Tester.SetUserPassword(CTX, User.GetUserId(), integration.UserPassword, false)
Tester.RegisterUserPasskey(CTX, User.GetUserId()) Tester.RegisterUserPasskey(CTX, User.GetUserId())
CTXLOGIN, _ = Tester.WithAuthorization(ctx, integration.Login), errCtx CTXLOGIN, _ = Tester.WithAuthorization(ctx, integration.Login), errCtx
return m.Run() return m.Run()
@ -321,7 +321,7 @@ func Test_ZITADEL_API_terminated_session_user_disabled(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
disabledUser := Tester.CreateHumanUser(CTX) 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) authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope)
sessionID, sessionToken, startTime, changeTime := Tester.CreatePasswordSession(t, CTXLOGIN, disabledUser.GetUserId(), integration.UserPassword) sessionID, sessionToken, startTime, changeTime := Tester.CreatePasswordSession(t, CTXLOGIN, disabledUser.GetUserId(), integration.UserPassword)
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{ linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{

View File

@ -277,10 +277,13 @@ func (s *Tester) RegisterUserU2F(ctx context.Context, userID string) {
logging.OnError(err).Fatal("create user u2f") 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{ _, err := s.Client.UserV2.SetPassword(ctx, &user.SetPasswordRequest{
UserId: userID, UserId: userID,
NewPassword: &user.Password{Password: password}, NewPassword: &user.Password{
Password: password,
ChangeRequired: changeRequired,
},
}) })
logging.OnError(err).Fatal("set user password") logging.OnError(err).Fatal("set user password")
} }

View File

@ -1,6 +1,6 @@
with usr as ( 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 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 left join projections.login_names3 n on u.id = n.user_id and u.instance_id = n.instance_id
where u.id = $1 where u.id = $1
and u.instance_id = $2 and u.instance_id = $2
@ -9,7 +9,7 @@ with usr as (
human as ( human as (
select $1 as user_id, row_to_json(r) as human from ( 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 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 where user_id = $1
and instance_id = $2 and instance_id = $2
) r ) r
@ -17,7 +17,7 @@ human as (
machine as ( machine as (
select $1 as user_id, row_to_json(r) as machine from ( select $1 as user_id, row_to_json(r) as machine from (
select name, description select name, description
from projections.users10_machines from projections.users11_machines
where user_id = $1 where user_id = $1
and instance_id = $2 and instance_id = $2
) r ) r

View File

@ -21,21 +21,21 @@ var (
", members.user_id" + ", members.user_id" +
", members.roles" + ", members.roles" +
", projections.login_names3.login_name" + ", projections.login_names3.login_name" +
", projections.users10_humans.email" + ", projections.users11_humans.email" +
", projections.users10_humans.first_name" + ", projections.users11_humans.first_name" +
", projections.users10_humans.last_name" + ", projections.users11_humans.last_name" +
", projections.users10_humans.display_name" + ", projections.users11_humans.display_name" +
", projections.users10_machines.name" + ", projections.users11_machines.name" +
", projections.users10_humans.avatar_key" + ", projections.users11_humans.avatar_key" +
", projections.users10.type" + ", projections.users11.type" +
", COUNT(*) OVER () " + ", COUNT(*) OVER () " +
"FROM projections.instance_members4 AS members " + "FROM projections.instance_members4 AS members " +
"LEFT JOIN projections.users10_humans " + "LEFT JOIN projections.users11_humans " +
"ON members.user_id = projections.users10_humans.user_id AND members.instance_id = projections.users10_humans.instance_id " + "ON members.user_id = projections.users11_humans.user_id AND members.instance_id = projections.users11_humans.instance_id " +
"LEFT JOIN projections.users10_machines " + "LEFT JOIN projections.users11_machines " +
"ON members.user_id = projections.users10_machines.user_id AND members.instance_id = projections.users10_machines.instance_id " + "ON members.user_id = projections.users11_machines.user_id AND members.instance_id = projections.users11_machines.instance_id " +
"LEFT JOIN projections.users10 " + "LEFT JOIN projections.users11 " +
"ON members.user_id = projections.users10.id AND members.instance_id = projections.users10.instance_id " + "ON members.user_id = projections.users11.id AND members.instance_id = projections.users11.instance_id " +
"LEFT JOIN projections.login_names3 " + "LEFT JOIN projections.login_names3 " +
"ON members.user_id = projections.login_names3.user_id AND members.instance_id = projections.login_names3.instance_id " + "ON members.user_id = projections.login_names3.user_id AND members.instance_id = projections.login_names3.instance_id " +
"AS OF SYSTEM TIME '-1 ms' " + "AS OF SYSTEM TIME '-1 ms' " +

View File

@ -21,24 +21,24 @@ var (
", members.user_id" + ", members.user_id" +
", members.roles" + ", members.roles" +
", projections.login_names3.login_name" + ", projections.login_names3.login_name" +
", projections.users10_humans.email" + ", projections.users11_humans.email" +
", projections.users10_humans.first_name" + ", projections.users11_humans.first_name" +
", projections.users10_humans.last_name" + ", projections.users11_humans.last_name" +
", projections.users10_humans.display_name" + ", projections.users11_humans.display_name" +
", projections.users10_machines.name" + ", projections.users11_machines.name" +
", projections.users10_humans.avatar_key" + ", projections.users11_humans.avatar_key" +
", projections.users10.type" + ", projections.users11.type" +
", COUNT(*) OVER () " + ", COUNT(*) OVER () " +
"FROM projections.org_members4 AS members " + "FROM projections.org_members4 AS members " +
"LEFT JOIN projections.users10_humans " + "LEFT JOIN projections.users11_humans " +
"ON members.user_id = projections.users10_humans.user_id " + "ON members.user_id = projections.users11_humans.user_id " +
"AND members.instance_id = projections.users10_humans.instance_id " + "AND members.instance_id = projections.users11_humans.instance_id " +
"LEFT JOIN projections.users10_machines " + "LEFT JOIN projections.users11_machines " +
"ON members.user_id = projections.users10_machines.user_id " + "ON members.user_id = projections.users11_machines.user_id " +
"AND members.instance_id = projections.users10_machines.instance_id " + "AND members.instance_id = projections.users11_machines.instance_id " +
"LEFT JOIN projections.users10 " + "LEFT JOIN projections.users11 " +
"ON members.user_id = projections.users10.id " + "ON members.user_id = projections.users11.id " +
"AND members.instance_id = projections.users10.instance_id " + "AND members.instance_id = projections.users11.instance_id " +
"LEFT JOIN projections.login_names3 " + "LEFT JOIN projections.login_names3 " +
"ON members.user_id = projections.login_names3.user_id " + "ON members.user_id = projections.login_names3.user_id " +
"AND members.instance_id = projections.login_names3.instance_id " + "AND members.instance_id = projections.login_names3.instance_id " +

View File

@ -21,24 +21,24 @@ var (
", members.user_id" + ", members.user_id" +
", members.roles" + ", members.roles" +
", projections.login_names3.login_name" + ", projections.login_names3.login_name" +
", projections.users10_humans.email" + ", projections.users11_humans.email" +
", projections.users10_humans.first_name" + ", projections.users11_humans.first_name" +
", projections.users10_humans.last_name" + ", projections.users11_humans.last_name" +
", projections.users10_humans.display_name" + ", projections.users11_humans.display_name" +
", projections.users10_machines.name" + ", projections.users11_machines.name" +
", projections.users10_humans.avatar_key" + ", projections.users11_humans.avatar_key" +
", projections.users10.type" + ", projections.users11.type" +
", COUNT(*) OVER () " + ", COUNT(*) OVER () " +
"FROM projections.project_grant_members4 AS members " + "FROM projections.project_grant_members4 AS members " +
"LEFT JOIN projections.users10_humans " + "LEFT JOIN projections.users11_humans " +
"ON members.user_id = projections.users10_humans.user_id " + "ON members.user_id = projections.users11_humans.user_id " +
"AND members.instance_id = projections.users10_humans.instance_id " + "AND members.instance_id = projections.users11_humans.instance_id " +
"LEFT JOIN projections.users10_machines " + "LEFT JOIN projections.users11_machines " +
"ON members.user_id = projections.users10_machines.user_id " + "ON members.user_id = projections.users11_machines.user_id " +
"AND members.instance_id = projections.users10_machines.instance_id " + "AND members.instance_id = projections.users11_machines.instance_id " +
"LEFT JOIN projections.users10 " + "LEFT JOIN projections.users11 " +
"ON members.user_id = projections.users10.id " + "ON members.user_id = projections.users11.id " +
"AND members.instance_id = projections.users10.instance_id " + "AND members.instance_id = projections.users11.instance_id " +
"LEFT JOIN projections.login_names3 " + "LEFT JOIN projections.login_names3 " +
"ON members.user_id = projections.login_names3.user_id " + "ON members.user_id = projections.login_names3.user_id " +
"AND members.instance_id = projections.login_names3.instance_id " + "AND members.instance_id = projections.login_names3.instance_id " +

View File

@ -21,24 +21,24 @@ var (
", members.user_id" + ", members.user_id" +
", members.roles" + ", members.roles" +
", projections.login_names3.login_name" + ", projections.login_names3.login_name" +
", projections.users10_humans.email" + ", projections.users11_humans.email" +
", projections.users10_humans.first_name" + ", projections.users11_humans.first_name" +
", projections.users10_humans.last_name" + ", projections.users11_humans.last_name" +
", projections.users10_humans.display_name" + ", projections.users11_humans.display_name" +
", projections.users10_machines.name" + ", projections.users11_machines.name" +
", projections.users10_humans.avatar_key" + ", projections.users11_humans.avatar_key" +
", projections.users10.type" + ", projections.users11.type" +
", COUNT(*) OVER () " + ", COUNT(*) OVER () " +
"FROM projections.project_members4 AS members " + "FROM projections.project_members4 AS members " +
"LEFT JOIN projections.users10_humans " + "LEFT JOIN projections.users11_humans " +
"ON members.user_id = projections.users10_humans.user_id " + "ON members.user_id = projections.users11_humans.user_id " +
"AND members.instance_id = projections.users10_humans.instance_id " + "AND members.instance_id = projections.users11_humans.instance_id " +
"LEFT JOIN projections.users10_machines " + "LEFT JOIN projections.users11_machines " +
"ON members.user_id = projections.users10_machines.user_id " + "ON members.user_id = projections.users11_machines.user_id " +
"AND members.instance_id = projections.users10_machines.instance_id " + "AND members.instance_id = projections.users11_machines.instance_id " +
"LEFT JOIN projections.users10 " + "LEFT JOIN projections.users11 " +
"ON members.user_id = projections.users10.id " + "ON members.user_id = projections.users11.id " +
"AND members.instance_id = projections.users10.instance_id " + "AND members.instance_id = projections.users11.instance_id " +
"LEFT JOIN projections.login_names3 " + "LEFT JOIN projections.login_names3 " +
"ON members.user_id = projections.login_names3.user_id " + "ON members.user_id = projections.login_names3.user_id " +
"AND members.instance_id = projections.login_names3.instance_id " + "AND members.instance_id = projections.login_names3.instance_id " +

View File

@ -15,7 +15,7 @@ import (
) )
const ( const (
UserTable = "projections.users10" UserTable = "projections.users11"
UserHumanTable = UserTable + "_" + UserHumanSuffix UserHumanTable = UserTable + "_" + UserHumanSuffix
UserMachineTable = UserTable + "_" + UserMachineSuffix UserMachineTable = UserTable + "_" + UserMachineSuffix
UserNotifyTable = UserTable + "_" + UserNotifySuffix UserNotifyTable = UserTable + "_" + UserNotifySuffix
@ -30,9 +30,10 @@ const (
UserUsernameCol = "username" UserUsernameCol = "username"
UserTypeCol = "type" UserTypeCol = "type"
UserHumanSuffix = "humans" UserHumanSuffix = "humans"
HumanUserIDCol = "user_id" HumanUserIDCol = "user_id"
HumanUserInstanceIDCol = "instance_id" HumanUserInstanceIDCol = "instance_id"
HumanPasswordChangeRequired = "password_change_required"
// profile // profile
HumanFirstNameCol = "first_name" HumanFirstNameCol = "first_name"
@ -113,6 +114,7 @@ func (*userProjection) Init() *old_handler.Check {
handler.NewColumn(HumanIsEmailVerifiedCol, handler.ColumnTypeBool, handler.Default(false)), handler.NewColumn(HumanIsEmailVerifiedCol, handler.ColumnTypeBool, handler.Default(false)),
handler.NewColumn(HumanPhoneCol, handler.ColumnTypeText, handler.Nullable()), handler.NewColumn(HumanPhoneCol, handler.ColumnTypeText, handler.Nullable()),
handler.NewColumn(HumanIsPhoneVerifiedCol, handler.ColumnTypeBool, handler.Nullable()), handler.NewColumn(HumanIsPhoneVerifiedCol, handler.ColumnTypeBool, handler.Nullable()),
handler.NewColumn(HumanPasswordChangeRequired, handler.ColumnTypeBool),
}, },
handler.NewPrimaryKey(HumanUserInstanceIDCol, HumanUserIDCol), handler.NewPrimaryKey(HumanUserInstanceIDCol, HumanUserIDCol),
UserHumanSuffix, 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(HumanGenderCol, &sql.NullInt16{Int16: int16(e.Gender), Valid: e.Gender.Specified()}),
handler.NewCol(HumanEmailCol, e.EmailAddress), handler.NewCol(HumanEmailCol, e.EmailAddress),
handler.NewCol(HumanPhoneCol, &sql.NullString{String: string(e.PhoneNumber), Valid: e.PhoneNumber != ""}), handler.NewCol(HumanPhoneCol, &sql.NullString{String: string(e.PhoneNumber), Valid: e.PhoneNumber != ""}),
handler.NewCol(HumanPasswordChangeRequired, e.ChangeRequired),
}, },
handler.WithTableSuffix(UserHumanSuffix), 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(HumanGenderCol, &sql.NullInt16{Int16: int16(e.Gender), Valid: e.Gender.Specified()}),
handler.NewCol(HumanEmailCol, e.EmailAddress), handler.NewCol(HumanEmailCol, e.EmailAddress),
handler.NewCol(HumanPhoneCol, &sql.NullString{String: string(e.PhoneNumber), Valid: e.PhoneNumber != ""}), handler.NewCol(HumanPhoneCol, &sql.NullString{String: string(e.PhoneNumber), Valid: e.PhoneNumber != ""}),
handler.NewCol(HumanPasswordChangeRequired, e.ChangeRequired),
}, },
handler.WithTableSuffix(UserHumanSuffix), handler.WithTableSuffix(UserHumanSuffix),
), ),
@ -904,17 +908,28 @@ func (p *userProjection) reduceHumanPasswordChanged(event eventstore.Event) (*ha
if !ok { if !ok {
return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-jqXUY", "reduce.wrong.event.type %s", user.HumanPasswordChangedType) return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-jqXUY", "reduce.wrong.event.type %s", user.HumanPasswordChangedType)
} }
return handler.NewMultiStatement(
return handler.NewUpdateStatement(
e, e,
[]handler.Column{ handler.AddUpdateStatement(
handler.NewCol(NotifyPasswordSetCol, true), []handler.Column{
}, handler.NewCol(HumanPasswordChangeRequired, e.ChangeRequired),
[]handler.Condition{ },
handler.NewCond(NotifyUserIDCol, e.Aggregate().ID), []handler.Condition{
handler.NewCond(NotifyInstanceIDCol, e.Aggregate().InstanceID), handler.NewCond(HumanUserIDCol, e.Aggregate().ID),
}, handler.NewCond(HumanUserInstanceIDCol, e.Aggregate().InstanceID),
handler.WithTableSuffix(UserNotifySuffix), },
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 ), nil
} }

View File

@ -40,7 +40,8 @@ func TestUserProjection_reduces(t *testing.T) {
"preferredLanguage": "ch-DE", "preferredLanguage": "ch-DE",
"gender": 1, "gender": 1,
"email": "email@zitadel.com", "email": "email@zitadel.com",
"phone": "+41 00 000 00 00" "phone": "+41 00 000 00 00",
"changeRequired": true
}`), }`),
), user.HumanAddedEventMapper), ), user.HumanAddedEventMapper),
}, },
@ -51,7 +52,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
anyArg{}, 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -77,10 +78,11 @@ func TestUserProjection_reduces(t *testing.T) {
&sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true}, &sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true},
domain.EmailAddress("email@zitadel.com"), domain.EmailAddress("email@zitadel.com"),
&sql.NullString{String: "+41 00 000 00 00", Valid: true}, &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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -120,7 +122,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
anyArg{}, 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -146,10 +148,11 @@ func TestUserProjection_reduces(t *testing.T) {
&sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true}, &sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true},
domain.EmailAddress("email@zitadel.com"), domain.EmailAddress("email@zitadel.com"),
&sql.NullString{String: "+41 00 000 00 00", Valid: true}, &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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -184,7 +187,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
anyArg{}, 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -210,10 +213,11 @@ func TestUserProjection_reduces(t *testing.T) {
&sql.NullInt16{}, &sql.NullInt16{},
domain.EmailAddress("email@zitadel.com"), domain.EmailAddress("email@zitadel.com"),
&sql.NullString{}, &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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -242,7 +246,8 @@ func TestUserProjection_reduces(t *testing.T) {
"preferredLanguage": "ch-DE", "preferredLanguage": "ch-DE",
"gender": 1, "gender": 1,
"email": "email@zitadel.com", "email": "email@zitadel.com",
"phone": "+41 00 000 00 00" "phone": "+41 00 000 00 00",
"changeRequired": true
}`), }`),
), user.HumanRegisteredEventMapper), ), user.HumanRegisteredEventMapper),
}, },
@ -253,7 +258,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
anyArg{}, 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -279,10 +284,11 @@ func TestUserProjection_reduces(t *testing.T) {
&sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true}, &sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true},
domain.EmailAddress("email@zitadel.com"), domain.EmailAddress("email@zitadel.com"),
&sql.NullString{String: "+41 00 000 00 00", Valid: true}, &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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -322,7 +328,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
anyArg{}, 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -348,10 +354,11 @@ func TestUserProjection_reduces(t *testing.T) {
&sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true}, &sql.NullInt16{Int16: int16(domain.GenderFemale), Valid: true},
domain.EmailAddress("email@zitadel.com"), domain.EmailAddress("email@zitadel.com"),
&sql.NullString{String: "+41 00 000 00 00", Valid: true}, &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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -386,7 +393,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
anyArg{}, 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -412,10 +419,11 @@ func TestUserProjection_reduces(t *testing.T) {
&sql.NullInt16{}, &sql.NullInt16{},
domain.EmailAddress("email@zitadel.com"), domain.EmailAddress("email@zitadel.com"),
&sql.NullString{}, &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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -445,7 +453,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
domain.UserStateInitial, domain.UserStateInitial,
"agg-id", "agg-id",
@ -473,7 +481,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
domain.UserStateInitial, domain.UserStateInitial,
"agg-id", "agg-id",
@ -501,7 +509,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
domain.UserStateActive, domain.UserStateActive,
"agg-id", "agg-id",
@ -529,7 +537,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
domain.UserStateActive, domain.UserStateActive,
"agg-id", "agg-id",
@ -557,7 +565,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
domain.UserStateLocked, domain.UserStateLocked,
@ -587,7 +595,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
domain.UserStateActive, domain.UserStateActive,
@ -617,7 +625,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
domain.UserStateInactive, domain.UserStateInactive,
@ -647,7 +655,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
domain.UserStateActive, domain.UserStateActive,
@ -677,7 +685,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -706,7 +714,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
"username", "username",
@ -738,7 +746,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
"id@temporary.domain", "id@temporary.domain",
@ -775,7 +783,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
"first-name", "first-name",
"last-name", "last-name",
@ -824,7 +832,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
"first-name", "first-name",
"last-name", "last-name",
@ -868,7 +876,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
domain.PhoneNumber("+41 00 000 00 00"), domain.PhoneNumber("+41 00 000 00 00"),
false, 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{}{ expectedArgs: []interface{}{
&sql.NullString{String: "+41 00 000 00 00", Valid: true}, &sql.NullString{String: "+41 00 000 00 00", Valid: true},
"agg-id", "agg-id",
@ -916,7 +924,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
domain.PhoneNumber("+41 00 000 00 00"), domain.PhoneNumber("+41 00 000 00 00"),
false, 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{}{ expectedArgs: []interface{}{
&sql.NullString{String: "+41 00 000 00 00", Valid: true}, &sql.NullString{String: "+41 00 000 00 00", Valid: true},
"agg-id", "agg-id",
@ -962,7 +970,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
nil, nil,
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{}{ expectedArgs: []interface{}{
nil, nil,
nil, nil,
@ -1009,7 +1017,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
nil, nil,
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{}{ expectedArgs: []interface{}{
nil, nil,
nil, nil,
@ -1056,7 +1064,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
true, true,
"agg-id", "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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -1100,7 +1108,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
true, true,
"agg-id", "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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -1146,7 +1154,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
domain.EmailAddress("email@zitadel.com"), domain.EmailAddress("email@zitadel.com"),
false, 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{}{ expectedArgs: []interface{}{
&sql.NullString{String: "email@zitadel.com", Valid: true}, &sql.NullString{String: "email@zitadel.com", Valid: true},
"agg-id", "agg-id",
@ -1194,7 +1202,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
domain.EmailAddress("email@zitadel.com"), domain.EmailAddress("email@zitadel.com"),
false, 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{}{ expectedArgs: []interface{}{
&sql.NullString{String: "email@zitadel.com", Valid: true}, &sql.NullString{String: "email@zitadel.com", Valid: true},
"agg-id", "agg-id",
@ -1240,7 +1248,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
true, true,
"agg-id", "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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -1284,7 +1292,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
true, true,
"agg-id", "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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -1330,7 +1338,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
"users/agg-id/avatar", "users/agg-id/avatar",
"agg-id", "agg-id",
@ -1367,7 +1375,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
nil, nil,
"agg-id", "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", name: "reduceMachineAddedEvent no description",
args: args{ args: args{
@ -1407,7 +1491,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
anyArg{}, 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -1455,7 +1539,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
anyArg{}, 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{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
"instance-id", "instance-id",
@ -1502,7 +1586,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
"machine-name", "machine-name",
"description", "description",
@ -1542,7 +1626,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
"machine-name", "machine-name",
"agg-id", "agg-id",
@ -1581,7 +1665,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
"description", "description",
"agg-id", "agg-id",
@ -1639,7 +1723,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
&crypto.CryptoValue{ &crypto.CryptoValue{
CryptoType: crypto.TypeHash, CryptoType: crypto.TypeHash,
@ -1680,7 +1764,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), 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{}{ expectedArgs: []interface{}{
nil, nil,
"agg-id", "agg-id",
@ -1717,7 +1801,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ 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{}{ expectedArgs: []interface{}{
"instance-id", "instance-id",
"agg-id", "agg-id",
@ -1744,7 +1828,7 @@ func TestUserProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "DELETE FROM projections.users10 WHERE (instance_id = $1)", expectedStmt: "DELETE FROM projections.users11 WHERE (instance_id = $1)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
"agg-id", "agg-id",
}, },

View File

@ -31,7 +31,7 @@ var (
` projections.sessions8.user_resource_owner,` + ` projections.sessions8.user_resource_owner,` +
` projections.sessions8.user_checked_at,` + ` projections.sessions8.user_checked_at,` +
` projections.login_names3.login_name,` + ` projections.login_names3.login_name,` +
` projections.users10_humans.display_name,` + ` projections.users11_humans.display_name,` +
` projections.sessions8.password_checked_at,` + ` projections.sessions8.password_checked_at,` +
` projections.sessions8.intent_checked_at,` + ` projections.sessions8.intent_checked_at,` +
` projections.sessions8.webauthn_checked_at,` + ` projections.sessions8.webauthn_checked_at,` +
@ -48,8 +48,8 @@ var (
` projections.sessions8.expiration` + ` projections.sessions8.expiration` +
` FROM projections.sessions8` + ` 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.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.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.users10 ON projections.sessions8.user_id = projections.users10.id AND projections.sessions8.instance_id = projections.users10.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'`) ` AS OF SYSTEM TIME '-1 ms'`)
expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions8.id,` + expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions8.id,` +
` projections.sessions8.creation_date,` + ` projections.sessions8.creation_date,` +
@ -62,7 +62,7 @@ var (
` projections.sessions8.user_resource_owner,` + ` projections.sessions8.user_resource_owner,` +
` projections.sessions8.user_checked_at,` + ` projections.sessions8.user_checked_at,` +
` projections.login_names3.login_name,` + ` projections.login_names3.login_name,` +
` projections.users10_humans.display_name,` + ` projections.users11_humans.display_name,` +
` projections.sessions8.password_checked_at,` + ` projections.sessions8.password_checked_at,` +
` projections.sessions8.intent_checked_at,` + ` projections.sessions8.intent_checked_at,` +
` projections.sessions8.webauthn_checked_at,` + ` projections.sessions8.webauthn_checked_at,` +
@ -75,8 +75,8 @@ var (
` COUNT(*) OVER ()` + ` COUNT(*) OVER ()` +
` FROM projections.sessions8` + ` 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.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.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.users10 ON projections.sessions8.user_id = projections.users10.id AND projections.sessions8.instance_id = projections.users10.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'`) ` AS OF SYSTEM TIME '-1 ms'`)
sessionCols = []string{ sessionCols = []string{

View File

@ -42,17 +42,18 @@ type User struct {
} }
type Human struct { type Human struct {
FirstName string `json:"first_name,omitempty"` FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"` LastName string `json:"last_name,omitempty"`
NickName string `json:"nick_name,omitempty"` NickName string `json:"nick_name,omitempty"`
DisplayName string `json:"display_name,omitempty"` DisplayName string `json:"display_name,omitempty"`
AvatarKey string `json:"avatar_key,omitempty"` AvatarKey string `json:"avatar_key,omitempty"`
PreferredLanguage language.Tag `json:"preferred_language,omitempty"` PreferredLanguage language.Tag `json:"preferred_language,omitempty"`
Gender domain.Gender `json:"gender,omitempty"` Gender domain.Gender `json:"gender,omitempty"`
Email domain.EmailAddress `json:"email,omitempty"` Email domain.EmailAddress `json:"email,omitempty"`
IsEmailVerified bool `json:"is_email_verified,omitempty"` IsEmailVerified bool `json:"is_email_verified,omitempty"`
Phone domain.PhoneNumber `json:"phone,omitempty"` Phone domain.PhoneNumber `json:"phone,omitempty"`
IsPhoneVerified bool `json:"is_phone_verified,omitempty"` IsPhoneVerified bool `json:"is_phone_verified,omitempty"`
PasswordChangeRequired bool `json:"password_change_required,omitempty"`
} }
type Profile struct { type Profile struct {
@ -275,6 +276,11 @@ var (
name: projection.HumanIsPhoneVerifiedCol, name: projection.HumanIsPhoneVerifiedCol,
table: humanTable, table: humanTable,
} }
HumanPasswordChangeRequiredCol = Column{
name: projection.HumanPasswordChangeRequired,
table: humanTable,
}
) )
var ( var (
@ -816,6 +822,7 @@ func scanUser(row *sql.Row) (*User, error) {
isEmailVerified := sql.NullBool{} isEmailVerified := sql.NullBool{}
phone := sql.NullString{} phone := sql.NullString{}
isPhoneVerified := sql.NullBool{} isPhoneVerified := sql.NullBool{}
passwordChangeRequired := sql.NullBool{}
machineID := sql.NullString{} machineID := sql.NullString{}
name := sql.NullString{} name := sql.NullString{}
@ -846,6 +853,7 @@ func scanUser(row *sql.Row) (*User, error) {
&isEmailVerified, &isEmailVerified,
&phone, &phone,
&isPhoneVerified, &isPhoneVerified,
&passwordChangeRequired,
&machineID, &machineID,
&name, &name,
&description, &description,
@ -865,17 +873,18 @@ func scanUser(row *sql.Row) (*User, error) {
if humanID.Valid { if humanID.Valid {
u.Human = &Human{ u.Human = &Human{
FirstName: firstName.String, FirstName: firstName.String,
LastName: lastName.String, LastName: lastName.String,
NickName: nickName.String, NickName: nickName.String,
DisplayName: displayName.String, DisplayName: displayName.String,
AvatarKey: avatarKey.String, AvatarKey: avatarKey.String,
PreferredLanguage: language.Make(preferredLanguage.String), PreferredLanguage: language.Make(preferredLanguage.String),
Gender: domain.Gender(gender.Int32), Gender: domain.Gender(gender.Int32),
Email: domain.EmailAddress(email.String), Email: domain.EmailAddress(email.String),
IsEmailVerified: isEmailVerified.Bool, IsEmailVerified: isEmailVerified.Bool,
Phone: domain.PhoneNumber(phone.String), Phone: domain.PhoneNumber(phone.String),
IsPhoneVerified: isPhoneVerified.Bool, IsPhoneVerified: isPhoneVerified.Bool,
PasswordChangeRequired: passwordChangeRequired.Bool,
} }
} else if machineID.Valid { } else if machineID.Valid {
u.Machine = &Machine{ u.Machine = &Machine{
@ -920,6 +929,7 @@ func prepareUserQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder
HumanIsEmailVerifiedCol.identifier(), HumanIsEmailVerifiedCol.identifier(),
HumanPhoneCol.identifier(), HumanPhoneCol.identifier(),
HumanIsPhoneVerifiedCol.identifier(), HumanIsPhoneVerifiedCol.identifier(),
HumanPasswordChangeRequiredCol.identifier(),
MachineUserIDCol.identifier(), MachineUserIDCol.identifier(),
MachineNameCol.identifier(), MachineNameCol.identifier(),
MachineDescriptionCol.identifier(), MachineDescriptionCol.identifier(),
@ -1306,6 +1316,7 @@ func prepareUsersQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilde
HumanIsEmailVerifiedCol.identifier(), HumanIsEmailVerifiedCol.identifier(),
HumanPhoneCol.identifier(), HumanPhoneCol.identifier(),
HumanIsPhoneVerifiedCol.identifier(), HumanIsPhoneVerifiedCol.identifier(),
HumanPasswordChangeRequiredCol.identifier(),
MachineUserIDCol.identifier(), MachineUserIDCol.identifier(),
MachineNameCol.identifier(), MachineNameCol.identifier(),
MachineDescriptionCol.identifier(), MachineDescriptionCol.identifier(),
@ -1344,6 +1355,7 @@ func prepareUsersQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilde
isEmailVerified := sql.NullBool{} isEmailVerified := sql.NullBool{}
phone := sql.NullString{} phone := sql.NullString{}
isPhoneVerified := sql.NullBool{} isPhoneVerified := sql.NullBool{}
passwordChangeRequired := sql.NullBool{}
machineID := sql.NullString{} machineID := sql.NullString{}
name := sql.NullString{} name := sql.NullString{}
@ -1374,6 +1386,7 @@ func prepareUsersQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilde
&isEmailVerified, &isEmailVerified,
&phone, &phone,
&isPhoneVerified, &isPhoneVerified,
&passwordChangeRequired,
&machineID, &machineID,
&name, &name,
&description, &description,
@ -1392,17 +1405,18 @@ func prepareUsersQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilde
if humanID.Valid { if humanID.Valid {
u.Human = &Human{ u.Human = &Human{
FirstName: firstName.String, FirstName: firstName.String,
LastName: lastName.String, LastName: lastName.String,
NickName: nickName.String, NickName: nickName.String,
DisplayName: displayName.String, DisplayName: displayName.String,
AvatarKey: avatarKey.String, AvatarKey: avatarKey.String,
PreferredLanguage: language.Make(preferredLanguage.String), PreferredLanguage: language.Make(preferredLanguage.String),
Gender: domain.Gender(gender.Int32), Gender: domain.Gender(gender.Int32),
Email: domain.EmailAddress(email.String), Email: domain.EmailAddress(email.String),
IsEmailVerified: isEmailVerified.Bool, IsEmailVerified: isEmailVerified.Bool,
Phone: domain.PhoneNumber(phone.String), Phone: domain.PhoneNumber(phone.String),
IsPhoneVerified: isPhoneVerified.Bool, IsPhoneVerified: isPhoneVerified.Bool,
PasswordChangeRequired: passwordChangeRequired.Bool,
} }
} else if machineID.Valid { } else if machineID.Valid {
u.Machine = &Machine{ u.Machine = &Machine{

View File

@ -39,38 +39,38 @@ var (
"method_type", "method_type",
"count", "count",
} }
prepareActiveAuthMethodTypesStmt = `SELECT projections.users10_notifications.password_set,` + prepareActiveAuthMethodTypesStmt = `SELECT projections.users11_notifications.password_set,` +
` auth_method_types.method_type,` + ` auth_method_types.method_type,` +
` user_idps_count.count` + ` user_idps_count.count` +
` FROM projections.users10` + ` FROM projections.users11` +
` LEFT JOIN projections.users10_notifications ON projections.users10.id = projections.users10_notifications.user_id AND projections.users10.instance_id = projections.users10_notifications.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 (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` + ` 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` + ` 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` + ` 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` + ` 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` ` AS OF SYSTEM TIME '-1 ms`
prepareActiveAuthMethodTypesCols = []string{ prepareActiveAuthMethodTypesCols = []string{
"password_set", "password_set",
"method_type", "method_type",
"idps_count", "idps_count",
} }
prepareAuthMethodTypesRequiredStmt = `SELECT projections.users10_notifications.password_set,` + prepareAuthMethodTypesRequiredStmt = `SELECT projections.users11_notifications.password_set,` +
` auth_method_types.method_type,` + ` auth_method_types.method_type,` +
` user_idps_count.count,` + ` user_idps_count.count,` +
` auth_methods_force_mfa.force_mfa,` + ` auth_methods_force_mfa.force_mfa,` +
` auth_methods_force_mfa.force_mfa_local_only` + ` auth_methods_force_mfa.force_mfa_local_only` +
` FROM projections.users10` + ` FROM projections.users11` +
` LEFT JOIN projections.users10_notifications ON projections.users10.id = projections.users10_notifications.user_id AND projections.users10.instance_id = projections.users10_notifications.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 (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` + ` 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` + ` 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` + ` 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` + ` 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` + ` 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 ` AS OF SYSTEM TIME '-1 ms
` `
prepareAuthMethodTypesRequiredCols = []string{ prepareAuthMethodTypesRequiredCols = []string{

View File

@ -58,20 +58,21 @@ SELECT
, h.is_email_verified , h.is_email_verified
, h.phone , h.phone
, h.is_phone_verified , h.is_phone_verified
, h.password_change_required
, m.user_id , m.user_id
, m.name , m.name
, m.description , m.description
, m.secret , m.secret
, m.access_token_type , m.access_token_type
, count(*) OVER () , count(*) OVER ()
FROM projections.users10 u FROM projections.users11 u
LEFT JOIN LEFT JOIN
projections.users10_humans h projections.users11_humans h
ON ON
u.id = h.user_id u.id = h.user_id
AND u.instance_id = h.instance_id AND u.instance_id = h.instance_id
LEFT JOIN LEFT JOIN
projections.users10_machines m projections.users11_machines m
ON ON
u.id = m.user_id u.id = m.user_id
AND u.instance_id = m.instance_id AND u.instance_id = m.instance_id

View File

@ -94,6 +94,7 @@ SELECT
, h.is_email_verified , h.is_email_verified
, h.phone , h.phone
, h.is_phone_verified , h.is_phone_verified
, h.password_change_required
, m.user_id , m.user_id
, m.name , m.name
, m.description , m.description
@ -102,17 +103,17 @@ SELECT
, count(*) OVER () , count(*) OVER ()
FROM found_users fu FROM found_users fu
JOIN JOIN
projections.users10 u projections.users11 u
ON ON
fu.id = u.id fu.id = u.id
AND fu.instance_id = u.instance_id AND fu.instance_id = u.instance_id
LEFT JOIN LEFT JOIN
projections.users10_humans h projections.users11_humans h
ON ON
fu.id = h.user_id fu.id = h.user_id
AND fu.instance_id = h.instance_id AND fu.instance_id = h.instance_id
LEFT JOIN LEFT JOIN
projections.users10_machines m projections.users11_machines m
ON ON
fu.id = m.user_id fu.id = m.user_id
AND fu.instance_id = m.instance_id AND fu.instance_id = m.instance_id

View File

@ -23,14 +23,14 @@ var (
", projections.user_grants5.roles" + ", projections.user_grants5.roles" +
", projections.user_grants5.state" + ", projections.user_grants5.state" +
", projections.user_grants5.user_id" + ", projections.user_grants5.user_id" +
", projections.users10.username" + ", projections.users11.username" +
", projections.users10.type" + ", projections.users11.type" +
", projections.users10.resource_owner" + ", projections.users11.resource_owner" +
", projections.users10_humans.first_name" + ", projections.users11_humans.first_name" +
", projections.users10_humans.last_name" + ", projections.users11_humans.last_name" +
", projections.users10_humans.email" + ", projections.users11_humans.email" +
", projections.users10_humans.display_name" + ", projections.users11_humans.display_name" +
", projections.users10_humans.avatar_key" + ", projections.users11_humans.avatar_key" +
", projections.login_names3.login_name" + ", projections.login_names3.login_name" +
", projections.user_grants5.resource_owner" + ", projections.user_grants5.resource_owner" +
", projections.orgs1.name" + ", projections.orgs1.name" +
@ -41,11 +41,11 @@ var (
", granted_orgs.name" + ", granted_orgs.name" +
", granted_orgs.primary_domain" + ", granted_orgs.primary_domain" +
" FROM projections.user_grants5" + " 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.users11 ON projections.user_grants5.user_id = projections.users11.id AND projections.user_grants5.instance_id = projections.users11.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_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.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.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" + " 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' ` + ` AS OF SYSTEM TIME '-1 ms' ` +
" WHERE projections.login_names3.is_primary = $1") " WHERE projections.login_names3.is_primary = $1")
@ -85,14 +85,14 @@ var (
", projections.user_grants5.roles" + ", projections.user_grants5.roles" +
", projections.user_grants5.state" + ", projections.user_grants5.state" +
", projections.user_grants5.user_id" + ", projections.user_grants5.user_id" +
", projections.users10.username" + ", projections.users11.username" +
", projections.users10.type" + ", projections.users11.type" +
", projections.users10.resource_owner" + ", projections.users11.resource_owner" +
", projections.users10_humans.first_name" + ", projections.users11_humans.first_name" +
", projections.users10_humans.last_name" + ", projections.users11_humans.last_name" +
", projections.users10_humans.email" + ", projections.users11_humans.email" +
", projections.users10_humans.display_name" + ", projections.users11_humans.display_name" +
", projections.users10_humans.avatar_key" + ", projections.users11_humans.avatar_key" +
", projections.login_names3.login_name" + ", projections.login_names3.login_name" +
", projections.user_grants5.resource_owner" + ", projections.user_grants5.resource_owner" +
", projections.orgs1.name" + ", projections.orgs1.name" +
@ -104,11 +104,11 @@ var (
", granted_orgs.primary_domain" + ", granted_orgs.primary_domain" +
", COUNT(*) OVER ()" + ", COUNT(*) OVER ()" +
" FROM projections.user_grants5" + " 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.users11 ON projections.user_grants5.user_id = projections.users11.id AND projections.user_grants5.instance_id = projections.users11.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_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.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.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" + " 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' ` + ` AS OF SYSTEM TIME '-1 ms' ` +
" WHERE projections.login_names3.is_primary = $1") " WHERE projections.login_names3.is_primary = $1")

View File

@ -62,14 +62,14 @@ SELECT
, n.verified_phone , n.verified_phone
, n.password_set , n.password_set
, count(*) OVER () , count(*) OVER ()
FROM projections.users10 u FROM projections.users11 u
LEFT JOIN LEFT JOIN
projections.users10_humans h projections.users11_humans h
ON ON
u.id = h.user_id u.id = h.user_id
AND u.instance_id = h.instance_id AND u.instance_id = h.instance_id
LEFT JOIN LEFT JOIN
projections.users10_notifications n projections.users11_notifications n
ON ON
u.id = n.user_id u.id = n.user_id
AND u.instance_id = n.instance_id AND u.instance_id = n.instance_id

View File

@ -99,17 +99,17 @@ SELECT
, count(*) OVER () , count(*) OVER ()
FROM found_users fu FROM found_users fu
JOIN JOIN
projections.users10 u projections.users11 u
ON ON
fu.id = u.id fu.id = u.id
AND fu.instance_id = u.instance_id AND fu.instance_id = u.instance_id
LEFT JOIN LEFT JOIN
projections.users10_humans h projections.users11_humans h
ON ON
fu.id = h.user_id fu.id = h.user_id
AND fu.instance_id = h.instance_id AND fu.instance_id = h.instance_id
LEFT JOIN LEFT JOIN
projections.users10_notifications n projections.users11_notifications n
ON ON
fu.id = n.user_id fu.id = n.user_id
AND fu.instance_id = n.instance_id AND fu.instance_id = n.instance_id

View File

@ -148,43 +148,44 @@ var (
preferredLoginNameQuery = `SELECT preferred_login_name.user_id, preferred_login_name.login_name, preferred_login_name.instance_id` + 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` + ` FROM projections.login_names3 AS preferred_login_name` +
` WHERE preferred_login_name.is_primary = $1` ` WHERE preferred_login_name.is_primary = $1`
userQuery = `SELECT projections.users10.id,` + userQuery = `SELECT projections.users11.id,` +
` projections.users10.creation_date,` + ` projections.users11.creation_date,` +
` projections.users10.change_date,` + ` projections.users11.change_date,` +
` projections.users10.resource_owner,` + ` projections.users11.resource_owner,` +
` projections.users10.sequence,` + ` projections.users11.sequence,` +
` projections.users10.state,` + ` projections.users11.state,` +
` projections.users10.type,` + ` projections.users11.type,` +
` projections.users10.username,` + ` projections.users11.username,` +
` login_names.loginnames,` + ` login_names.loginnames,` +
` preferred_login_name.login_name,` + ` preferred_login_name.login_name,` +
` projections.users10_humans.user_id,` + ` projections.users11_humans.user_id,` +
` projections.users10_humans.first_name,` + ` projections.users11_humans.first_name,` +
` projections.users10_humans.last_name,` + ` projections.users11_humans.last_name,` +
` projections.users10_humans.nick_name,` + ` projections.users11_humans.nick_name,` +
` projections.users10_humans.display_name,` + ` projections.users11_humans.display_name,` +
` projections.users10_humans.preferred_language,` + ` projections.users11_humans.preferred_language,` +
` projections.users10_humans.gender,` + ` projections.users11_humans.gender,` +
` projections.users10_humans.avatar_key,` + ` projections.users11_humans.avatar_key,` +
` projections.users10_humans.email,` + ` projections.users11_humans.email,` +
` projections.users10_humans.is_email_verified,` + ` projections.users11_humans.is_email_verified,` +
` projections.users10_humans.phone,` + ` projections.users11_humans.phone,` +
` projections.users10_humans.is_phone_verified,` + ` projections.users11_humans.is_phone_verified,` +
` projections.users10_machines.user_id,` + ` projections.users11_humans.password_change_required,` +
` projections.users10_machines.name,` + ` projections.users11_machines.user_id,` +
` projections.users10_machines.description,` + ` projections.users11_machines.name,` +
` projections.users10_machines.secret,` + ` projections.users11_machines.description,` +
` projections.users10_machines.access_token_type,` + ` projections.users11_machines.secret,` +
` projections.users11_machines.access_token_type,` +
` COUNT(*) OVER ()` + ` COUNT(*) OVER ()` +
` FROM projections.users10` + ` FROM projections.users11` +
` 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.users11_humans ON projections.users11.id = projections.users11_humans.user_id AND projections.users11.instance_id = projections.users11_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` + ` 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` + ` LEFT JOIN` +
` (` + loginNamesQuery + `) AS login_names` + ` (` + 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` + ` LEFT JOIN` +
` (` + preferredLoginNameQuery + `) AS preferred_login_name` + ` (` + 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'` ` AS OF SYSTEM TIME '-1 ms'`
userCols = []string{ userCols = []string{
"id", "id",
@ -210,6 +211,7 @@ var (
"is_email_verified", "is_email_verified",
"phone", "phone",
"is_phone_verified", "is_phone_verified",
"password_change_required",
// machine // machine
"user_id", "user_id",
"name", "name",
@ -218,21 +220,21 @@ var (
"access_token_type", "access_token_type",
"count", "count",
} }
profileQuery = `SELECT projections.users10.id,` + profileQuery = `SELECT projections.users11.id,` +
` projections.users10.creation_date,` + ` projections.users11.creation_date,` +
` projections.users10.change_date,` + ` projections.users11.change_date,` +
` projections.users10.resource_owner,` + ` projections.users11.resource_owner,` +
` projections.users10.sequence,` + ` projections.users11.sequence,` +
` projections.users10_humans.user_id,` + ` projections.users11_humans.user_id,` +
` projections.users10_humans.first_name,` + ` projections.users11_humans.first_name,` +
` projections.users10_humans.last_name,` + ` projections.users11_humans.last_name,` +
` projections.users10_humans.nick_name,` + ` projections.users11_humans.nick_name,` +
` projections.users10_humans.display_name,` + ` projections.users11_humans.display_name,` +
` projections.users10_humans.preferred_language,` + ` projections.users11_humans.preferred_language,` +
` projections.users10_humans.gender,` + ` projections.users11_humans.gender,` +
` projections.users10_humans.avatar_key` + ` projections.users11_humans.avatar_key` +
` FROM projections.users10` + ` FROM projections.users11` +
` 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.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'` ` AS OF SYSTEM TIME '-1 ms'`
profileCols = []string{ profileCols = []string{
"id", "id",
@ -249,16 +251,16 @@ var (
"gender", "gender",
"avatar_key", "avatar_key",
} }
emailQuery = `SELECT projections.users10.id,` + emailQuery = `SELECT projections.users11.id,` +
` projections.users10.creation_date,` + ` projections.users11.creation_date,` +
` projections.users10.change_date,` + ` projections.users11.change_date,` +
` projections.users10.resource_owner,` + ` projections.users11.resource_owner,` +
` projections.users10.sequence,` + ` projections.users11.sequence,` +
` projections.users10_humans.user_id,` + ` projections.users11_humans.user_id,` +
` projections.users10_humans.email,` + ` projections.users11_humans.email,` +
` projections.users10_humans.is_email_verified` + ` projections.users11_humans.is_email_verified` +
` FROM projections.users10` + ` FROM projections.users11` +
` 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.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'` ` AS OF SYSTEM TIME '-1 ms'`
emailCols = []string{ emailCols = []string{
"id", "id",
@ -270,16 +272,16 @@ var (
"email", "email",
"is_email_verified", "is_email_verified",
} }
phoneQuery = `SELECT projections.users10.id,` + phoneQuery = `SELECT projections.users11.id,` +
` projections.users10.creation_date,` + ` projections.users11.creation_date,` +
` projections.users10.change_date,` + ` projections.users11.change_date,` +
` projections.users10.resource_owner,` + ` projections.users11.resource_owner,` +
` projections.users10.sequence,` + ` projections.users11.sequence,` +
` projections.users10_humans.user_id,` + ` projections.users11_humans.user_id,` +
` projections.users10_humans.phone,` + ` projections.users11_humans.phone,` +
` projections.users10_humans.is_phone_verified` + ` projections.users11_humans.is_phone_verified` +
` FROM projections.users10` + ` FROM projections.users11` +
` 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.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'` ` AS OF SYSTEM TIME '-1 ms'`
phoneCols = []string{ phoneCols = []string{
"id", "id",
@ -291,14 +293,14 @@ var (
"phone", "phone",
"is_phone_verified", "is_phone_verified",
} }
userUniqueQuery = `SELECT projections.users10.id,` + userUniqueQuery = `SELECT projections.users11.id,` +
` projections.users10.state,` + ` projections.users11.state,` +
` projections.users10.username,` + ` projections.users11.username,` +
` projections.users10_humans.user_id,` + ` projections.users11_humans.user_id,` +
` projections.users10_humans.email,` + ` projections.users11_humans.email,` +
` projections.users10_humans.is_email_verified` + ` projections.users11_humans.is_email_verified` +
` FROM projections.users10` + ` FROM projections.users11` +
` 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.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'` ` AS OF SYSTEM TIME '-1 ms'`
userUniqueCols = []string{ userUniqueCols = []string{
"id", "id",
@ -308,40 +310,40 @@ var (
"email", "email",
"is_email_verified", "is_email_verified",
} }
notifyUserQuery = `SELECT projections.users10.id,` + notifyUserQuery = `SELECT projections.users11.id,` +
` projections.users10.creation_date,` + ` projections.users11.creation_date,` +
` projections.users10.change_date,` + ` projections.users11.change_date,` +
` projections.users10.resource_owner,` + ` projections.users11.resource_owner,` +
` projections.users10.sequence,` + ` projections.users11.sequence,` +
` projections.users10.state,` + ` projections.users11.state,` +
` projections.users10.type,` + ` projections.users11.type,` +
` projections.users10.username,` + ` projections.users11.username,` +
` login_names.loginnames,` + ` login_names.loginnames,` +
` preferred_login_name.login_name,` + ` preferred_login_name.login_name,` +
` projections.users10_humans.user_id,` + ` projections.users11_humans.user_id,` +
` projections.users10_humans.first_name,` + ` projections.users11_humans.first_name,` +
` projections.users10_humans.last_name,` + ` projections.users11_humans.last_name,` +
` projections.users10_humans.nick_name,` + ` projections.users11_humans.nick_name,` +
` projections.users10_humans.display_name,` + ` projections.users11_humans.display_name,` +
` projections.users10_humans.preferred_language,` + ` projections.users11_humans.preferred_language,` +
` projections.users10_humans.gender,` + ` projections.users11_humans.gender,` +
` projections.users10_humans.avatar_key,` + ` projections.users11_humans.avatar_key,` +
` projections.users10_notifications.user_id,` + ` projections.users11_notifications.user_id,` +
` projections.users10_notifications.last_email,` + ` projections.users11_notifications.last_email,` +
` projections.users10_notifications.verified_email,` + ` projections.users11_notifications.verified_email,` +
` projections.users10_notifications.last_phone,` + ` projections.users11_notifications.last_phone,` +
` projections.users10_notifications.verified_phone,` + ` projections.users11_notifications.verified_phone,` +
` projections.users10_notifications.password_set,` + ` projections.users11_notifications.password_set,` +
` COUNT(*) OVER ()` + ` COUNT(*) OVER ()` +
` FROM projections.users10` + ` FROM projections.users11` +
` 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.users11_humans ON projections.users11.id = projections.users11_humans.user_id AND projections.users11.instance_id = projections.users11_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` + ` 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` + ` LEFT JOIN` +
` (` + loginNamesQuery + `) AS login_names` + ` (` + 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` + ` LEFT JOIN` +
` (` + preferredLoginNameQuery + `) AS preferred_login_name` + ` (` + 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'` ` AS OF SYSTEM TIME '-1 ms'`
notifyUserCols = []string{ notifyUserCols = []string{
"id", "id",
@ -372,43 +374,44 @@ var (
"password_set", "password_set",
"count", "count",
} }
usersQuery = `SELECT projections.users10.id,` + usersQuery = `SELECT projections.users11.id,` +
` projections.users10.creation_date,` + ` projections.users11.creation_date,` +
` projections.users10.change_date,` + ` projections.users11.change_date,` +
` projections.users10.resource_owner,` + ` projections.users11.resource_owner,` +
` projections.users10.sequence,` + ` projections.users11.sequence,` +
` projections.users10.state,` + ` projections.users11.state,` +
` projections.users10.type,` + ` projections.users11.type,` +
` projections.users10.username,` + ` projections.users11.username,` +
` login_names.loginnames,` + ` login_names.loginnames,` +
` preferred_login_name.login_name,` + ` preferred_login_name.login_name,` +
` projections.users10_humans.user_id,` + ` projections.users11_humans.user_id,` +
` projections.users10_humans.first_name,` + ` projections.users11_humans.first_name,` +
` projections.users10_humans.last_name,` + ` projections.users11_humans.last_name,` +
` projections.users10_humans.nick_name,` + ` projections.users11_humans.nick_name,` +
` projections.users10_humans.display_name,` + ` projections.users11_humans.display_name,` +
` projections.users10_humans.preferred_language,` + ` projections.users11_humans.preferred_language,` +
` projections.users10_humans.gender,` + ` projections.users11_humans.gender,` +
` projections.users10_humans.avatar_key,` + ` projections.users11_humans.avatar_key,` +
` projections.users10_humans.email,` + ` projections.users11_humans.email,` +
` projections.users10_humans.is_email_verified,` + ` projections.users11_humans.is_email_verified,` +
` projections.users10_humans.phone,` + ` projections.users11_humans.phone,` +
` projections.users10_humans.is_phone_verified,` + ` projections.users11_humans.is_phone_verified,` +
` projections.users10_machines.user_id,` + ` projections.users11_humans.password_change_required,` +
` projections.users10_machines.name,` + ` projections.users11_machines.user_id,` +
` projections.users10_machines.description,` + ` projections.users11_machines.name,` +
` projections.users10_machines.secret,` + ` projections.users11_machines.description,` +
` projections.users10_machines.access_token_type,` + ` projections.users11_machines.secret,` +
` projections.users11_machines.access_token_type,` +
` COUNT(*) OVER ()` + ` COUNT(*) OVER ()` +
` FROM projections.users10` + ` FROM projections.users11` +
` 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.users11_humans ON projections.users11.id = projections.users11_humans.user_id AND projections.users11.instance_id = projections.users11_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` + ` 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` + ` LEFT JOIN` +
` (` + loginNamesQuery + `) AS login_names` + ` (` + 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` + ` LEFT JOIN` +
` (` + preferredLoginNameQuery + `) AS preferred_login_name` + ` (` + 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'` ` AS OF SYSTEM TIME '-1 ms'`
usersCols = []string{ usersCols = []string{
"id", "id",
@ -434,6 +437,7 @@ var (
"is_email_verified", "is_email_verified",
"phone", "phone",
"is_phone_verified", "is_phone_verified",
"password_change_required",
// machine // machine
"user_id", "user_id",
"name", "name",
@ -504,6 +508,7 @@ func Test_UserPrepares(t *testing.T) {
true, true,
"phone", "phone",
true, true,
true,
// machine // machine
nil, nil,
nil, nil,
@ -526,17 +531,18 @@ func Test_UserPrepares(t *testing.T) {
LoginNames: database.TextArray[string]{"login_name1", "login_name2"}, LoginNames: database.TextArray[string]{"login_name1", "login_name2"},
PreferredLoginName: "login_name1", PreferredLoginName: "login_name1",
Human: &Human{ Human: &Human{
FirstName: "first_name", FirstName: "first_name",
LastName: "last_name", LastName: "last_name",
NickName: "nick_name", NickName: "nick_name",
DisplayName: "display_name", DisplayName: "display_name",
AvatarKey: "avatar_key", AvatarKey: "avatar_key",
PreferredLanguage: language.German, PreferredLanguage: language.German,
Gender: domain.GenderUnspecified, Gender: domain.GenderUnspecified,
Email: "email", Email: "email",
IsEmailVerified: true, IsEmailVerified: true,
Phone: "phone", Phone: "phone",
IsPhoneVerified: true, IsPhoneVerified: true,
PasswordChangeRequired: true,
}, },
}, },
}, },
@ -571,6 +577,7 @@ func Test_UserPrepares(t *testing.T) {
nil, nil,
nil, nil,
nil, nil,
nil,
// machine // machine
"id", "id",
"name", "name",
@ -631,6 +638,7 @@ func Test_UserPrepares(t *testing.T) {
nil, nil,
nil, nil,
nil, nil,
nil,
// machine // machine
"id", "id",
"name", "name",
@ -1222,6 +1230,7 @@ func Test_UserPrepares(t *testing.T) {
true, true,
"phone", "phone",
true, true,
true,
// machine // machine
nil, nil,
nil, nil,
@ -1249,17 +1258,18 @@ func Test_UserPrepares(t *testing.T) {
LoginNames: database.TextArray[string]{"login_name1", "login_name2"}, LoginNames: database.TextArray[string]{"login_name1", "login_name2"},
PreferredLoginName: "login_name1", PreferredLoginName: "login_name1",
Human: &Human{ Human: &Human{
FirstName: "first_name", FirstName: "first_name",
LastName: "last_name", LastName: "last_name",
NickName: "nick_name", NickName: "nick_name",
DisplayName: "display_name", DisplayName: "display_name",
AvatarKey: "avatar_key", AvatarKey: "avatar_key",
PreferredLanguage: language.German, PreferredLanguage: language.German,
Gender: domain.GenderUnspecified, Gender: domain.GenderUnspecified,
Email: "email", Email: "email",
IsEmailVerified: true, IsEmailVerified: true,
Phone: "phone", Phone: "phone",
IsPhoneVerified: true, IsPhoneVerified: true,
PasswordChangeRequired: true,
}, },
}, },
}, },
@ -1297,6 +1307,7 @@ func Test_UserPrepares(t *testing.T) {
true, true,
"phone", "phone",
true, true,
true,
// machine // machine
nil, nil,
nil, nil,
@ -1328,6 +1339,7 @@ func Test_UserPrepares(t *testing.T) {
nil, nil,
nil, nil,
nil, nil,
nil,
// machine // machine
"id", "id",
"name", "name",
@ -1355,17 +1367,18 @@ func Test_UserPrepares(t *testing.T) {
LoginNames: database.TextArray[string]{"login_name1", "login_name2"}, LoginNames: database.TextArray[string]{"login_name1", "login_name2"},
PreferredLoginName: "login_name1", PreferredLoginName: "login_name1",
Human: &Human{ Human: &Human{
FirstName: "first_name", FirstName: "first_name",
LastName: "last_name", LastName: "last_name",
NickName: "nick_name", NickName: "nick_name",
DisplayName: "display_name", DisplayName: "display_name",
AvatarKey: "avatar_key", AvatarKey: "avatar_key",
PreferredLanguage: language.German, PreferredLanguage: language.German,
Gender: domain.GenderUnspecified, Gender: domain.GenderUnspecified,
Email: "email", Email: "email",
IsEmailVerified: true, IsEmailVerified: true,
Phone: "phone", Phone: "phone",
IsPhoneVerified: true, IsPhoneVerified: true,
PasswordChangeRequired: true,
}, },
}, },
{ {

View File

@ -19,8 +19,8 @@ SELECT s.creation_date,
s.sequence, s.sequence,
s.instance_id s.instance_id
FROM auth.user_sessions s 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.users11 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_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 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) WHERE (s.user_agent_id = $1)
AND (s.user_id = $2) AND (s.user_id = $2)

View File

@ -19,8 +19,8 @@ SELECT s.creation_date,
s.sequence, s.sequence,
s.instance_id s.instance_id
FROM auth.user_sessions s 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.users11 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_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 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) WHERE (s.user_agent_id = $1)
AND (s.instance_id = $2) AND (s.instance_id = $2)

View File

@ -134,34 +134,44 @@ message SetMetadataEntry {
} }
message HumanUser { message HumanUser {
// Unique identifier of the user.
string user_id = 1 [ string user_id = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\""; example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\"";
} }
]; ];
// State of the user, for example active, inactive, locked, deleted, initial.
UserState state = 2 [ UserState state = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "current state of the user"; description: "current state of the user";
} }
]; ];
// Username of the user, which can be globally unique or unique on organization level.
string username = 3 [ string username = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"minnie-mouse\""; example: "\"minnie-mouse\"";
} }
]; ];
// Possible usable login names for the user.
repeated string login_names = 4 [ repeated string login_names = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[\"gigi@zitadel.com\", \"gigi@zitadel.zitadel.ch\"]"; example: "[\"gigi@zitadel.com\", \"gigi@zitadel.zitadel.ch\"]";
} }
]; ];
// Preferred login name of the user.
string preferred_login_name = 5 [ string preferred_login_name = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"gigi@zitadel.com\""; example: "\"gigi@zitadel.com\"";
} }
]; ];
// Profile information of the user.
HumanProfile profile = 6; HumanProfile profile = 6;
// Email of the user, if defined.
HumanEmail email = 7; HumanEmail email = 7;
// Phone of the user, if defined.
HumanPhone phone = 8; HumanPhone phone = 8;
// User is required to change the used password on the next login.
bool password_change_required = 9;
} }
message User { message User {