feat(repository): implement user repository (#10967)

## Summary

This PR introduces the relational user repository for backend v3,
including schema, repository APIs, reducers/projections, and tests for
both human and machine users.

## What changed

* Added user-focused relational migrations (users, verifications,
metadata, PATs, machine keys, passkeys, identity provider links) and
related FK wiring.
* Implemented/expanded repository domain contracts and storage
implementations for human and machine user flows.
* Added support for machine secret handling and aligned access token
type modeling.
* Extended user domain models (verifications, password/email/phone/TOTP
state, passkeys, metadata, invite handling, identity provider links).
* Updated projection/reduction coverage and integration tests for key
user lifecycle events.
* Regenerated and updated mocks/enums plus supporting database
change/column utilities.

## Notes for reviewers

* This PR is large because it establishes the foundational relational
user storage layer and related test scaffolding. Sorry for that.

## Closes

Closes #10218
Closes #10224
Closes #10225
Closes #10209
Closes #10802

---------

Co-authored-by: Iraq Jaber <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Marco A. <[email protected]>
Co-authored-by: Tim Möhlmann <[email protected]>
This commit is contained in:
Silvan
2026-02-23 16:03:47 +01:00
committed by GitHub
co-authored by Iraq Jaber Copilot Marco A. Tim Möhlmann
parent 40c7b38ca1
commit 5df8a97f9d
73 changed files with 15914 additions and 1661 deletions
+1
View File
@@ -1,5 +1,6 @@
--- ---
applyTo: '**' applyTo: '**'
excludeAgent: ["coding-agent", "code-review"]
--- ---
// This file is automatically generated by Nx Console // This file is automatically generated by Nx Console
@@ -0,0 +1,82 @@
// Code generated by "enumer -type AccessTokenType -transform lower -trimprefix AccessTokenType"; DO NOT EDIT.
package domain
import (
"fmt"
"strings"
)
const _AccessTokenTypeName = "unspecifiedbearerjwt"
var _AccessTokenTypeIndex = [...]uint8{0, 11, 17, 20}
const _AccessTokenTypeLowerName = "unspecifiedbearerjwt"
func (i AccessTokenType) String() string {
if i >= AccessTokenType(len(_AccessTokenTypeIndex)-1) {
return fmt.Sprintf("AccessTokenType(%d)", i)
}
return _AccessTokenTypeName[_AccessTokenTypeIndex[i]:_AccessTokenTypeIndex[i+1]]
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _AccessTokenTypeNoOp() {
var x [1]struct{}
_ = x[AccessTokenTypeUnspecified-(0)]
_ = x[AccessTokenTypeBearer-(1)]
_ = x[AccessTokenTypeJWT-(2)]
}
var _AccessTokenTypeValues = []AccessTokenType{AccessTokenTypeUnspecified, AccessTokenTypeBearer, AccessTokenTypeJWT}
var _AccessTokenTypeNameToValueMap = map[string]AccessTokenType{
_AccessTokenTypeName[0:11]: AccessTokenTypeUnspecified,
_AccessTokenTypeLowerName[0:11]: AccessTokenTypeUnspecified,
_AccessTokenTypeName[11:17]: AccessTokenTypeBearer,
_AccessTokenTypeLowerName[11:17]: AccessTokenTypeBearer,
_AccessTokenTypeName[17:20]: AccessTokenTypeJWT,
_AccessTokenTypeLowerName[17:20]: AccessTokenTypeJWT,
}
var _AccessTokenTypeNames = []string{
_AccessTokenTypeName[0:11],
_AccessTokenTypeName[11:17],
_AccessTokenTypeName[17:20],
}
// AccessTokenTypeString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func AccessTokenTypeString(s string) (AccessTokenType, error) {
if val, ok := _AccessTokenTypeNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _AccessTokenTypeNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to AccessTokenType values", s)
}
// AccessTokenTypeValues returns all values of the enum
func AccessTokenTypeValues() []AccessTokenType {
return _AccessTokenTypeValues
}
// AccessTokenTypeStrings returns a slice of all String values of the enum
func AccessTokenTypeStrings() []string {
strs := make([]string, len(_AccessTokenTypeNames))
copy(strs, _AccessTokenTypeNames)
return strs
}
// IsAAccessTokenType returns "true" if the value is listed in the enum definition. "false" otherwise
func (i AccessTokenType) IsAAccessTokenType() bool {
for _, v := range _AccessTokenTypeValues {
if i == v {
return true
}
}
return false
}
-71
View File
@@ -1,71 +0,0 @@
package domain
import (
"time"
"github.com/zitadel/zitadel/internal/crypto"
)
type Check struct {
Code *crypto.CryptoValue `db:"code"`
ExpiresAt *time.Time `db:"expires_at"`
FailedAttempts uint8 `db:"failed_attempts"`
}
type CheckType interface {
isCheckType()
}
type PasswordCheckType interface {
isPasswordCheckType()
}
// CheckTypeInit initializes a new check.
type CheckTypeInit struct {
// CreatedAt is the time when the check was created.
// If zero, the current time will be used.
CreatedAt time.Time
// Expiry is the duration after which the check expires.
Expiry *time.Duration
// Code to be used for the check.
Code *crypto.CryptoValue
}
// isCheckType implements [CheckType].
func (v *CheckTypeInit) isCheckType() {}
var _ CheckType = (*CheckTypeInit)(nil)
// CheckTypeFailed indicates that the check failed.
// It is used to increment the failed attempts counter.
type CheckTypeFailed struct {
FailedAt time.Time
}
// isCheckType implements [CheckType].
func (v *CheckTypeFailed) isCheckType() {}
// isPasswordCheckType implements [PasswordCheckType].
func (v *CheckTypeFailed) isPasswordCheckType() {}
var (
_ CheckType = (*CheckTypeFailed)(nil)
_ PasswordCheckType = (*CheckTypeFailed)(nil)
)
// CheckTypeSucceeded indicates that the check succeeded.
// It is used to reset the failed attempts counter.
type CheckTypeSucceeded struct {
SucceededAt time.Time
}
// isCheckType implements [CheckType].
func (v *CheckTypeSucceeded) isCheckType() {}
// isPasswordCheckType implements [PasswordCheckType].
func (v *CheckTypeSucceeded) isPasswordCheckType() {}
var (
_ CheckType = (*CheckTypeSucceeded)(nil)
_ PasswordCheckType = (*CheckTypeSucceeded)(nil)
)
+11 -15
View File
@@ -7,11 +7,11 @@ import (
"strings" "strings"
) )
const _MachineKeyTypeName = "unspecifiedjsonnone" const _MachineKeyTypeName = "nonejson"
var _MachineKeyTypeIndex = [...]uint8{0, 11, 15, 19} var _MachineKeyTypeIndex = [...]uint8{0, 4, 8}
const _MachineKeyTypeLowerName = "unspecifiedjsonnone" const _MachineKeyTypeLowerName = "nonejson"
func (i MachineKeyType) String() string { func (i MachineKeyType) String() string {
if i >= MachineKeyType(len(_MachineKeyTypeIndex)-1) { if i >= MachineKeyType(len(_MachineKeyTypeIndex)-1) {
@@ -24,26 +24,22 @@ func (i MachineKeyType) String() string {
// Re-run the stringer command to generate them again. // Re-run the stringer command to generate them again.
func _MachineKeyTypeNoOp() { func _MachineKeyTypeNoOp() {
var x [1]struct{} var x [1]struct{}
_ = x[MachineKeyTypeUnspecified-(0)] _ = x[MachineKeyTypeNone-(0)]
_ = x[MachineKeyTypeJSON-(1)] _ = x[MachineKeyTypeJSON-(1)]
_ = x[MachineKeyTypeNone-(2)]
} }
var _MachineKeyTypeValues = []MachineKeyType{MachineKeyTypeUnspecified, MachineKeyTypeJSON, MachineKeyTypeNone} var _MachineKeyTypeValues = []MachineKeyType{MachineKeyTypeNone, MachineKeyTypeJSON}
var _MachineKeyTypeNameToValueMap = map[string]MachineKeyType{ var _MachineKeyTypeNameToValueMap = map[string]MachineKeyType{
_MachineKeyTypeName[0:11]: MachineKeyTypeUnspecified, _MachineKeyTypeName[0:4]: MachineKeyTypeNone,
_MachineKeyTypeLowerName[0:11]: MachineKeyTypeUnspecified, _MachineKeyTypeLowerName[0:4]: MachineKeyTypeNone,
_MachineKeyTypeName[11:15]: MachineKeyTypeJSON, _MachineKeyTypeName[4:8]: MachineKeyTypeJSON,
_MachineKeyTypeLowerName[11:15]: MachineKeyTypeJSON, _MachineKeyTypeLowerName[4:8]: MachineKeyTypeJSON,
_MachineKeyTypeName[15:19]: MachineKeyTypeNone,
_MachineKeyTypeLowerName[15:19]: MachineKeyTypeNone,
} }
var _MachineKeyTypeNames = []string{ var _MachineKeyTypeNames = []string{
_MachineKeyTypeName[0:11], _MachineKeyTypeName[0:4],
_MachineKeyTypeName[11:15], _MachineKeyTypeName[4:8],
_MachineKeyTypeName[15:19],
} }
// MachineKeyTypeString retrieves an enum value from the enum constants string name. // MachineKeyTypeString retrieves an enum value from the enum constants string name.
@@ -158,6 +158,44 @@ func (c *MockAuthorizationRepositoryDeleteCall) DoAndReturn(f func(context.Conte
return c return c
} }
// ExistsRole mocks base method.
func (m *MockAuthorizationRepository) ExistsRole(cond database.Condition) database.Condition {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ExistsRole", cond)
ret0, _ := ret[0].(database.Condition)
return ret0
}
// ExistsRole indicates an expected call of ExistsRole.
func (mr *MockAuthorizationRepositoryMockRecorder) ExistsRole(cond any) *MockAuthorizationRepositoryExistsRoleCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistsRole", reflect.TypeOf((*MockAuthorizationRepository)(nil).ExistsRole), cond)
return &MockAuthorizationRepositoryExistsRoleCall{Call: call}
}
// MockAuthorizationRepositoryExistsRoleCall wrap *gomock.Call
type MockAuthorizationRepositoryExistsRoleCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockAuthorizationRepositoryExistsRoleCall) Return(arg0 database.Condition) *MockAuthorizationRepositoryExistsRoleCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockAuthorizationRepositoryExistsRoleCall) Do(f func(database.Condition) database.Condition) *MockAuthorizationRepositoryExistsRoleCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockAuthorizationRepositoryExistsRoleCall) DoAndReturn(f func(database.Condition) database.Condition) *MockAuthorizationRepositoryExistsRoleCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// Get mocks base method. // Get mocks base method.
func (m *MockAuthorizationRepository) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.Authorization, error) { func (m *MockAuthorizationRepository) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.Authorization, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
File diff suppressed because it is too large Load Diff
@@ -354,17 +354,17 @@ func (c *MockInstanceDomainRepositoryIsGeneratedColumnCall) DoAndReturn(f func()
} }
// IsGeneratedCondition mocks base method. // IsGeneratedCondition mocks base method.
func (m *MockInstanceDomainRepository) IsGeneratedCondition(arg0 bool) database.Condition { func (m *MockInstanceDomainRepository) IsGeneratedCondition(isGenerated bool) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IsGeneratedCondition", arg0) ret := m.ctrl.Call(m, "IsGeneratedCondition", isGenerated)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// IsGeneratedCondition indicates an expected call of IsGeneratedCondition. // IsGeneratedCondition indicates an expected call of IsGeneratedCondition.
func (mr *MockInstanceDomainRepositoryMockRecorder) IsGeneratedCondition(arg0 any) *MockInstanceDomainRepositoryIsGeneratedConditionCall { func (mr *MockInstanceDomainRepositoryMockRecorder) IsGeneratedCondition(isGenerated any) *MockInstanceDomainRepositoryIsGeneratedConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsGeneratedCondition", reflect.TypeOf((*MockInstanceDomainRepository)(nil).IsGeneratedCondition), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsGeneratedCondition", reflect.TypeOf((*MockInstanceDomainRepository)(nil).IsGeneratedCondition), isGenerated)
return &MockInstanceDomainRepositoryIsGeneratedConditionCall{Call: call} return &MockInstanceDomainRepositoryIsGeneratedConditionCall{Call: call}
} }
+142 -66
View File
@@ -237,6 +237,44 @@ func (c *MockMachineUserRepositoryExistsMetadataCall) DoAndReturn(f func(databas
return c return c
} }
// IDColumn mocks base method.
func (m *MockMachineUserRepository) IDColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IDColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// IDColumn indicates an expected call of IDColumn.
func (mr *MockMachineUserRepositoryMockRecorder) IDColumn() *MockMachineUserRepositoryIDColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDColumn", reflect.TypeOf((*MockMachineUserRepository)(nil).IDColumn))
return &MockMachineUserRepositoryIDColumnCall{Call: call}
}
// MockMachineUserRepositoryIDColumnCall wrap *gomock.Call
type MockMachineUserRepositoryIDColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockMachineUserRepositoryIDColumnCall) Return(arg0 database.Column) *MockMachineUserRepositoryIDColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockMachineUserRepositoryIDColumnCall) Do(f func() database.Column) *MockMachineUserRepositoryIDColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockMachineUserRepositoryIDColumnCall) DoAndReturn(f func() database.Column) *MockMachineUserRepositoryIDColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// IDCondition mocks base method. // IDCondition mocks base method.
func (m *MockMachineUserRepository) IDCondition(userID string) database.Condition { func (m *MockMachineUserRepository) IDCondition(userID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@@ -275,6 +313,44 @@ func (c *MockMachineUserRepositoryIDConditionCall) DoAndReturn(f func(string) da
return c return c
} }
// InstanceIDColumn mocks base method.
func (m *MockMachineUserRepository) InstanceIDColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InstanceIDColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// InstanceIDColumn indicates an expected call of InstanceIDColumn.
func (mr *MockMachineUserRepositoryMockRecorder) InstanceIDColumn() *MockMachineUserRepositoryInstanceIDColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDColumn", reflect.TypeOf((*MockMachineUserRepository)(nil).InstanceIDColumn))
return &MockMachineUserRepositoryInstanceIDColumnCall{Call: call}
}
// MockMachineUserRepositoryInstanceIDColumnCall wrap *gomock.Call
type MockMachineUserRepositoryInstanceIDColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockMachineUserRepositoryInstanceIDColumnCall) Return(arg0 database.Column) *MockMachineUserRepositoryInstanceIDColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockMachineUserRepositoryInstanceIDColumnCall) Do(f func() database.Column) *MockMachineUserRepositoryInstanceIDColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockMachineUserRepositoryInstanceIDColumnCall) DoAndReturn(f func() database.Column) *MockMachineUserRepositoryInstanceIDColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// InstanceIDCondition mocks base method. // InstanceIDCondition mocks base method.
func (m *MockMachineUserRepository) InstanceIDCondition(instanceID string) database.Condition { func (m *MockMachineUserRepository) InstanceIDCondition(instanceID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@@ -351,116 +427,78 @@ func (c *MockMachineUserRepositoryLoginNameConditionCall) DoAndReturn(f func(dat
return c return c
} }
// MetadataKeyCondition mocks base method. // MetadataConditions mocks base method.
func (m *MockMachineUserRepository) MetadataKeyCondition(key string) database.Condition { func (m *MockMachineUserRepository) MetadataConditions() domain.UserMetadataConditions {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "MetadataKeyCondition", key) ret := m.ctrl.Call(m, "MetadataConditions")
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(domain.UserMetadataConditions)
return ret0 return ret0
} }
// MetadataKeyCondition indicates an expected call of MetadataKeyCondition. // MetadataConditions indicates an expected call of MetadataConditions.
func (mr *MockMachineUserRepositoryMockRecorder) MetadataKeyCondition(key any) *MockMachineUserRepositoryMetadataKeyConditionCall { func (mr *MockMachineUserRepositoryMockRecorder) MetadataConditions() *MockMachineUserRepositoryMetadataConditionsCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MetadataKeyCondition", reflect.TypeOf((*MockMachineUserRepository)(nil).MetadataKeyCondition), key) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MetadataConditions", reflect.TypeOf((*MockMachineUserRepository)(nil).MetadataConditions))
return &MockMachineUserRepositoryMetadataKeyConditionCall{Call: call} return &MockMachineUserRepositoryMetadataConditionsCall{Call: call}
} }
// MockMachineUserRepositoryMetadataKeyConditionCall wrap *gomock.Call // MockMachineUserRepositoryMetadataConditionsCall wrap *gomock.Call
type MockMachineUserRepositoryMetadataKeyConditionCall struct { type MockMachineUserRepositoryMetadataConditionsCall struct {
*gomock.Call *gomock.Call
} }
// Return rewrite *gomock.Call.Return // Return rewrite *gomock.Call.Return
func (c *MockMachineUserRepositoryMetadataKeyConditionCall) Return(arg0 database.Condition) *MockMachineUserRepositoryMetadataKeyConditionCall { func (c *MockMachineUserRepositoryMetadataConditionsCall) Return(arg0 domain.UserMetadataConditions) *MockMachineUserRepositoryMetadataConditionsCall {
c.Call = c.Call.Return(arg0) c.Call = c.Call.Return(arg0)
return c return c
} }
// Do rewrite *gomock.Call.Do // Do rewrite *gomock.Call.Do
func (c *MockMachineUserRepositoryMetadataKeyConditionCall) Do(f func(string) database.Condition) *MockMachineUserRepositoryMetadataKeyConditionCall { func (c *MockMachineUserRepositoryMetadataConditionsCall) Do(f func() domain.UserMetadataConditions) *MockMachineUserRepositoryMetadataConditionsCall {
c.Call = c.Call.Do(f) c.Call = c.Call.Do(f)
return c return c
} }
// DoAndReturn rewrite *gomock.Call.DoAndReturn // DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockMachineUserRepositoryMetadataKeyConditionCall) DoAndReturn(f func(string) database.Condition) *MockMachineUserRepositoryMetadataKeyConditionCall { func (c *MockMachineUserRepositoryMetadataConditionsCall) DoAndReturn(f func() domain.UserMetadataConditions) *MockMachineUserRepositoryMetadataConditionsCall {
c.Call = c.Call.DoAndReturn(f) c.Call = c.Call.DoAndReturn(f)
return c return c
} }
// MetadataValueCondition mocks base method. // OrganizationIDCondition mocks base method.
func (m *MockMachineUserRepository) MetadataValueCondition(op database.BytesOperation, value []byte) database.Condition { func (m *MockMachineUserRepository) OrganizationIDCondition(orgID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "MetadataValueCondition", op, value) ret := m.ctrl.Call(m, "OrganizationIDCondition", orgID)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// MetadataValueCondition indicates an expected call of MetadataValueCondition. // OrganizationIDCondition indicates an expected call of OrganizationIDCondition.
func (mr *MockMachineUserRepositoryMockRecorder) MetadataValueCondition(op, value any) *MockMachineUserRepositoryMetadataValueConditionCall { func (mr *MockMachineUserRepositoryMockRecorder) OrganizationIDCondition(orgID any) *MockMachineUserRepositoryOrganizationIDConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MetadataValueCondition", reflect.TypeOf((*MockMachineUserRepository)(nil).MetadataValueCondition), op, value) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OrganizationIDCondition", reflect.TypeOf((*MockMachineUserRepository)(nil).OrganizationIDCondition), orgID)
return &MockMachineUserRepositoryMetadataValueConditionCall{Call: call} return &MockMachineUserRepositoryOrganizationIDConditionCall{Call: call}
} }
// MockMachineUserRepositoryMetadataValueConditionCall wrap *gomock.Call // MockMachineUserRepositoryOrganizationIDConditionCall wrap *gomock.Call
type MockMachineUserRepositoryMetadataValueConditionCall struct { type MockMachineUserRepositoryOrganizationIDConditionCall struct {
*gomock.Call *gomock.Call
} }
// Return rewrite *gomock.Call.Return // Return rewrite *gomock.Call.Return
func (c *MockMachineUserRepositoryMetadataValueConditionCall) Return(arg0 database.Condition) *MockMachineUserRepositoryMetadataValueConditionCall { func (c *MockMachineUserRepositoryOrganizationIDConditionCall) Return(arg0 database.Condition) *MockMachineUserRepositoryOrganizationIDConditionCall {
c.Call = c.Call.Return(arg0) c.Call = c.Call.Return(arg0)
return c return c
} }
// Do rewrite *gomock.Call.Do // Do rewrite *gomock.Call.Do
func (c *MockMachineUserRepositoryMetadataValueConditionCall) Do(f func(database.BytesOperation, []byte) database.Condition) *MockMachineUserRepositoryMetadataValueConditionCall { func (c *MockMachineUserRepositoryOrganizationIDConditionCall) Do(f func(string) database.Condition) *MockMachineUserRepositoryOrganizationIDConditionCall {
c.Call = c.Call.Do(f) c.Call = c.Call.Do(f)
return c return c
} }
// DoAndReturn rewrite *gomock.Call.DoAndReturn // DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockMachineUserRepositoryMetadataValueConditionCall) DoAndReturn(f func(database.BytesOperation, []byte) database.Condition) *MockMachineUserRepositoryMetadataValueConditionCall { func (c *MockMachineUserRepositoryOrganizationIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockMachineUserRepositoryOrganizationIDConditionCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// OrgIDCondition mocks base method.
func (m *MockMachineUserRepository) OrgIDCondition(orgID string) database.Condition {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "OrgIDCondition", orgID)
ret0, _ := ret[0].(database.Condition)
return ret0
}
// OrgIDCondition indicates an expected call of OrgIDCondition.
func (mr *MockMachineUserRepositoryMockRecorder) OrgIDCondition(orgID any) *MockMachineUserRepositoryOrgIDConditionCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OrgIDCondition", reflect.TypeOf((*MockMachineUserRepository)(nil).OrgIDCondition), orgID)
return &MockMachineUserRepositoryOrgIDConditionCall{Call: call}
}
// MockMachineUserRepositoryOrgIDConditionCall wrap *gomock.Call
type MockMachineUserRepositoryOrgIDConditionCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockMachineUserRepositoryOrgIDConditionCall) Return(arg0 database.Condition) *MockMachineUserRepositoryOrgIDConditionCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockMachineUserRepositoryOrgIDConditionCall) Do(f func(string) database.Condition) *MockMachineUserRepositoryOrgIDConditionCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockMachineUserRepositoryOrgIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockMachineUserRepositoryOrgIDConditionCall {
c.Call = c.Call.DoAndReturn(f) c.Call = c.Call.DoAndReturn(f)
return c return c
} }
@@ -656,7 +694,7 @@ func (c *MockMachineUserRepositoryRemovePersonalAccessTokenCall) DoAndReturn(f f
} }
// SetAccessTokenType mocks base method. // SetAccessTokenType mocks base method.
func (m *MockMachineUserRepository) SetAccessTokenType(tokenType domain.PersonalAccessTokenType) database.Change { func (m *MockMachineUserRepository) SetAccessTokenType(tokenType domain.AccessTokenType) database.Change {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetAccessTokenType", tokenType) ret := m.ctrl.Call(m, "SetAccessTokenType", tokenType)
ret0, _ := ret[0].(database.Change) ret0, _ := ret[0].(database.Change)
@@ -682,13 +720,13 @@ func (c *MockMachineUserRepositorySetAccessTokenTypeCall) Return(arg0 database.C
} }
// Do rewrite *gomock.Call.Do // Do rewrite *gomock.Call.Do
func (c *MockMachineUserRepositorySetAccessTokenTypeCall) Do(f func(domain.PersonalAccessTokenType) database.Change) *MockMachineUserRepositorySetAccessTokenTypeCall { func (c *MockMachineUserRepositorySetAccessTokenTypeCall) Do(f func(domain.AccessTokenType) database.Change) *MockMachineUserRepositorySetAccessTokenTypeCall {
c.Call = c.Call.Do(f) c.Call = c.Call.Do(f)
return c return c
} }
// DoAndReturn rewrite *gomock.Call.DoAndReturn // DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockMachineUserRepositorySetAccessTokenTypeCall) DoAndReturn(f func(domain.PersonalAccessTokenType) database.Change) *MockMachineUserRepositorySetAccessTokenTypeCall { func (c *MockMachineUserRepositorySetAccessTokenTypeCall) DoAndReturn(f func(domain.AccessTokenType) database.Change) *MockMachineUserRepositorySetAccessTokenTypeCall {
c.Call = c.Call.DoAndReturn(f) c.Call = c.Call.DoAndReturn(f)
return c return c
} }
@@ -997,6 +1035,44 @@ func (c *MockMachineUserRepositoryStateConditionCall) DoAndReturn(f func(domain.
return c return c
} }
// TypeColumn mocks base method.
func (m *MockMachineUserRepository) TypeColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TypeColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// TypeColumn indicates an expected call of TypeColumn.
func (mr *MockMachineUserRepositoryMockRecorder) TypeColumn() *MockMachineUserRepositoryTypeColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TypeColumn", reflect.TypeOf((*MockMachineUserRepository)(nil).TypeColumn))
return &MockMachineUserRepositoryTypeColumnCall{Call: call}
}
// MockMachineUserRepositoryTypeColumnCall wrap *gomock.Call
type MockMachineUserRepositoryTypeColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockMachineUserRepositoryTypeColumnCall) Return(arg0 database.Column) *MockMachineUserRepositoryTypeColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockMachineUserRepositoryTypeColumnCall) Do(f func() database.Column) *MockMachineUserRepositoryTypeColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockMachineUserRepositoryTypeColumnCall) DoAndReturn(f func() database.Column) *MockMachineUserRepositoryTypeColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// TypeCondition mocks base method. // TypeCondition mocks base method.
func (m *MockMachineUserRepository) TypeCondition(userType domain.UserType) database.Condition { func (m *MockMachineUserRepository) TypeCondition(userType domain.UserType) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
+76
View File
@@ -202,6 +202,82 @@ func (c *MockProjectRepositoryGetCall) DoAndReturn(f func(context.Context, datab
return c return c
} }
// GrantedOrganizationIDColumn mocks base method.
func (m *MockProjectRepository) GrantedOrganizationIDColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GrantedOrganizationIDColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// GrantedOrganizationIDColumn indicates an expected call of GrantedOrganizationIDColumn.
func (mr *MockProjectRepositoryMockRecorder) GrantedOrganizationIDColumn() *MockProjectRepositoryGrantedOrganizationIDColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantedOrganizationIDColumn", reflect.TypeOf((*MockProjectRepository)(nil).GrantedOrganizationIDColumn))
return &MockProjectRepositoryGrantedOrganizationIDColumnCall{Call: call}
}
// MockProjectRepositoryGrantedOrganizationIDColumnCall wrap *gomock.Call
type MockProjectRepositoryGrantedOrganizationIDColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockProjectRepositoryGrantedOrganizationIDColumnCall) Return(arg0 database.Column) *MockProjectRepositoryGrantedOrganizationIDColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockProjectRepositoryGrantedOrganizationIDColumnCall) Do(f func() database.Column) *MockProjectRepositoryGrantedOrganizationIDColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockProjectRepositoryGrantedOrganizationIDColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryGrantedOrganizationIDColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// GrantedOrganizationIDCondition mocks base method.
func (m *MockProjectRepository) GrantedOrganizationIDCondition(organizationID string) database.Condition {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GrantedOrganizationIDCondition", organizationID)
ret0, _ := ret[0].(database.Condition)
return ret0
}
// GrantedOrganizationIDCondition indicates an expected call of GrantedOrganizationIDCondition.
func (mr *MockProjectRepositoryMockRecorder) GrantedOrganizationIDCondition(organizationID any) *MockProjectRepositoryGrantedOrganizationIDConditionCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GrantedOrganizationIDCondition", reflect.TypeOf((*MockProjectRepository)(nil).GrantedOrganizationIDCondition), organizationID)
return &MockProjectRepositoryGrantedOrganizationIDConditionCall{Call: call}
}
// MockProjectRepositoryGrantedOrganizationIDConditionCall wrap *gomock.Call
type MockProjectRepositoryGrantedOrganizationIDConditionCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockProjectRepositoryGrantedOrganizationIDConditionCall) Return(arg0 database.Condition) *MockProjectRepositoryGrantedOrganizationIDConditionCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockProjectRepositoryGrantedOrganizationIDConditionCall) Do(f func(string) database.Condition) *MockProjectRepositoryGrantedOrganizationIDConditionCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockProjectRepositoryGrantedOrganizationIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockProjectRepositoryGrantedOrganizationIDConditionCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// IDColumn mocks base method. // IDColumn mocks base method.
func (m *MockProjectRepository) IDColumn() database.Column { func (m *MockProjectRepository) IDColumn() database.Column {
m.ctrl.T.Helper() m.ctrl.T.Helper()
File diff suppressed because it is too large Load Diff
+108 -107
View File
@@ -23,6 +23,7 @@ import (
type MockSessionRepository struct { type MockSessionRepository struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockSessionRepositoryMockRecorder recorder *MockSessionRepositoryMockRecorder
isgomock struct{}
} }
// MockSessionRepositoryMockRecorder is the mock recorder for MockSessionRepository. // MockSessionRepositoryMockRecorder is the mock recorder for MockSessionRepository.
@@ -43,17 +44,17 @@ func (m *MockSessionRepository) EXPECT() *MockSessionRepositoryMockRecorder {
} }
// ClearFactor mocks base method. // ClearFactor mocks base method.
func (m *MockSessionRepository) ClearFactor(arg0 domain.SessionFactorType) database.Change { func (m *MockSessionRepository) ClearFactor(factor domain.SessionFactorType) database.Change {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ClearFactor", arg0) ret := m.ctrl.Call(m, "ClearFactor", factor)
ret0, _ := ret[0].(database.Change) ret0, _ := ret[0].(database.Change)
return ret0 return ret0
} }
// ClearFactor indicates an expected call of ClearFactor. // ClearFactor indicates an expected call of ClearFactor.
func (mr *MockSessionRepositoryMockRecorder) ClearFactor(arg0 any) *MockSessionRepositoryClearFactorCall { func (mr *MockSessionRepositoryMockRecorder) ClearFactor(factor any) *MockSessionRepositoryClearFactorCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClearFactor", reflect.TypeOf((*MockSessionRepository)(nil).ClearFactor), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClearFactor", reflect.TypeOf((*MockSessionRepository)(nil).ClearFactor), factor)
return &MockSessionRepositoryClearFactorCall{Call: call} return &MockSessionRepositoryClearFactorCall{Call: call}
} }
@@ -81,17 +82,17 @@ func (c *MockSessionRepositoryClearFactorCall) DoAndReturn(f func(domain.Session
} }
// Create mocks base method. // Create mocks base method.
func (m *MockSessionRepository) Create(arg0 context.Context, arg1 database.QueryExecutor, arg2 *domain.Session) error { func (m *MockSessionRepository) Create(ctx context.Context, client database.QueryExecutor, user *domain.Session) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Create", arg0, arg1, arg2) ret := m.ctrl.Call(m, "Create", ctx, client, user)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// Create indicates an expected call of Create. // Create indicates an expected call of Create.
func (mr *MockSessionRepositoryMockRecorder) Create(arg0, arg1, arg2 any) *MockSessionRepositoryCreateCall { func (mr *MockSessionRepositoryMockRecorder) Create(ctx, client, user any) *MockSessionRepositoryCreateCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockSessionRepository)(nil).Create), arg0, arg1, arg2) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockSessionRepository)(nil).Create), ctx, client, user)
return &MockSessionRepositoryCreateCall{Call: call} return &MockSessionRepositoryCreateCall{Call: call}
} }
@@ -157,17 +158,17 @@ func (c *MockSessionRepositoryCreatedAtColumnCall) DoAndReturn(f func() database
} }
// CreatedAtCondition mocks base method. // CreatedAtCondition mocks base method.
func (m *MockSessionRepository) CreatedAtCondition(arg0 database.NumberOperation, arg1 time.Time) database.Condition { func (m *MockSessionRepository) CreatedAtCondition(op database.NumberOperation, createdAt time.Time) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreatedAtCondition", arg0, arg1) ret := m.ctrl.Call(m, "CreatedAtCondition", op, createdAt)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// CreatedAtCondition indicates an expected call of CreatedAtCondition. // CreatedAtCondition indicates an expected call of CreatedAtCondition.
func (mr *MockSessionRepositoryMockRecorder) CreatedAtCondition(arg0, arg1 any) *MockSessionRepositoryCreatedAtConditionCall { func (mr *MockSessionRepositoryMockRecorder) CreatedAtCondition(op, createdAt any) *MockSessionRepositoryCreatedAtConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatedAtCondition", reflect.TypeOf((*MockSessionRepository)(nil).CreatedAtCondition), arg0, arg1) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatedAtCondition", reflect.TypeOf((*MockSessionRepository)(nil).CreatedAtCondition), op, createdAt)
return &MockSessionRepositoryCreatedAtConditionCall{Call: call} return &MockSessionRepositoryCreatedAtConditionCall{Call: call}
} }
@@ -195,17 +196,17 @@ func (c *MockSessionRepositoryCreatedAtConditionCall) DoAndReturn(f func(databas
} }
// CreatorIDCondition mocks base method. // CreatorIDCondition mocks base method.
func (m *MockSessionRepository) CreatorIDCondition(arg0 string) database.Condition { func (m *MockSessionRepository) CreatorIDCondition(creatorID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreatorIDCondition", arg0) ret := m.ctrl.Call(m, "CreatorIDCondition", creatorID)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// CreatorIDCondition indicates an expected call of CreatorIDCondition. // CreatorIDCondition indicates an expected call of CreatorIDCondition.
func (mr *MockSessionRepositoryMockRecorder) CreatorIDCondition(arg0 any) *MockSessionRepositoryCreatorIDConditionCall { func (mr *MockSessionRepositoryMockRecorder) CreatorIDCondition(creatorID any) *MockSessionRepositoryCreatorIDConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatorIDCondition", reflect.TypeOf((*MockSessionRepository)(nil).CreatorIDCondition), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatorIDCondition", reflect.TypeOf((*MockSessionRepository)(nil).CreatorIDCondition), creatorID)
return &MockSessionRepositoryCreatorIDConditionCall{Call: call} return &MockSessionRepositoryCreatorIDConditionCall{Call: call}
} }
@@ -233,18 +234,18 @@ func (c *MockSessionRepositoryCreatorIDConditionCall) DoAndReturn(f func(string)
} }
// Delete mocks base method. // Delete mocks base method.
func (m *MockSessionRepository) Delete(arg0 context.Context, arg1 database.QueryExecutor, arg2 database.Condition) (int64, error) { func (m *MockSessionRepository) Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", arg0, arg1, arg2) ret := m.ctrl.Call(m, "Delete", ctx, client, condition)
ret0, _ := ret[0].(int64) ret0, _ := ret[0].(int64)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// Delete indicates an expected call of Delete. // Delete indicates an expected call of Delete.
func (mr *MockSessionRepositoryMockRecorder) Delete(arg0, arg1, arg2 any) *MockSessionRepositoryDeleteCall { func (mr *MockSessionRepositoryMockRecorder) Delete(ctx, client, condition any) *MockSessionRepositoryDeleteCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockSessionRepository)(nil).Delete), arg0, arg1, arg2) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockSessionRepository)(nil).Delete), ctx, client, condition)
return &MockSessionRepositoryDeleteCall{Call: call} return &MockSessionRepositoryDeleteCall{Call: call}
} }
@@ -272,17 +273,17 @@ func (c *MockSessionRepositoryDeleteCall) DoAndReturn(f func(context.Context, da
} }
// ExistsFactor mocks base method. // ExistsFactor mocks base method.
func (m *MockSessionRepository) ExistsFactor(arg0 database.Condition) database.Condition { func (m *MockSessionRepository) ExistsFactor(condition database.Condition) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ExistsFactor", arg0) ret := m.ctrl.Call(m, "ExistsFactor", condition)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// ExistsFactor indicates an expected call of ExistsFactor. // ExistsFactor indicates an expected call of ExistsFactor.
func (mr *MockSessionRepositoryMockRecorder) ExistsFactor(arg0 any) *MockSessionRepositoryExistsFactorCall { func (mr *MockSessionRepositoryMockRecorder) ExistsFactor(condition any) *MockSessionRepositoryExistsFactorCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistsFactor", reflect.TypeOf((*MockSessionRepository)(nil).ExistsFactor), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistsFactor", reflect.TypeOf((*MockSessionRepository)(nil).ExistsFactor), condition)
return &MockSessionRepositoryExistsFactorCall{Call: call} return &MockSessionRepositoryExistsFactorCall{Call: call}
} }
@@ -310,17 +311,17 @@ func (c *MockSessionRepositoryExistsFactorCall) DoAndReturn(f func(database.Cond
} }
// ExistsMetadata mocks base method. // ExistsMetadata mocks base method.
func (m *MockSessionRepository) ExistsMetadata(arg0 database.Condition) database.Condition { func (m *MockSessionRepository) ExistsMetadata(condition database.Condition) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ExistsMetadata", arg0) ret := m.ctrl.Call(m, "ExistsMetadata", condition)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// ExistsMetadata indicates an expected call of ExistsMetadata. // ExistsMetadata indicates an expected call of ExistsMetadata.
func (mr *MockSessionRepositoryMockRecorder) ExistsMetadata(arg0 any) *MockSessionRepositoryExistsMetadataCall { func (mr *MockSessionRepositoryMockRecorder) ExistsMetadata(condition any) *MockSessionRepositoryExistsMetadataCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistsMetadata", reflect.TypeOf((*MockSessionRepository)(nil).ExistsMetadata), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistsMetadata", reflect.TypeOf((*MockSessionRepository)(nil).ExistsMetadata), condition)
return &MockSessionRepositoryExistsMetadataCall{Call: call} return &MockSessionRepositoryExistsMetadataCall{Call: call}
} }
@@ -386,17 +387,17 @@ func (c *MockSessionRepositoryExpirationColumnCall) DoAndReturn(f func() databas
} }
// ExpirationCondition mocks base method. // ExpirationCondition mocks base method.
func (m *MockSessionRepository) ExpirationCondition(arg0 database.NumberOperation, arg1 time.Time) database.Condition { func (m *MockSessionRepository) ExpirationCondition(op database.NumberOperation, expiration time.Time) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ExpirationCondition", arg0, arg1) ret := m.ctrl.Call(m, "ExpirationCondition", op, expiration)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// ExpirationCondition indicates an expected call of ExpirationCondition. // ExpirationCondition indicates an expected call of ExpirationCondition.
func (mr *MockSessionRepositoryMockRecorder) ExpirationCondition(arg0, arg1 any) *MockSessionRepositoryExpirationConditionCall { func (mr *MockSessionRepositoryMockRecorder) ExpirationCondition(op, expiration any) *MockSessionRepositoryExpirationConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExpirationCondition", reflect.TypeOf((*MockSessionRepository)(nil).ExpirationCondition), arg0, arg1) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExpirationCondition", reflect.TypeOf((*MockSessionRepository)(nil).ExpirationCondition), op, expiration)
return &MockSessionRepositoryExpirationConditionCall{Call: call} return &MockSessionRepositoryExpirationConditionCall{Call: call}
} }
@@ -462,10 +463,10 @@ func (c *MockSessionRepositoryFactorConditionsCall) DoAndReturn(f func() domain.
} }
// Get mocks base method. // Get mocks base method.
func (m *MockSessionRepository) Get(arg0 context.Context, arg1 database.QueryExecutor, arg2 ...database.QueryOption) (*domain.Session, error) { func (m *MockSessionRepository) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.Session, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []any{arg0, arg1} varargs := []any{ctx, client}
for _, a := range arg2 { for _, a := range opts {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
ret := m.ctrl.Call(m, "Get", varargs...) ret := m.ctrl.Call(m, "Get", varargs...)
@@ -475,9 +476,9 @@ func (m *MockSessionRepository) Get(arg0 context.Context, arg1 database.QueryExe
} }
// Get indicates an expected call of Get. // Get indicates an expected call of Get.
func (mr *MockSessionRepositoryMockRecorder) Get(arg0, arg1 any, arg2 ...any) *MockSessionRepositoryGetCall { func (mr *MockSessionRepositoryMockRecorder) Get(ctx, client any, opts ...any) *MockSessionRepositoryGetCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]any{arg0, arg1}, arg2...) varargs := append([]any{ctx, client}, opts...)
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockSessionRepository)(nil).Get), varargs...) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockSessionRepository)(nil).Get), varargs...)
return &MockSessionRepositoryGetCall{Call: call} return &MockSessionRepositoryGetCall{Call: call}
} }
@@ -544,17 +545,17 @@ func (c *MockSessionRepositoryIDColumnCall) DoAndReturn(f func() database.Column
} }
// IDCondition mocks base method. // IDCondition mocks base method.
func (m *MockSessionRepository) IDCondition(arg0 string) database.Condition { func (m *MockSessionRepository) IDCondition(sessionID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IDCondition", arg0) ret := m.ctrl.Call(m, "IDCondition", sessionID)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// IDCondition indicates an expected call of IDCondition. // IDCondition indicates an expected call of IDCondition.
func (mr *MockSessionRepositoryMockRecorder) IDCondition(arg0 any) *MockSessionRepositoryIDConditionCall { func (mr *MockSessionRepositoryMockRecorder) IDCondition(sessionID any) *MockSessionRepositoryIDConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDCondition", reflect.TypeOf((*MockSessionRepository)(nil).IDCondition), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDCondition", reflect.TypeOf((*MockSessionRepository)(nil).IDCondition), sessionID)
return &MockSessionRepositoryIDConditionCall{Call: call} return &MockSessionRepositoryIDConditionCall{Call: call}
} }
@@ -620,17 +621,17 @@ func (c *MockSessionRepositoryInstanceIDColumnCall) DoAndReturn(f func() databas
} }
// InstanceIDCondition mocks base method. // InstanceIDCondition mocks base method.
func (m *MockSessionRepository) InstanceIDCondition(arg0 string) database.Condition { func (m *MockSessionRepository) InstanceIDCondition(instanceID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InstanceIDCondition", arg0) ret := m.ctrl.Call(m, "InstanceIDCondition", instanceID)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// InstanceIDCondition indicates an expected call of InstanceIDCondition. // InstanceIDCondition indicates an expected call of InstanceIDCondition.
func (mr *MockSessionRepositoryMockRecorder) InstanceIDCondition(arg0 any) *MockSessionRepositoryInstanceIDConditionCall { func (mr *MockSessionRepositoryMockRecorder) InstanceIDCondition(instanceID any) *MockSessionRepositoryInstanceIDConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDCondition", reflect.TypeOf((*MockSessionRepository)(nil).InstanceIDCondition), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDCondition", reflect.TypeOf((*MockSessionRepository)(nil).InstanceIDCondition), instanceID)
return &MockSessionRepositoryInstanceIDConditionCall{Call: call} return &MockSessionRepositoryInstanceIDConditionCall{Call: call}
} }
@@ -696,10 +697,10 @@ func (c *MockSessionRepositoryLifetimeColumnCall) DoAndReturn(f func() database.
} }
// List mocks base method. // List mocks base method.
func (m *MockSessionRepository) List(arg0 context.Context, arg1 database.QueryExecutor, arg2 ...database.QueryOption) ([]*domain.Session, error) { func (m *MockSessionRepository) List(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) ([]*domain.Session, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []any{arg0, arg1} varargs := []any{ctx, client}
for _, a := range arg2 { for _, a := range opts {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
ret := m.ctrl.Call(m, "List", varargs...) ret := m.ctrl.Call(m, "List", varargs...)
@@ -709,9 +710,9 @@ func (m *MockSessionRepository) List(arg0 context.Context, arg1 database.QueryEx
} }
// List indicates an expected call of List. // List indicates an expected call of List.
func (mr *MockSessionRepositoryMockRecorder) List(arg0, arg1 any, arg2 ...any) *MockSessionRepositoryListCall { func (mr *MockSessionRepositoryMockRecorder) List(ctx, client any, opts ...any) *MockSessionRepositoryListCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]any{arg0, arg1}, arg2...) varargs := append([]any{ctx, client}, opts...)
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockSessionRepository)(nil).List), varargs...) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockSessionRepository)(nil).List), varargs...)
return &MockSessionRepositoryListCall{Call: call} return &MockSessionRepositoryListCall{Call: call}
} }
@@ -816,17 +817,17 @@ func (c *MockSessionRepositoryPrimaryKeyColumnsCall) DoAndReturn(f func() []data
} }
// PrimaryKeyCondition mocks base method. // PrimaryKeyCondition mocks base method.
func (m *MockSessionRepository) PrimaryKeyCondition(arg0, arg1 string) database.Condition { func (m *MockSessionRepository) PrimaryKeyCondition(instanceID, sessionID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PrimaryKeyCondition", arg0, arg1) ret := m.ctrl.Call(m, "PrimaryKeyCondition", instanceID, sessionID)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// PrimaryKeyCondition indicates an expected call of PrimaryKeyCondition. // PrimaryKeyCondition indicates an expected call of PrimaryKeyCondition.
func (mr *MockSessionRepositoryMockRecorder) PrimaryKeyCondition(arg0, arg1 any) *MockSessionRepositoryPrimaryKeyConditionCall { func (mr *MockSessionRepositoryMockRecorder) PrimaryKeyCondition(instanceID, sessionID any) *MockSessionRepositoryPrimaryKeyConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrimaryKeyCondition", reflect.TypeOf((*MockSessionRepository)(nil).PrimaryKeyCondition), arg0, arg1) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrimaryKeyCondition", reflect.TypeOf((*MockSessionRepository)(nil).PrimaryKeyCondition), instanceID, sessionID)
return &MockSessionRepositoryPrimaryKeyConditionCall{Call: call} return &MockSessionRepositoryPrimaryKeyConditionCall{Call: call}
} }
@@ -854,17 +855,17 @@ func (c *MockSessionRepositoryPrimaryKeyConditionCall) DoAndReturn(f func(string
} }
// SetChallenge mocks base method. // SetChallenge mocks base method.
func (m *MockSessionRepository) SetChallenge(arg0 domain.SessionChallenge) database.Change { func (m *MockSessionRepository) SetChallenge(challenge domain.SessionChallenge) database.Change {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetChallenge", arg0) ret := m.ctrl.Call(m, "SetChallenge", challenge)
ret0, _ := ret[0].(database.Change) ret0, _ := ret[0].(database.Change)
return ret0 return ret0
} }
// SetChallenge indicates an expected call of SetChallenge. // SetChallenge indicates an expected call of SetChallenge.
func (mr *MockSessionRepositoryMockRecorder) SetChallenge(arg0 any) *MockSessionRepositorySetChallengeCall { func (mr *MockSessionRepositoryMockRecorder) SetChallenge(challenge any) *MockSessionRepositorySetChallengeCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetChallenge", reflect.TypeOf((*MockSessionRepository)(nil).SetChallenge), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetChallenge", reflect.TypeOf((*MockSessionRepository)(nil).SetChallenge), challenge)
return &MockSessionRepositorySetChallengeCall{Call: call} return &MockSessionRepositorySetChallengeCall{Call: call}
} }
@@ -892,17 +893,17 @@ func (c *MockSessionRepositorySetChallengeCall) DoAndReturn(f func(domain.Sessio
} }
// SetFactor mocks base method. // SetFactor mocks base method.
func (m *MockSessionRepository) SetFactor(arg0 domain.SessionFactor) database.Change { func (m *MockSessionRepository) SetFactor(factor domain.SessionFactor) database.Change {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetFactor", arg0) ret := m.ctrl.Call(m, "SetFactor", factor)
ret0, _ := ret[0].(database.Change) ret0, _ := ret[0].(database.Change)
return ret0 return ret0
} }
// SetFactor indicates an expected call of SetFactor. // SetFactor indicates an expected call of SetFactor.
func (mr *MockSessionRepositoryMockRecorder) SetFactor(arg0 any) *MockSessionRepositorySetFactorCall { func (mr *MockSessionRepositoryMockRecorder) SetFactor(factor any) *MockSessionRepositorySetFactorCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFactor", reflect.TypeOf((*MockSessionRepository)(nil).SetFactor), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFactor", reflect.TypeOf((*MockSessionRepository)(nil).SetFactor), factor)
return &MockSessionRepositorySetFactorCall{Call: call} return &MockSessionRepositorySetFactorCall{Call: call}
} }
@@ -930,17 +931,17 @@ func (c *MockSessionRepositorySetFactorCall) DoAndReturn(f func(domain.SessionFa
} }
// SetLifetime mocks base method. // SetLifetime mocks base method.
func (m *MockSessionRepository) SetLifetime(arg0 time.Duration) database.Change { func (m *MockSessionRepository) SetLifetime(lifetime time.Duration) database.Change {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetLifetime", arg0) ret := m.ctrl.Call(m, "SetLifetime", lifetime)
ret0, _ := ret[0].(database.Change) ret0, _ := ret[0].(database.Change)
return ret0 return ret0
} }
// SetLifetime indicates an expected call of SetLifetime. // SetLifetime indicates an expected call of SetLifetime.
func (mr *MockSessionRepositoryMockRecorder) SetLifetime(arg0 any) *MockSessionRepositorySetLifetimeCall { func (mr *MockSessionRepositoryMockRecorder) SetLifetime(lifetime any) *MockSessionRepositorySetLifetimeCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLifetime", reflect.TypeOf((*MockSessionRepository)(nil).SetLifetime), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLifetime", reflect.TypeOf((*MockSessionRepository)(nil).SetLifetime), lifetime)
return &MockSessionRepositorySetLifetimeCall{Call: call} return &MockSessionRepositorySetLifetimeCall{Call: call}
} }
@@ -968,17 +969,17 @@ func (c *MockSessionRepositorySetLifetimeCall) DoAndReturn(f func(time.Duration)
} }
// SetMetadata mocks base method. // SetMetadata mocks base method.
func (m *MockSessionRepository) SetMetadata(arg0 []*domain.SessionMetadata) database.Change { func (m *MockSessionRepository) SetMetadata(metadata []*domain.SessionMetadata) database.Change {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetMetadata", arg0) ret := m.ctrl.Call(m, "SetMetadata", metadata)
ret0, _ := ret[0].(database.Change) ret0, _ := ret[0].(database.Change)
return ret0 return ret0
} }
// SetMetadata indicates an expected call of SetMetadata. // SetMetadata indicates an expected call of SetMetadata.
func (mr *MockSessionRepositoryMockRecorder) SetMetadata(arg0 any) *MockSessionRepositorySetMetadataCall { func (mr *MockSessionRepositoryMockRecorder) SetMetadata(metadata any) *MockSessionRepositorySetMetadataCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMetadata", reflect.TypeOf((*MockSessionRepository)(nil).SetMetadata), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMetadata", reflect.TypeOf((*MockSessionRepository)(nil).SetMetadata), metadata)
return &MockSessionRepositorySetMetadataCall{Call: call} return &MockSessionRepositorySetMetadataCall{Call: call}
} }
@@ -1006,17 +1007,17 @@ func (c *MockSessionRepositorySetMetadataCall) DoAndReturn(f func([]*domain.Sess
} }
// SetToken mocks base method. // SetToken mocks base method.
func (m *MockSessionRepository) SetToken(arg0 string) database.Change { func (m *MockSessionRepository) SetToken(token string) database.Change {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetToken", arg0) ret := m.ctrl.Call(m, "SetToken", token)
ret0, _ := ret[0].(database.Change) ret0, _ := ret[0].(database.Change)
return ret0 return ret0
} }
// SetToken indicates an expected call of SetToken. // SetToken indicates an expected call of SetToken.
func (mr *MockSessionRepositoryMockRecorder) SetToken(arg0 any) *MockSessionRepositorySetTokenCall { func (mr *MockSessionRepositoryMockRecorder) SetToken(token any) *MockSessionRepositorySetTokenCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetToken", reflect.TypeOf((*MockSessionRepository)(nil).SetToken), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetToken", reflect.TypeOf((*MockSessionRepository)(nil).SetToken), token)
return &MockSessionRepositorySetTokenCall{Call: call} return &MockSessionRepositorySetTokenCall{Call: call}
} }
@@ -1044,17 +1045,17 @@ func (c *MockSessionRepositorySetTokenCall) DoAndReturn(f func(string) database.
} }
// SetUpdatedAt mocks base method. // SetUpdatedAt mocks base method.
func (m *MockSessionRepository) SetUpdatedAt(arg0 time.Time) database.Change { func (m *MockSessionRepository) SetUpdatedAt(updatedAt time.Time) database.Change {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetUpdatedAt", arg0) ret := m.ctrl.Call(m, "SetUpdatedAt", updatedAt)
ret0, _ := ret[0].(database.Change) ret0, _ := ret[0].(database.Change)
return ret0 return ret0
} }
// SetUpdatedAt indicates an expected call of SetUpdatedAt. // SetUpdatedAt indicates an expected call of SetUpdatedAt.
func (mr *MockSessionRepositoryMockRecorder) SetUpdatedAt(arg0 any) *MockSessionRepositorySetUpdatedAtCall { func (mr *MockSessionRepositoryMockRecorder) SetUpdatedAt(updatedAt any) *MockSessionRepositorySetUpdatedAtCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUpdatedAt", reflect.TypeOf((*MockSessionRepository)(nil).SetUpdatedAt), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUpdatedAt", reflect.TypeOf((*MockSessionRepository)(nil).SetUpdatedAt), updatedAt)
return &MockSessionRepositorySetUpdatedAtCall{Call: call} return &MockSessionRepositorySetUpdatedAtCall{Call: call}
} }
@@ -1081,49 +1082,49 @@ func (c *MockSessionRepositorySetUpdatedAtCall) DoAndReturn(f func(time.Time) da
return c return c
} }
// TokenColumn mocks base method. // TokenIDColumn mocks base method.
func (m *MockSessionRepository) TokenColumn() database.Column { func (m *MockSessionRepository) TokenIDColumn() database.Column {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TokenColumn") ret := m.ctrl.Call(m, "TokenIDColumn")
ret0, _ := ret[0].(database.Column) ret0, _ := ret[0].(database.Column)
return ret0 return ret0
} }
// TokenColumn indicates an expected call of TokenColumn. // TokenIDColumn indicates an expected call of TokenIDColumn.
func (mr *MockSessionRepositoryMockRecorder) TokenColumn() *MockSessionRepositoryTokenColumnCall { func (mr *MockSessionRepositoryMockRecorder) TokenIDColumn() *MockSessionRepositoryTokenIDColumnCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TokenColumn", reflect.TypeOf((*MockSessionRepository)(nil).TokenColumn)) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TokenIDColumn", reflect.TypeOf((*MockSessionRepository)(nil).TokenIDColumn))
return &MockSessionRepositoryTokenColumnCall{Call: call} return &MockSessionRepositoryTokenIDColumnCall{Call: call}
} }
// MockSessionRepositoryTokenColumnCall wrap *gomock.Call // MockSessionRepositoryTokenIDColumnCall wrap *gomock.Call
type MockSessionRepositoryTokenColumnCall struct { type MockSessionRepositoryTokenIDColumnCall struct {
*gomock.Call *gomock.Call
} }
// Return rewrite *gomock.Call.Return // Return rewrite *gomock.Call.Return
func (c *MockSessionRepositoryTokenColumnCall) Return(arg0 database.Column) *MockSessionRepositoryTokenColumnCall { func (c *MockSessionRepositoryTokenIDColumnCall) Return(arg0 database.Column) *MockSessionRepositoryTokenIDColumnCall {
c.Call = c.Call.Return(arg0) c.Call = c.Call.Return(arg0)
return c return c
} }
// Do rewrite *gomock.Call.Do // Do rewrite *gomock.Call.Do
func (c *MockSessionRepositoryTokenColumnCall) Do(f func() database.Column) *MockSessionRepositoryTokenColumnCall { func (c *MockSessionRepositoryTokenIDColumnCall) Do(f func() database.Column) *MockSessionRepositoryTokenIDColumnCall {
c.Call = c.Call.Do(f) c.Call = c.Call.Do(f)
return c return c
} }
// DoAndReturn rewrite *gomock.Call.DoAndReturn // DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockSessionRepositoryTokenColumnCall) DoAndReturn(f func() database.Column) *MockSessionRepositoryTokenColumnCall { func (c *MockSessionRepositoryTokenIDColumnCall) DoAndReturn(f func() database.Column) *MockSessionRepositoryTokenIDColumnCall {
c.Call = c.Call.DoAndReturn(f) c.Call = c.Call.DoAndReturn(f)
return c return c
} }
// Update mocks base method. // Update mocks base method.
func (m *MockSessionRepository) Update(arg0 context.Context, arg1 database.QueryExecutor, arg2 database.Condition, arg3 ...database.Change) (int64, error) { func (m *MockSessionRepository) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []any{arg0, arg1, arg2} varargs := []any{ctx, client, condition}
for _, a := range arg3 { for _, a := range changes {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
ret := m.ctrl.Call(m, "Update", varargs...) ret := m.ctrl.Call(m, "Update", varargs...)
@@ -1133,9 +1134,9 @@ func (m *MockSessionRepository) Update(arg0 context.Context, arg1 database.Query
} }
// Update indicates an expected call of Update. // Update indicates an expected call of Update.
func (mr *MockSessionRepositoryMockRecorder) Update(arg0, arg1, arg2 any, arg3 ...any) *MockSessionRepositoryUpdateCall { func (mr *MockSessionRepositoryMockRecorder) Update(ctx, client, condition any, changes ...any) *MockSessionRepositoryUpdateCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]any{arg0, arg1, arg2}, arg3...) varargs := append([]any{ctx, client, condition}, changes...)
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockSessionRepository)(nil).Update), varargs...) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockSessionRepository)(nil).Update), varargs...)
return &MockSessionRepositoryUpdateCall{Call: call} return &MockSessionRepositoryUpdateCall{Call: call}
} }
@@ -1202,17 +1203,17 @@ func (c *MockSessionRepositoryUpdatedAtColumnCall) DoAndReturn(f func() database
} }
// UpdatedAtCondition mocks base method. // UpdatedAtCondition mocks base method.
func (m *MockSessionRepository) UpdatedAtCondition(arg0 database.NumberOperation, arg1 time.Time) database.Condition { func (m *MockSessionRepository) UpdatedAtCondition(op database.NumberOperation, updatedAt time.Time) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdatedAtCondition", arg0, arg1) ret := m.ctrl.Call(m, "UpdatedAtCondition", op, updatedAt)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// UpdatedAtCondition indicates an expected call of UpdatedAtCondition. // UpdatedAtCondition indicates an expected call of UpdatedAtCondition.
func (mr *MockSessionRepositoryMockRecorder) UpdatedAtCondition(arg0, arg1 any) *MockSessionRepositoryUpdatedAtConditionCall { func (mr *MockSessionRepositoryMockRecorder) UpdatedAtCondition(op, updatedAt any) *MockSessionRepositoryUpdatedAtConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatedAtCondition", reflect.TypeOf((*MockSessionRepository)(nil).UpdatedAtCondition), arg0, arg1) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatedAtCondition", reflect.TypeOf((*MockSessionRepository)(nil).UpdatedAtCondition), op, updatedAt)
return &MockSessionRepositoryUpdatedAtConditionCall{Call: call} return &MockSessionRepositoryUpdatedAtConditionCall{Call: call}
} }
@@ -1240,17 +1241,17 @@ func (c *MockSessionRepositoryUpdatedAtConditionCall) DoAndReturn(f func(databas
} }
// UserAgentIDCondition mocks base method. // UserAgentIDCondition mocks base method.
func (m *MockSessionRepository) UserAgentIDCondition(arg0 string) database.Condition { func (m *MockSessionRepository) UserAgentIDCondition(userAgentID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UserAgentIDCondition", arg0) ret := m.ctrl.Call(m, "UserAgentIDCondition", userAgentID)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// UserAgentIDCondition indicates an expected call of UserAgentIDCondition. // UserAgentIDCondition indicates an expected call of UserAgentIDCondition.
func (mr *MockSessionRepositoryMockRecorder) UserAgentIDCondition(arg0 any) *MockSessionRepositoryUserAgentIDConditionCall { func (mr *MockSessionRepositoryMockRecorder) UserAgentIDCondition(userAgentID any) *MockSessionRepositoryUserAgentIDConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserAgentIDCondition", reflect.TypeOf((*MockSessionRepository)(nil).UserAgentIDCondition), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserAgentIDCondition", reflect.TypeOf((*MockSessionRepository)(nil).UserAgentIDCondition), userAgentID)
return &MockSessionRepositoryUserAgentIDConditionCall{Call: call} return &MockSessionRepositoryUserAgentIDConditionCall{Call: call}
} }
@@ -1316,17 +1317,17 @@ func (c *MockSessionRepositoryUserIDColumnCall) DoAndReturn(f func() database.Co
} }
// UserIDCondition mocks base method. // UserIDCondition mocks base method.
func (m *MockSessionRepository) UserIDCondition(arg0 string) database.Condition { func (m *MockSessionRepository) UserIDCondition(userID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UserIDCondition", arg0) ret := m.ctrl.Call(m, "UserIDCondition", userID)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// UserIDCondition indicates an expected call of UserIDCondition. // UserIDCondition indicates an expected call of UserIDCondition.
func (mr *MockSessionRepositoryMockRecorder) UserIDCondition(arg0 any) *MockSessionRepositoryUserIDConditionCall { func (mr *MockSessionRepositoryMockRecorder) UserIDCondition(userID any) *MockSessionRepositoryUserIDConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserIDCondition", reflect.TypeOf((*MockSessionRepository)(nil).UserIDCondition), arg0) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserIDCondition", reflect.TypeOf((*MockSessionRepository)(nil).UserIDCondition), userID)
return &MockSessionRepositoryUserIDConditionCall{Call: call} return &MockSessionRepositoryUserIDConditionCall{Call: call}
} }
+139 -291
View File
@@ -320,6 +320,44 @@ func (c *MockUserRepositoryHumanCall) DoAndReturn(f func() domain.HumanUserRepos
return c return c
} }
// IDColumn mocks base method.
func (m *MockUserRepository) IDColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IDColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// IDColumn indicates an expected call of IDColumn.
func (mr *MockUserRepositoryMockRecorder) IDColumn() *MockUserRepositoryIDColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDColumn", reflect.TypeOf((*MockUserRepository)(nil).IDColumn))
return &MockUserRepositoryIDColumnCall{Call: call}
}
// MockUserRepositoryIDColumnCall wrap *gomock.Call
type MockUserRepositoryIDColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryIDColumnCall) Return(arg0 database.Column) *MockUserRepositoryIDColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryIDColumnCall) Do(f func() database.Column) *MockUserRepositoryIDColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryIDColumnCall) DoAndReturn(f func() database.Column) *MockUserRepositoryIDColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// IDCondition mocks base method. // IDCondition mocks base method.
func (m *MockUserRepository) IDCondition(userID string) database.Condition { func (m *MockUserRepository) IDCondition(userID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@@ -358,6 +396,44 @@ func (c *MockUserRepositoryIDConditionCall) DoAndReturn(f func(string) database.
return c return c
} }
// InstanceIDColumn mocks base method.
func (m *MockUserRepository) InstanceIDColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InstanceIDColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// InstanceIDColumn indicates an expected call of InstanceIDColumn.
func (mr *MockUserRepositoryMockRecorder) InstanceIDColumn() *MockUserRepositoryInstanceIDColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDColumn", reflect.TypeOf((*MockUserRepository)(nil).InstanceIDColumn))
return &MockUserRepositoryInstanceIDColumnCall{Call: call}
}
// MockUserRepositoryInstanceIDColumnCall wrap *gomock.Call
type MockUserRepositoryInstanceIDColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryInstanceIDColumnCall) Return(arg0 database.Column) *MockUserRepositoryInstanceIDColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryInstanceIDColumnCall) Do(f func() database.Column) *MockUserRepositoryInstanceIDColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryInstanceIDColumnCall) DoAndReturn(f func() database.Column) *MockUserRepositoryInstanceIDColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// InstanceIDCondition mocks base method. // InstanceIDCondition mocks base method.
func (m *MockUserRepository) InstanceIDCondition(instanceID string) database.Condition { func (m *MockUserRepository) InstanceIDCondition(instanceID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@@ -440,234 +516,6 @@ func (c *MockUserRepositoryListCall) DoAndReturn(f func(context.Context, databas
return c return c
} }
// LoadIdentityProviderLinks mocks base method.
func (m *MockUserRepository) LoadIdentityProviderLinks() domain.UserRepository {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LoadIdentityProviderLinks")
ret0, _ := ret[0].(domain.UserRepository)
return ret0
}
// LoadIdentityProviderLinks indicates an expected call of LoadIdentityProviderLinks.
func (mr *MockUserRepositoryMockRecorder) LoadIdentityProviderLinks() *MockUserRepositoryLoadIdentityProviderLinksCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadIdentityProviderLinks", reflect.TypeOf((*MockUserRepository)(nil).LoadIdentityProviderLinks))
return &MockUserRepositoryLoadIdentityProviderLinksCall{Call: call}
}
// MockUserRepositoryLoadIdentityProviderLinksCall wrap *gomock.Call
type MockUserRepositoryLoadIdentityProviderLinksCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryLoadIdentityProviderLinksCall) Return(arg0 domain.UserRepository) *MockUserRepositoryLoadIdentityProviderLinksCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryLoadIdentityProviderLinksCall) Do(f func() domain.UserRepository) *MockUserRepositoryLoadIdentityProviderLinksCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryLoadIdentityProviderLinksCall) DoAndReturn(f func() domain.UserRepository) *MockUserRepositoryLoadIdentityProviderLinksCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// LoadKeys mocks base method.
func (m *MockUserRepository) LoadKeys() domain.UserRepository {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LoadKeys")
ret0, _ := ret[0].(domain.UserRepository)
return ret0
}
// LoadKeys indicates an expected call of LoadKeys.
func (mr *MockUserRepositoryMockRecorder) LoadKeys() *MockUserRepositoryLoadKeysCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadKeys", reflect.TypeOf((*MockUserRepository)(nil).LoadKeys))
return &MockUserRepositoryLoadKeysCall{Call: call}
}
// MockUserRepositoryLoadKeysCall wrap *gomock.Call
type MockUserRepositoryLoadKeysCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryLoadKeysCall) Return(arg0 domain.UserRepository) *MockUserRepositoryLoadKeysCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryLoadKeysCall) Do(f func() domain.UserRepository) *MockUserRepositoryLoadKeysCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryLoadKeysCall) DoAndReturn(f func() domain.UserRepository) *MockUserRepositoryLoadKeysCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// LoadMetadata mocks base method.
func (m *MockUserRepository) LoadMetadata() domain.UserRepository {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LoadMetadata")
ret0, _ := ret[0].(domain.UserRepository)
return ret0
}
// LoadMetadata indicates an expected call of LoadMetadata.
func (mr *MockUserRepositoryMockRecorder) LoadMetadata() *MockUserRepositoryLoadMetadataCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadMetadata", reflect.TypeOf((*MockUserRepository)(nil).LoadMetadata))
return &MockUserRepositoryLoadMetadataCall{Call: call}
}
// MockUserRepositoryLoadMetadataCall wrap *gomock.Call
type MockUserRepositoryLoadMetadataCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryLoadMetadataCall) Return(arg0 domain.UserRepository) *MockUserRepositoryLoadMetadataCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryLoadMetadataCall) Do(f func() domain.UserRepository) *MockUserRepositoryLoadMetadataCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryLoadMetadataCall) DoAndReturn(f func() domain.UserRepository) *MockUserRepositoryLoadMetadataCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// LoadPATs mocks base method.
func (m *MockUserRepository) LoadPATs() domain.UserRepository {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LoadPATs")
ret0, _ := ret[0].(domain.UserRepository)
return ret0
}
// LoadPATs indicates an expected call of LoadPATs.
func (mr *MockUserRepositoryMockRecorder) LoadPATs() *MockUserRepositoryLoadPATsCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadPATs", reflect.TypeOf((*MockUserRepository)(nil).LoadPATs))
return &MockUserRepositoryLoadPATsCall{Call: call}
}
// MockUserRepositoryLoadPATsCall wrap *gomock.Call
type MockUserRepositoryLoadPATsCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryLoadPATsCall) Return(arg0 domain.UserRepository) *MockUserRepositoryLoadPATsCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryLoadPATsCall) Do(f func() domain.UserRepository) *MockUserRepositoryLoadPATsCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryLoadPATsCall) DoAndReturn(f func() domain.UserRepository) *MockUserRepositoryLoadPATsCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// LoadPasskeys mocks base method.
func (m *MockUserRepository) LoadPasskeys() domain.UserRepository {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LoadPasskeys")
ret0, _ := ret[0].(domain.UserRepository)
return ret0
}
// LoadPasskeys indicates an expected call of LoadPasskeys.
func (mr *MockUserRepositoryMockRecorder) LoadPasskeys() *MockUserRepositoryLoadPasskeysCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadPasskeys", reflect.TypeOf((*MockUserRepository)(nil).LoadPasskeys))
return &MockUserRepositoryLoadPasskeysCall{Call: call}
}
// MockUserRepositoryLoadPasskeysCall wrap *gomock.Call
type MockUserRepositoryLoadPasskeysCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryLoadPasskeysCall) Return(arg0 domain.UserRepository) *MockUserRepositoryLoadPasskeysCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryLoadPasskeysCall) Do(f func() domain.UserRepository) *MockUserRepositoryLoadPasskeysCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryLoadPasskeysCall) DoAndReturn(f func() domain.UserRepository) *MockUserRepositoryLoadPasskeysCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// LoadVerifications mocks base method.
func (m *MockUserRepository) LoadVerifications() domain.UserRepository {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LoadVerifications")
ret0, _ := ret[0].(domain.UserRepository)
return ret0
}
// LoadVerifications indicates an expected call of LoadVerifications.
func (mr *MockUserRepositoryMockRecorder) LoadVerifications() *MockUserRepositoryLoadVerificationsCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadVerifications", reflect.TypeOf((*MockUserRepository)(nil).LoadVerifications))
return &MockUserRepositoryLoadVerificationsCall{Call: call}
}
// MockUserRepositoryLoadVerificationsCall wrap *gomock.Call
type MockUserRepositoryLoadVerificationsCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryLoadVerificationsCall) Return(arg0 domain.UserRepository) *MockUserRepositoryLoadVerificationsCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryLoadVerificationsCall) Do(f func() domain.UserRepository) *MockUserRepositoryLoadVerificationsCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryLoadVerificationsCall) DoAndReturn(f func() domain.UserRepository) *MockUserRepositoryLoadVerificationsCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// LoginNameCondition mocks base method. // LoginNameCondition mocks base method.
func (m *MockUserRepository) LoginNameCondition(op database.TextOperation, loginName string) database.Condition { func (m *MockUserRepository) LoginNameCondition(op database.TextOperation, loginName string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@@ -744,116 +592,78 @@ func (c *MockUserRepositoryMachineCall) DoAndReturn(f func() domain.MachineUserR
return c return c
} }
// MetadataKeyCondition mocks base method. // MetadataConditions mocks base method.
func (m *MockUserRepository) MetadataKeyCondition(key string) database.Condition { func (m *MockUserRepository) MetadataConditions() domain.UserMetadataConditions {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "MetadataKeyCondition", key) ret := m.ctrl.Call(m, "MetadataConditions")
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(domain.UserMetadataConditions)
return ret0 return ret0
} }
// MetadataKeyCondition indicates an expected call of MetadataKeyCondition. // MetadataConditions indicates an expected call of MetadataConditions.
func (mr *MockUserRepositoryMockRecorder) MetadataKeyCondition(key any) *MockUserRepositoryMetadataKeyConditionCall { func (mr *MockUserRepositoryMockRecorder) MetadataConditions() *MockUserRepositoryMetadataConditionsCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MetadataKeyCondition", reflect.TypeOf((*MockUserRepository)(nil).MetadataKeyCondition), key) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MetadataConditions", reflect.TypeOf((*MockUserRepository)(nil).MetadataConditions))
return &MockUserRepositoryMetadataKeyConditionCall{Call: call} return &MockUserRepositoryMetadataConditionsCall{Call: call}
} }
// MockUserRepositoryMetadataKeyConditionCall wrap *gomock.Call // MockUserRepositoryMetadataConditionsCall wrap *gomock.Call
type MockUserRepositoryMetadataKeyConditionCall struct { type MockUserRepositoryMetadataConditionsCall struct {
*gomock.Call *gomock.Call
} }
// Return rewrite *gomock.Call.Return // Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryMetadataKeyConditionCall) Return(arg0 database.Condition) *MockUserRepositoryMetadataKeyConditionCall { func (c *MockUserRepositoryMetadataConditionsCall) Return(arg0 domain.UserMetadataConditions) *MockUserRepositoryMetadataConditionsCall {
c.Call = c.Call.Return(arg0) c.Call = c.Call.Return(arg0)
return c return c
} }
// Do rewrite *gomock.Call.Do // Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryMetadataKeyConditionCall) Do(f func(string) database.Condition) *MockUserRepositoryMetadataKeyConditionCall { func (c *MockUserRepositoryMetadataConditionsCall) Do(f func() domain.UserMetadataConditions) *MockUserRepositoryMetadataConditionsCall {
c.Call = c.Call.Do(f) c.Call = c.Call.Do(f)
return c return c
} }
// DoAndReturn rewrite *gomock.Call.DoAndReturn // DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryMetadataKeyConditionCall) DoAndReturn(f func(string) database.Condition) *MockUserRepositoryMetadataKeyConditionCall { func (c *MockUserRepositoryMetadataConditionsCall) DoAndReturn(f func() domain.UserMetadataConditions) *MockUserRepositoryMetadataConditionsCall {
c.Call = c.Call.DoAndReturn(f) c.Call = c.Call.DoAndReturn(f)
return c return c
} }
// MetadataValueCondition mocks base method. // OrganizationIDCondition mocks base method.
func (m *MockUserRepository) MetadataValueCondition(op database.BytesOperation, value []byte) database.Condition { func (m *MockUserRepository) OrganizationIDCondition(orgID string) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "MetadataValueCondition", op, value) ret := m.ctrl.Call(m, "OrganizationIDCondition", orgID)
ret0, _ := ret[0].(database.Condition) ret0, _ := ret[0].(database.Condition)
return ret0 return ret0
} }
// MetadataValueCondition indicates an expected call of MetadataValueCondition. // OrganizationIDCondition indicates an expected call of OrganizationIDCondition.
func (mr *MockUserRepositoryMockRecorder) MetadataValueCondition(op, value any) *MockUserRepositoryMetadataValueConditionCall { func (mr *MockUserRepositoryMockRecorder) OrganizationIDCondition(orgID any) *MockUserRepositoryOrganizationIDConditionCall {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MetadataValueCondition", reflect.TypeOf((*MockUserRepository)(nil).MetadataValueCondition), op, value) call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OrganizationIDCondition", reflect.TypeOf((*MockUserRepository)(nil).OrganizationIDCondition), orgID)
return &MockUserRepositoryMetadataValueConditionCall{Call: call} return &MockUserRepositoryOrganizationIDConditionCall{Call: call}
} }
// MockUserRepositoryMetadataValueConditionCall wrap *gomock.Call // MockUserRepositoryOrganizationIDConditionCall wrap *gomock.Call
type MockUserRepositoryMetadataValueConditionCall struct { type MockUserRepositoryOrganizationIDConditionCall struct {
*gomock.Call *gomock.Call
} }
// Return rewrite *gomock.Call.Return // Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryMetadataValueConditionCall) Return(arg0 database.Condition) *MockUserRepositoryMetadataValueConditionCall { func (c *MockUserRepositoryOrganizationIDConditionCall) Return(arg0 database.Condition) *MockUserRepositoryOrganizationIDConditionCall {
c.Call = c.Call.Return(arg0) c.Call = c.Call.Return(arg0)
return c return c
} }
// Do rewrite *gomock.Call.Do // Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryMetadataValueConditionCall) Do(f func(database.BytesOperation, []byte) database.Condition) *MockUserRepositoryMetadataValueConditionCall { func (c *MockUserRepositoryOrganizationIDConditionCall) Do(f func(string) database.Condition) *MockUserRepositoryOrganizationIDConditionCall {
c.Call = c.Call.Do(f) c.Call = c.Call.Do(f)
return c return c
} }
// DoAndReturn rewrite *gomock.Call.DoAndReturn // DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryMetadataValueConditionCall) DoAndReturn(f func(database.BytesOperation, []byte) database.Condition) *MockUserRepositoryMetadataValueConditionCall { func (c *MockUserRepositoryOrganizationIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockUserRepositoryOrganizationIDConditionCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// OrgIDCondition mocks base method.
func (m *MockUserRepository) OrgIDCondition(orgID string) database.Condition {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "OrgIDCondition", orgID)
ret0, _ := ret[0].(database.Condition)
return ret0
}
// OrgIDCondition indicates an expected call of OrgIDCondition.
func (mr *MockUserRepositoryMockRecorder) OrgIDCondition(orgID any) *MockUserRepositoryOrgIDConditionCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OrgIDCondition", reflect.TypeOf((*MockUserRepository)(nil).OrgIDCondition), orgID)
return &MockUserRepositoryOrgIDConditionCall{Call: call}
}
// MockUserRepositoryOrgIDConditionCall wrap *gomock.Call
type MockUserRepositoryOrgIDConditionCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryOrgIDConditionCall) Return(arg0 database.Condition) *MockUserRepositoryOrgIDConditionCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryOrgIDConditionCall) Do(f func(string) database.Condition) *MockUserRepositoryOrgIDConditionCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryOrgIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockUserRepositoryOrgIDConditionCall {
c.Call = c.Call.DoAndReturn(f) c.Call = c.Call.DoAndReturn(f)
return c return c
} }
@@ -1162,6 +972,44 @@ func (c *MockUserRepositoryStateConditionCall) DoAndReturn(f func(domain.UserSta
return c return c
} }
// TypeColumn mocks base method.
func (m *MockUserRepository) TypeColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TypeColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// TypeColumn indicates an expected call of TypeColumn.
func (mr *MockUserRepositoryMockRecorder) TypeColumn() *MockUserRepositoryTypeColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TypeColumn", reflect.TypeOf((*MockUserRepository)(nil).TypeColumn))
return &MockUserRepositoryTypeColumnCall{Call: call}
}
// MockUserRepositoryTypeColumnCall wrap *gomock.Call
type MockUserRepositoryTypeColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserRepositoryTypeColumnCall) Return(arg0 database.Column) *MockUserRepositoryTypeColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserRepositoryTypeColumnCall) Do(f func() database.Column) *MockUserRepositoryTypeColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserRepositoryTypeColumnCall) DoAndReturn(f func() database.Column) *MockUserRepositoryTypeColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// TypeCondition mocks base method. // TypeCondition mocks base method.
func (m *MockUserRepository) TypeCondition(userType domain.UserType) database.Condition { func (m *MockUserRepository) TypeCondition(userType domain.UserType) database.Condition {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@@ -0,0 +1,899 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/zitadel/zitadel/backend/v3/domain (interfaces: UserIdentityProviderLinkRepository)
//
// Generated by this command:
//
// mockgen -typed -package domainmock -destination ./mock/user_identity_provider_link.mock.go . UserIdentityProviderLinkRepository
//
// Package domainmock is a generated GoMock package.
package domainmock
import (
context "context"
reflect "reflect"
time "time"
domain "github.com/zitadel/zitadel/backend/v3/domain"
database "github.com/zitadel/zitadel/backend/v3/storage/database"
gomock "go.uber.org/mock/gomock"
)
// MockUserIdentityProviderLinkRepository is a mock of UserIdentityProviderLinkRepository interface.
type MockUserIdentityProviderLinkRepository struct {
ctrl *gomock.Controller
recorder *MockUserIdentityProviderLinkRepositoryMockRecorder
isgomock struct{}
}
// MockUserIdentityProviderLinkRepositoryMockRecorder is the mock recorder for MockUserIdentityProviderLinkRepository.
type MockUserIdentityProviderLinkRepositoryMockRecorder struct {
mock *MockUserIdentityProviderLinkRepository
}
// NewMockUserIdentityProviderLinkRepository creates a new mock instance.
func NewMockUserIdentityProviderLinkRepository(ctrl *gomock.Controller) *MockUserIdentityProviderLinkRepository {
mock := &MockUserIdentityProviderLinkRepository{ctrl: ctrl}
mock.recorder = &MockUserIdentityProviderLinkRepositoryMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockUserIdentityProviderLinkRepository) EXPECT() *MockUserIdentityProviderLinkRepositoryMockRecorder {
return m.recorder
}
// Create mocks base method.
func (m *MockUserIdentityProviderLinkRepository) Create(ctx context.Context, client database.QueryExecutor, link *domain.UserIdentityProviderLink) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Create", ctx, client, link)
ret0, _ := ret[0].(error)
return ret0
}
// Create indicates an expected call of Create.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) Create(ctx, client, link any) *MockUserIdentityProviderLinkRepositoryCreateCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).Create), ctx, client, link)
return &MockUserIdentityProviderLinkRepositoryCreateCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryCreateCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryCreateCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryCreateCall) Return(arg0 error) *MockUserIdentityProviderLinkRepositoryCreateCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryCreateCall) Do(f func(context.Context, database.QueryExecutor, *domain.UserIdentityProviderLink) error) *MockUserIdentityProviderLinkRepositoryCreateCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryCreateCall) DoAndReturn(f func(context.Context, database.QueryExecutor, *domain.UserIdentityProviderLink) error) *MockUserIdentityProviderLinkRepositoryCreateCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// CreatedAtColumn mocks base method.
func (m *MockUserIdentityProviderLinkRepository) CreatedAtColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreatedAtColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// CreatedAtColumn indicates an expected call of CreatedAtColumn.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) CreatedAtColumn() *MockUserIdentityProviderLinkRepositoryCreatedAtColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatedAtColumn", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).CreatedAtColumn))
return &MockUserIdentityProviderLinkRepositoryCreatedAtColumnCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryCreatedAtColumnCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryCreatedAtColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryCreatedAtColumnCall) Return(arg0 database.Column) *MockUserIdentityProviderLinkRepositoryCreatedAtColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryCreatedAtColumnCall) Do(f func() database.Column) *MockUserIdentityProviderLinkRepositoryCreatedAtColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryCreatedAtColumnCall) DoAndReturn(f func() database.Column) *MockUserIdentityProviderLinkRepositoryCreatedAtColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// Delete mocks base method.
func (m *MockUserIdentityProviderLinkRepository) Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", ctx, client, condition)
ret0, _ := ret[0].(int64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Delete indicates an expected call of Delete.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) Delete(ctx, client, condition any) *MockUserIdentityProviderLinkRepositoryDeleteCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).Delete), ctx, client, condition)
return &MockUserIdentityProviderLinkRepositoryDeleteCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryDeleteCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryDeleteCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryDeleteCall) Return(arg0 int64, arg1 error) *MockUserIdentityProviderLinkRepositoryDeleteCall {
c.Call = c.Call.Return(arg0, arg1)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryDeleteCall) Do(f func(context.Context, database.QueryExecutor, database.Condition) (int64, error)) *MockUserIdentityProviderLinkRepositoryDeleteCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryDeleteCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition) (int64, error)) *MockUserIdentityProviderLinkRepositoryDeleteCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// Get mocks base method.
func (m *MockUserIdentityProviderLinkRepository) Get(ctx context.Context, client database.QueryExecutor, condition database.Condition, opts ...database.QueryOption) (*domain.UserIdentityProviderLink, error) {
m.ctrl.T.Helper()
varargs := []any{ctx, client, condition}
for _, a := range opts {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "Get", varargs...)
ret0, _ := ret[0].(*domain.UserIdentityProviderLink)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Get indicates an expected call of Get.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) Get(ctx, client, condition any, opts ...any) *MockUserIdentityProviderLinkRepositoryGetCall {
mr.mock.ctrl.T.Helper()
varargs := append([]any{ctx, client, condition}, opts...)
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).Get), varargs...)
return &MockUserIdentityProviderLinkRepositoryGetCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryGetCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryGetCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryGetCall) Return(arg0 *domain.UserIdentityProviderLink, arg1 error) *MockUserIdentityProviderLinkRepositoryGetCall {
c.Call = c.Call.Return(arg0, arg1)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryGetCall) Do(f func(context.Context, database.QueryExecutor, database.Condition, ...database.QueryOption) (*domain.UserIdentityProviderLink, error)) *MockUserIdentityProviderLinkRepositoryGetCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryGetCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition, ...database.QueryOption) (*domain.UserIdentityProviderLink, error)) *MockUserIdentityProviderLinkRepositoryGetCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// IdentityProviderIDColumn mocks base method.
func (m *MockUserIdentityProviderLinkRepository) IdentityProviderIDColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IdentityProviderIDColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// IdentityProviderIDColumn indicates an expected call of IdentityProviderIDColumn.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) IdentityProviderIDColumn() *MockUserIdentityProviderLinkRepositoryIdentityProviderIDColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IdentityProviderIDColumn", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).IdentityProviderIDColumn))
return &MockUserIdentityProviderLinkRepositoryIdentityProviderIDColumnCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryIdentityProviderIDColumnCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryIdentityProviderIDColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryIdentityProviderIDColumnCall) Return(arg0 database.Column) *MockUserIdentityProviderLinkRepositoryIdentityProviderIDColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryIdentityProviderIDColumnCall) Do(f func() database.Column) *MockUserIdentityProviderLinkRepositoryIdentityProviderIDColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryIdentityProviderIDColumnCall) DoAndReturn(f func() database.Column) *MockUserIdentityProviderLinkRepositoryIdentityProviderIDColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// IdentityProviderIDCondition mocks base method.
func (m *MockUserIdentityProviderLinkRepository) IdentityProviderIDCondition(op database.TextOperation, id string) database.Condition {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IdentityProviderIDCondition", op, id)
ret0, _ := ret[0].(database.Condition)
return ret0
}
// IdentityProviderIDCondition indicates an expected call of IdentityProviderIDCondition.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) IdentityProviderIDCondition(op, id any) *MockUserIdentityProviderLinkRepositoryIdentityProviderIDConditionCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IdentityProviderIDCondition", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).IdentityProviderIDCondition), op, id)
return &MockUserIdentityProviderLinkRepositoryIdentityProviderIDConditionCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryIdentityProviderIDConditionCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryIdentityProviderIDConditionCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryIdentityProviderIDConditionCall) Return(arg0 database.Condition) *MockUserIdentityProviderLinkRepositoryIdentityProviderIDConditionCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryIdentityProviderIDConditionCall) Do(f func(database.TextOperation, string) database.Condition) *MockUserIdentityProviderLinkRepositoryIdentityProviderIDConditionCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryIdentityProviderIDConditionCall) DoAndReturn(f func(database.TextOperation, string) database.Condition) *MockUserIdentityProviderLinkRepositoryIdentityProviderIDConditionCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// InstanceIDColumn mocks base method.
func (m *MockUserIdentityProviderLinkRepository) InstanceIDColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InstanceIDColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// InstanceIDColumn indicates an expected call of InstanceIDColumn.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) InstanceIDColumn() *MockUserIdentityProviderLinkRepositoryInstanceIDColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDColumn", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).InstanceIDColumn))
return &MockUserIdentityProviderLinkRepositoryInstanceIDColumnCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryInstanceIDColumnCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryInstanceIDColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryInstanceIDColumnCall) Return(arg0 database.Column) *MockUserIdentityProviderLinkRepositoryInstanceIDColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryInstanceIDColumnCall) Do(f func() database.Column) *MockUserIdentityProviderLinkRepositoryInstanceIDColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryInstanceIDColumnCall) DoAndReturn(f func() database.Column) *MockUserIdentityProviderLinkRepositoryInstanceIDColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// InstanceIDCondition mocks base method.
func (m *MockUserIdentityProviderLinkRepository) InstanceIDCondition(op database.TextOperation, id string) database.Condition {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InstanceIDCondition", op, id)
ret0, _ := ret[0].(database.Condition)
return ret0
}
// InstanceIDCondition indicates an expected call of InstanceIDCondition.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) InstanceIDCondition(op, id any) *MockUserIdentityProviderLinkRepositoryInstanceIDConditionCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDCondition", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).InstanceIDCondition), op, id)
return &MockUserIdentityProviderLinkRepositoryInstanceIDConditionCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryInstanceIDConditionCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryInstanceIDConditionCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryInstanceIDConditionCall) Return(arg0 database.Condition) *MockUserIdentityProviderLinkRepositoryInstanceIDConditionCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryInstanceIDConditionCall) Do(f func(database.TextOperation, string) database.Condition) *MockUserIdentityProviderLinkRepositoryInstanceIDConditionCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryInstanceIDConditionCall) DoAndReturn(f func(database.TextOperation, string) database.Condition) *MockUserIdentityProviderLinkRepositoryInstanceIDConditionCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// List mocks base method.
func (m *MockUserIdentityProviderLinkRepository) List(ctx context.Context, client database.QueryExecutor, condition database.Condition, opts ...database.QueryOption) ([]*domain.UserIdentityProviderLink, error) {
m.ctrl.T.Helper()
varargs := []any{ctx, client, condition}
for _, a := range opts {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "List", varargs...)
ret0, _ := ret[0].([]*domain.UserIdentityProviderLink)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// List indicates an expected call of List.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) List(ctx, client, condition any, opts ...any) *MockUserIdentityProviderLinkRepositoryListCall {
mr.mock.ctrl.T.Helper()
varargs := append([]any{ctx, client, condition}, opts...)
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).List), varargs...)
return &MockUserIdentityProviderLinkRepositoryListCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryListCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryListCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryListCall) Return(arg0 []*domain.UserIdentityProviderLink, arg1 error) *MockUserIdentityProviderLinkRepositoryListCall {
c.Call = c.Call.Return(arg0, arg1)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryListCall) Do(f func(context.Context, database.QueryExecutor, database.Condition, ...database.QueryOption) ([]*domain.UserIdentityProviderLink, error)) *MockUserIdentityProviderLinkRepositoryListCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryListCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition, ...database.QueryOption) ([]*domain.UserIdentityProviderLink, error)) *MockUserIdentityProviderLinkRepositoryListCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// PrimaryKeyColumns mocks base method.
func (m *MockUserIdentityProviderLinkRepository) PrimaryKeyColumns() []database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PrimaryKeyColumns")
ret0, _ := ret[0].([]database.Column)
return ret0
}
// PrimaryKeyColumns indicates an expected call of PrimaryKeyColumns.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) PrimaryKeyColumns() *MockUserIdentityProviderLinkRepositoryPrimaryKeyColumnsCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrimaryKeyColumns", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).PrimaryKeyColumns))
return &MockUserIdentityProviderLinkRepositoryPrimaryKeyColumnsCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryPrimaryKeyColumnsCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryPrimaryKeyColumnsCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryPrimaryKeyColumnsCall) Return(arg0 []database.Column) *MockUserIdentityProviderLinkRepositoryPrimaryKeyColumnsCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryPrimaryKeyColumnsCall) Do(f func() []database.Column) *MockUserIdentityProviderLinkRepositoryPrimaryKeyColumnsCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryPrimaryKeyColumnsCall) DoAndReturn(f func() []database.Column) *MockUserIdentityProviderLinkRepositoryPrimaryKeyColumnsCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// PrimaryKeyCondition mocks base method.
func (m *MockUserIdentityProviderLinkRepository) PrimaryKeyCondition(instanceID, idpID, providedID string) database.Condition {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PrimaryKeyCondition", instanceID, idpID, providedID)
ret0, _ := ret[0].(database.Condition)
return ret0
}
// PrimaryKeyCondition indicates an expected call of PrimaryKeyCondition.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) PrimaryKeyCondition(instanceID, idpID, providedID any) *MockUserIdentityProviderLinkRepositoryPrimaryKeyConditionCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrimaryKeyCondition", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).PrimaryKeyCondition), instanceID, idpID, providedID)
return &MockUserIdentityProviderLinkRepositoryPrimaryKeyConditionCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryPrimaryKeyConditionCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryPrimaryKeyConditionCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryPrimaryKeyConditionCall) Return(arg0 database.Condition) *MockUserIdentityProviderLinkRepositoryPrimaryKeyConditionCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryPrimaryKeyConditionCall) Do(f func(string, string, string) database.Condition) *MockUserIdentityProviderLinkRepositoryPrimaryKeyConditionCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryPrimaryKeyConditionCall) DoAndReturn(f func(string, string, string) database.Condition) *MockUserIdentityProviderLinkRepositoryPrimaryKeyConditionCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// ProvidedIDColumn mocks base method.
func (m *MockUserIdentityProviderLinkRepository) ProvidedIDColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ProvidedIDColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// ProvidedIDColumn indicates an expected call of ProvidedIDColumn.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) ProvidedIDColumn() *MockUserIdentityProviderLinkRepositoryProvidedIDColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidedIDColumn", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).ProvidedIDColumn))
return &MockUserIdentityProviderLinkRepositoryProvidedIDColumnCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryProvidedIDColumnCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryProvidedIDColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryProvidedIDColumnCall) Return(arg0 database.Column) *MockUserIdentityProviderLinkRepositoryProvidedIDColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryProvidedIDColumnCall) Do(f func() database.Column) *MockUserIdentityProviderLinkRepositoryProvidedIDColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryProvidedIDColumnCall) DoAndReturn(f func() database.Column) *MockUserIdentityProviderLinkRepositoryProvidedIDColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// ProvidedIDCondition mocks base method.
func (m *MockUserIdentityProviderLinkRepository) ProvidedIDCondition(op database.TextOperation, id string) database.Condition {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ProvidedIDCondition", op, id)
ret0, _ := ret[0].(database.Condition)
return ret0
}
// ProvidedIDCondition indicates an expected call of ProvidedIDCondition.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) ProvidedIDCondition(op, id any) *MockUserIdentityProviderLinkRepositoryProvidedIDConditionCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidedIDCondition", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).ProvidedIDCondition), op, id)
return &MockUserIdentityProviderLinkRepositoryProvidedIDConditionCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryProvidedIDConditionCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryProvidedIDConditionCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryProvidedIDConditionCall) Return(arg0 database.Condition) *MockUserIdentityProviderLinkRepositoryProvidedIDConditionCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryProvidedIDConditionCall) Do(f func(database.TextOperation, string) database.Condition) *MockUserIdentityProviderLinkRepositoryProvidedIDConditionCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryProvidedIDConditionCall) DoAndReturn(f func(database.TextOperation, string) database.Condition) *MockUserIdentityProviderLinkRepositoryProvidedIDConditionCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// ProvidedUsernameColumn mocks base method.
func (m *MockUserIdentityProviderLinkRepository) ProvidedUsernameColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ProvidedUsernameColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// ProvidedUsernameColumn indicates an expected call of ProvidedUsernameColumn.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) ProvidedUsernameColumn() *MockUserIdentityProviderLinkRepositoryProvidedUsernameColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidedUsernameColumn", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).ProvidedUsernameColumn))
return &MockUserIdentityProviderLinkRepositoryProvidedUsernameColumnCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryProvidedUsernameColumnCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryProvidedUsernameColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryProvidedUsernameColumnCall) Return(arg0 database.Column) *MockUserIdentityProviderLinkRepositoryProvidedUsernameColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryProvidedUsernameColumnCall) Do(f func() database.Column) *MockUserIdentityProviderLinkRepositoryProvidedUsernameColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryProvidedUsernameColumnCall) DoAndReturn(f func() database.Column) *MockUserIdentityProviderLinkRepositoryProvidedUsernameColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// ProvidedUsernameCondition mocks base method.
func (m *MockUserIdentityProviderLinkRepository) ProvidedUsernameCondition(op database.TextOperation, username string) database.Condition {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ProvidedUsernameCondition", op, username)
ret0, _ := ret[0].(database.Condition)
return ret0
}
// ProvidedUsernameCondition indicates an expected call of ProvidedUsernameCondition.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) ProvidedUsernameCondition(op, username any) *MockUserIdentityProviderLinkRepositoryProvidedUsernameConditionCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvidedUsernameCondition", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).ProvidedUsernameCondition), op, username)
return &MockUserIdentityProviderLinkRepositoryProvidedUsernameConditionCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryProvidedUsernameConditionCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryProvidedUsernameConditionCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryProvidedUsernameConditionCall) Return(arg0 database.Condition) *MockUserIdentityProviderLinkRepositoryProvidedUsernameConditionCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryProvidedUsernameConditionCall) Do(f func(database.TextOperation, string) database.Condition) *MockUserIdentityProviderLinkRepositoryProvidedUsernameConditionCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryProvidedUsernameConditionCall) DoAndReturn(f func(database.TextOperation, string) database.Condition) *MockUserIdentityProviderLinkRepositoryProvidedUsernameConditionCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// SetProvidedUserID mocks base method.
func (m *MockUserIdentityProviderLinkRepository) SetProvidedUserID(providedID string) database.Change {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetProvidedUserID", providedID)
ret0, _ := ret[0].(database.Change)
return ret0
}
// SetProvidedUserID indicates an expected call of SetProvidedUserID.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) SetProvidedUserID(providedID any) *MockUserIdentityProviderLinkRepositorySetProvidedUserIDCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProvidedUserID", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).SetProvidedUserID), providedID)
return &MockUserIdentityProviderLinkRepositorySetProvidedUserIDCall{Call: call}
}
// MockUserIdentityProviderLinkRepositorySetProvidedUserIDCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositorySetProvidedUserIDCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositorySetProvidedUserIDCall) Return(arg0 database.Change) *MockUserIdentityProviderLinkRepositorySetProvidedUserIDCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositorySetProvidedUserIDCall) Do(f func(string) database.Change) *MockUserIdentityProviderLinkRepositorySetProvidedUserIDCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositorySetProvidedUserIDCall) DoAndReturn(f func(string) database.Change) *MockUserIdentityProviderLinkRepositorySetProvidedUserIDCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// SetProvidedUsername mocks base method.
func (m *MockUserIdentityProviderLinkRepository) SetProvidedUsername(username string) database.Change {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetProvidedUsername", username)
ret0, _ := ret[0].(database.Change)
return ret0
}
// SetProvidedUsername indicates an expected call of SetProvidedUsername.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) SetProvidedUsername(username any) *MockUserIdentityProviderLinkRepositorySetProvidedUsernameCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProvidedUsername", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).SetProvidedUsername), username)
return &MockUserIdentityProviderLinkRepositorySetProvidedUsernameCall{Call: call}
}
// MockUserIdentityProviderLinkRepositorySetProvidedUsernameCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositorySetProvidedUsernameCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositorySetProvidedUsernameCall) Return(arg0 database.Change) *MockUserIdentityProviderLinkRepositorySetProvidedUsernameCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositorySetProvidedUsernameCall) Do(f func(string) database.Change) *MockUserIdentityProviderLinkRepositorySetProvidedUsernameCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositorySetProvidedUsernameCall) DoAndReturn(f func(string) database.Change) *MockUserIdentityProviderLinkRepositorySetProvidedUsernameCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// SetUpdatedAt mocks base method.
func (m *MockUserIdentityProviderLinkRepository) SetUpdatedAt(updatedAt time.Time) database.Change {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetUpdatedAt", updatedAt)
ret0, _ := ret[0].(database.Change)
return ret0
}
// SetUpdatedAt indicates an expected call of SetUpdatedAt.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) SetUpdatedAt(updatedAt any) *MockUserIdentityProviderLinkRepositorySetUpdatedAtCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUpdatedAt", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).SetUpdatedAt), updatedAt)
return &MockUserIdentityProviderLinkRepositorySetUpdatedAtCall{Call: call}
}
// MockUserIdentityProviderLinkRepositorySetUpdatedAtCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositorySetUpdatedAtCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositorySetUpdatedAtCall) Return(arg0 database.Change) *MockUserIdentityProviderLinkRepositorySetUpdatedAtCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositorySetUpdatedAtCall) Do(f func(time.Time) database.Change) *MockUserIdentityProviderLinkRepositorySetUpdatedAtCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositorySetUpdatedAtCall) DoAndReturn(f func(time.Time) database.Change) *MockUserIdentityProviderLinkRepositorySetUpdatedAtCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// Update mocks base method.
func (m *MockUserIdentityProviderLinkRepository) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) {
m.ctrl.T.Helper()
varargs := []any{ctx, client, condition}
for _, a := range changes {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "Update", varargs...)
ret0, _ := ret[0].(int64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Update indicates an expected call of Update.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) Update(ctx, client, condition any, changes ...any) *MockUserIdentityProviderLinkRepositoryUpdateCall {
mr.mock.ctrl.T.Helper()
varargs := append([]any{ctx, client, condition}, changes...)
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).Update), varargs...)
return &MockUserIdentityProviderLinkRepositoryUpdateCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryUpdateCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryUpdateCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryUpdateCall) Return(arg0 int64, arg1 error) *MockUserIdentityProviderLinkRepositoryUpdateCall {
c.Call = c.Call.Return(arg0, arg1)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryUpdateCall) Do(f func(context.Context, database.QueryExecutor, database.Condition, ...database.Change) (int64, error)) *MockUserIdentityProviderLinkRepositoryUpdateCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryUpdateCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition, ...database.Change) (int64, error)) *MockUserIdentityProviderLinkRepositoryUpdateCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// UpdatedAtColumn mocks base method.
func (m *MockUserIdentityProviderLinkRepository) UpdatedAtColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdatedAtColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// UpdatedAtColumn indicates an expected call of UpdatedAtColumn.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) UpdatedAtColumn() *MockUserIdentityProviderLinkRepositoryUpdatedAtColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatedAtColumn", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).UpdatedAtColumn))
return &MockUserIdentityProviderLinkRepositoryUpdatedAtColumnCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryUpdatedAtColumnCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryUpdatedAtColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryUpdatedAtColumnCall) Return(arg0 database.Column) *MockUserIdentityProviderLinkRepositoryUpdatedAtColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryUpdatedAtColumnCall) Do(f func() database.Column) *MockUserIdentityProviderLinkRepositoryUpdatedAtColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryUpdatedAtColumnCall) DoAndReturn(f func() database.Column) *MockUserIdentityProviderLinkRepositoryUpdatedAtColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// UserIDColumn mocks base method.
func (m *MockUserIdentityProviderLinkRepository) UserIDColumn() database.Column {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UserIDColumn")
ret0, _ := ret[0].(database.Column)
return ret0
}
// UserIDColumn indicates an expected call of UserIDColumn.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) UserIDColumn() *MockUserIdentityProviderLinkRepositoryUserIDColumnCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserIDColumn", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).UserIDColumn))
return &MockUserIdentityProviderLinkRepositoryUserIDColumnCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryUserIDColumnCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryUserIDColumnCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryUserIDColumnCall) Return(arg0 database.Column) *MockUserIdentityProviderLinkRepositoryUserIDColumnCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryUserIDColumnCall) Do(f func() database.Column) *MockUserIdentityProviderLinkRepositoryUserIDColumnCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryUserIDColumnCall) DoAndReturn(f func() database.Column) *MockUserIdentityProviderLinkRepositoryUserIDColumnCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
// UserIDCondition mocks base method.
func (m *MockUserIdentityProviderLinkRepository) UserIDCondition(op database.TextOperation, id string) database.Condition {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UserIDCondition", op, id)
ret0, _ := ret[0].(database.Condition)
return ret0
}
// UserIDCondition indicates an expected call of UserIDCondition.
func (mr *MockUserIdentityProviderLinkRepositoryMockRecorder) UserIDCondition(op, id any) *MockUserIdentityProviderLinkRepositoryUserIDConditionCall {
mr.mock.ctrl.T.Helper()
call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserIDCondition", reflect.TypeOf((*MockUserIdentityProviderLinkRepository)(nil).UserIDCondition), op, id)
return &MockUserIdentityProviderLinkRepositoryUserIDConditionCall{Call: call}
}
// MockUserIdentityProviderLinkRepositoryUserIDConditionCall wrap *gomock.Call
type MockUserIdentityProviderLinkRepositoryUserIDConditionCall struct {
*gomock.Call
}
// Return rewrite *gomock.Call.Return
func (c *MockUserIdentityProviderLinkRepositoryUserIDConditionCall) Return(arg0 database.Condition) *MockUserIdentityProviderLinkRepositoryUserIDConditionCall {
c.Call = c.Call.Return(arg0)
return c
}
// Do rewrite *gomock.Call.Do
func (c *MockUserIdentityProviderLinkRepositoryUserIDConditionCall) Do(f func(database.TextOperation, string) database.Condition) *MockUserIdentityProviderLinkRepositoryUserIDConditionCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
func (c *MockUserIdentityProviderLinkRepositoryUserIDConditionCall) DoAndReturn(f func(database.TextOperation, string) database.Condition) *MockUserIdentityProviderLinkRepositoryUserIDConditionCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
+50 -1
View File
@@ -1,8 +1,10 @@
// Code generated by "enumer -type PasskeyType -transform lower -trimprefix PasskeyType"; DO NOT EDIT. // Code generated by "enumer -type PasskeyType -transform lower -trimprefix PasskeyType -json -sql"; DO NOT EDIT.
package domain package domain
import ( import (
"database/sql/driver"
"encoding/json"
"fmt" "fmt"
"strings" "strings"
) )
@@ -80,3 +82,50 @@ func (i PasskeyType) IsAPasskeyType() bool {
} }
return false return false
} }
// MarshalJSON implements the json.Marshaler interface for PasskeyType
func (i PasskeyType) MarshalJSON() ([]byte, error) {
return json.Marshal(i.String())
}
// UnmarshalJSON implements the json.Unmarshaler interface for PasskeyType
func (i *PasskeyType) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return fmt.Errorf("PasskeyType should be a string, got %s", data)
}
var err error
*i, err = PasskeyTypeString(s)
return err
}
func (i PasskeyType) Value() (driver.Value, error) {
return i.String(), nil
}
func (i *PasskeyType) Scan(value interface{}) error {
if value == nil {
return nil
}
var str string
switch v := value.(type) {
case []byte:
str = string(v)
case string:
str = v
case fmt.Stringer:
str = v.String()
default:
return fmt.Errorf("invalid value of PasskeyType: %[1]T(%[1]v)", value)
}
val, err := PasskeyTypeString(str)
if err != nil {
return err
}
*i = val
return nil
}
@@ -1,82 +0,0 @@
// Code generated by "enumer -type PersonalAccessTokenType -transform lower -trimprefix PersonalAccessTokenType"; DO NOT EDIT.
package domain
import (
"fmt"
"strings"
)
const _PersonalAccessTokenTypeName = "unspecifiedbearerjwt"
var _PersonalAccessTokenTypeIndex = [...]uint8{0, 11, 17, 20}
const _PersonalAccessTokenTypeLowerName = "unspecifiedbearerjwt"
func (i PersonalAccessTokenType) String() string {
if i >= PersonalAccessTokenType(len(_PersonalAccessTokenTypeIndex)-1) {
return fmt.Sprintf("PersonalAccessTokenType(%d)", i)
}
return _PersonalAccessTokenTypeName[_PersonalAccessTokenTypeIndex[i]:_PersonalAccessTokenTypeIndex[i+1]]
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _PersonalAccessTokenTypeNoOp() {
var x [1]struct{}
_ = x[PersonalAccessTokenTypeUnspecified-(0)]
_ = x[PersonalAccessTokenTypeBearer-(1)]
_ = x[PersonalAccessTokenTypeJWT-(2)]
}
var _PersonalAccessTokenTypeValues = []PersonalAccessTokenType{PersonalAccessTokenTypeUnspecified, PersonalAccessTokenTypeBearer, PersonalAccessTokenTypeJWT}
var _PersonalAccessTokenTypeNameToValueMap = map[string]PersonalAccessTokenType{
_PersonalAccessTokenTypeName[0:11]: PersonalAccessTokenTypeUnspecified,
_PersonalAccessTokenTypeLowerName[0:11]: PersonalAccessTokenTypeUnspecified,
_PersonalAccessTokenTypeName[11:17]: PersonalAccessTokenTypeBearer,
_PersonalAccessTokenTypeLowerName[11:17]: PersonalAccessTokenTypeBearer,
_PersonalAccessTokenTypeName[17:20]: PersonalAccessTokenTypeJWT,
_PersonalAccessTokenTypeLowerName[17:20]: PersonalAccessTokenTypeJWT,
}
var _PersonalAccessTokenTypeNames = []string{
_PersonalAccessTokenTypeName[0:11],
_PersonalAccessTokenTypeName[11:17],
_PersonalAccessTokenTypeName[17:20],
}
// PersonalAccessTokenTypeString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func PersonalAccessTokenTypeString(s string) (PersonalAccessTokenType, error) {
if val, ok := _PersonalAccessTokenTypeNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _PersonalAccessTokenTypeNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to PersonalAccessTokenType values", s)
}
// PersonalAccessTokenTypeValues returns all values of the enum
func PersonalAccessTokenTypeValues() []PersonalAccessTokenType {
return _PersonalAccessTokenTypeValues
}
// PersonalAccessTokenTypeStrings returns a slice of all String values of the enum
func PersonalAccessTokenTypeStrings() []string {
strs := make([]string, len(_PersonalAccessTokenTypeNames))
copy(strs, _PersonalAccessTokenTypeNames)
return strs
}
// IsAPersonalAccessTokenType returns "true" if the value is listed in the enum definition. "false" otherwise
func (i PersonalAccessTokenType) IsAPersonalAccessTokenType() bool {
for _, v := range _PersonalAccessTokenTypeValues {
if i == v {
return true
}
}
return false
}
+108 -93
View File
@@ -4,6 +4,8 @@ import (
"time" "time"
"golang.org/x/text/language" "golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/crypto"
) )
type User struct { type User struct {
@@ -15,48 +17,50 @@ type User struct {
CreatedAt time.Time `json:"createdAt,omitzero" db:"created_at"` CreatedAt time.Time `json:"createdAt,omitzero" db:"created_at"`
UpdatedAt time.Time `json:"updatedAt,omitzero" db:"updated_at"` UpdatedAt time.Time `json:"updatedAt,omitzero" db:"updated_at"`
Machine *MachineUser `json:"machine,omitempty" db:"machine"` Machine *MachineUser `json:"machine,omitempty" db:"-"`
Human *HumanUser `json:"human,omitempty" db:"human"` Human *HumanUser `json:"human,omitempty" db:"-"`
Metadata []*UserMetadata `json:"metadata,omitempty" db:"metadata"` Metadata []*Metadata `json:"metadata,omitempty" db:"metadata"`
} }
type MachineUser struct { type MachineUser struct {
Name string `json:"name,omitempty" db:"name"` Name string `json:"name,omitempty" db:"-"`
Description string `json:"description,omitempty" db:"description"` Description string `json:"description,omitempty" db:"-"`
Secret string `json:"secret,omitempty" db:"secret"` Secret string `json:"secret,omitempty" db:"-"`
AccessTokenType PersonalAccessTokenType `json:"access_token_type,omitempty" db:"access_token_type"` AccessTokenType AccessTokenType `json:"accessTokenType,omitempty" db:"-"`
PATs []*PersonalAccessToken `json:"pats,omitempty" db:"pats"` PATs []*PersonalAccessToken `json:"pats,omitempty" db:"-"`
Keys []*MachineKey `json:"keys,omitempty" db:"keys"` Keys []*MachineKey `json:"keys,omitempty" db:"-"`
} }
type HumanUser struct { type HumanUser struct {
FirstName string `json:"firstName,omitempty" db:"first_name"` FirstName string `json:"firstName,omitempty" db:"-"`
LastName string `json:"lastName,omitempty" db:"last_name"` LastName string `json:"lastName,omitempty" db:"-"`
Nickname string `json:"nickname,omitempty" db:"nickname"` Nickname string `json:"nickname,omitempty" db:"-"`
DisplayName string `json:"displayName,omitempty" db:"display_name"` DisplayName string `json:"displayName,omitempty" db:"-"`
PreferredLanguage language.Tag `json:"preferredLanguage,omitzero" db:"preferred_language"` PreferredLanguage language.Tag `json:"preferredLanguage,omitzero" db:"-"`
Gender HumanGender `json:"gender,omitempty" db:"gender"` Gender HumanGender `json:"gender,omitempty" db:"-"`
AvatarKey string `json:"avatarKey,omitempty" db:"avatar_key"` AvatarKey string `json:"avatarKey,omitempty" db:"-"`
MultifactorInitializationSkippedAt time.Time `json:"multifactorInitializationSkippedAt,omitzero" db:"multifactor_initialization_skipped_at"` MultifactorInitializationSkippedAt time.Time `json:"multifactorInitializationSkippedAt,omitzero" db:"-"`
Email HumanEmail `json:"email,omitzero" db:"email"` Email HumanEmail `json:"email,omitzero" db:"-"`
Phone *HumanPhone `json:"phone,omitempty" db:"phone"` Phone *HumanPhone `json:"phone,omitempty" db:"-"`
Passkeys []*Passkey `json:"passkeys,omitempty" db:"passkeys"` Passkeys []*Passkey `json:"passkeys,omitempty" db:"-"`
Password HumanPassword `json:"password,omitzero" db:"password"` Password HumanPassword `json:"password,omitzero" db:"-"`
TOTP HumanTOTP `json:"totp,omitzero" db:"totp"` TOTP *HumanTOTP `json:"totp,omitempty" db:"-"`
IdentityProviderLinks []*IdentityProviderLink `json:"identityProviderLinks,omitempty" db:"identity_provider_links"` IdentityProviderLinks []*IdentityProviderLink `json:"identityProviderLinks,omitempty" db:"-"`
Invite *HumanInvite `json:"invite,omitempty" db:"-"`
// Verifications are used if the Login does something on behalf of the user that requires verification // Verifications are used if the Login does something on behalf of the user that requires verification
// e.g. starting passkey registration // e.g. starting passkey registration
Verifications []*Verification `db:"verifications" json:"verifications,omitempty"` Verifications []*Verification `json:"verifications,omitempty" db:"-"`
} }
type UserMetadata struct { type UserMetadata struct {
Metadata Metadata
UserID string `json:"userId,omitempty" db:"user_id"` UserID string `json:"userId,omitempty" db:"-"`
} }
//go:generate enumer -type UserState -transform lower -trimprefix UserState -sql //go:generate enumer -type UserState -transform lower -trimprefix UserState -sql
@@ -83,81 +87,84 @@ const (
) )
type HumanPassword struct { type HumanPassword struct {
// Password is the hashed password // Hash is the hashed password
Password string `json:"-" db:"password"` Hash string `json:"hash" db:"-"`
// IsChangeRequired indicates if the user must change their password // IsChangeRequired indicates if the user must change their password
IsChangeRequired bool `json:"isChangeRequired,omitempty" db:"is_change_required"` IsChangeRequired bool `json:"isChangeRequired,omitempty" db:"-"`
// VerifiedAt is the time when the current password was verified // ChangedAt is the time when the current password was last updated
VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"verified_at"` ChangedAt time.Time `json:"changedAt,omitzero" db:"-"`
// Unverified is the verification data for setting a new password // PendingVerification is the verification data for setting a new password
// If nil, no password change is in progress // If nil, no password change is in progress
Unverified *Verification `json:"-"` PendingVerification *Verification `json:"pendingVerification,omitempty" db:"-"`
// LastSuccessfullyCheckedAt is the time when the password was last successfully checked
LastSuccessfullyCheckedAt *time.Time `json:"lastSuccessfullyCheckedAt,omitzero" db:"-"`
// FailedAttempts is the number of consecutive failed password attempts // FailedAttempts is the number of consecutive failed password attempts
// It is reset to 0 on successful verification // It is reset to 0 on successful verification
FailedAttempts uint8 `json:"failedAttempts,omitempty" db:"failed_attempts"` FailedAttempts uint8 `json:"failedAttempts,omitempty" db:"-"`
} }
type HumanEmail struct { type HumanEmail struct {
Address string `json:"address" db:"email"` Address string `json:"address" db:"-"`
VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"verified_at"` UnverifiedAddress string `json:"unverifiedAddress,omitempty" db:"-"`
OTP OTP `json:"-"` VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"-"`
// Unverified is the verification data for setting a new email OTP OTP `json:"otp" db:"-"`
// PendingVerification is the verification data for UnverifiedAddress
// If nil, no email change is in progress // If nil, no email change is in progress
Unverified *Verification `json:"-"` PendingVerification *Verification `json:"pendingVerification,omitempty" db:"-"`
} }
type HumanPhone struct { type HumanPhone struct {
Number string `json:"number" db:"phone"` Number string `json:"number" db:"-"`
VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"verified_at"` UnverifiedNumber string `json:"unverifiedNumber,omitempty" db:"-"`
OTP OTP `json:"-"` VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"-"`
// Unverified is the verification data for setting a new phone number OTP OTP `json:"otp,omitzero" db:"-"`
// PendingVerification is the verification data for setting a new phone number
// If nil, no phone change is in progress // If nil, no phone change is in progress
Unverified *Verification `json:"-"` PendingVerification *Verification `json:"pendingVerification,omitempty" db:"-"`
} }
type HumanTOTP struct { type HumanTOTP struct {
VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"verified_at"` VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"-"`
Secret *crypto.CryptoValue `json:"secret,omitempty" db:"-"`
// LastSuccessfullyCheckedAt is the time when the TOTP was last successfully checked
LastSuccessfullyCheckedAt *time.Time `json:"lastSuccessfullyCheckedAt,omitzero" db:"-"`
LastSuccessfullyCheckedAt time.Time `json:"lastSuccessfullyCheckedAt,omitzero" db:"last_successfully_checked_at"` // FailedAttempts is the number of consecutive failed password attempts
// Check is the verified secret // It is reset to 0 on successful verification
Check *Check `json:"-"` FailedAttempts uint8 `json:"failedAttempts,omitempty" db:"-"`
// Unverified is the unverified secret
Unverified *Verification `json:"-"`
} }
type OTP struct { type OTP struct {
EnabledAt time.Time `json:"enabledAt,omitzero" db:"enabled_at"` EnabledAt time.Time `json:"enabledAt,omitzero" db:"-"`
LastSuccessfullyCheckedAt time.Time `json:"lastSuccessfullyCheckedAt,omitzero" db:"last_successfully_checked_at"` // LastSuccessfullyCheckedAt is the time when the OTP was last successfully checked
// Check is the currently active OTP check LastSuccessfullyCheckedAt *time.Time `json:"lastSuccessfullyCheckedAt,omitzero" db:"-"`
// If nil, no OTP check is active // FailedAttempts is the number of consecutive failed password attempts
Check *Check `json:"-"` // It is reset to 0 on successful verification
FailedAttempts uint8 `json:"failedAttempts,omitempty" db:"-"`
} }
type PersonalAccessToken struct { type PersonalAccessToken struct {
ID string `json:"id" db:"id"` ID string `json:"id" db:"-"`
CreatedAt time.Time `json:"createdAt,omitzero" db:"created_at"` CreatedAt time.Time `json:"createdAt,omitzero" db:"-"`
ExpiresAt time.Time `json:"expiresAt,omitzero" db:"expires_at"` ExpiresAt time.Time `json:"expiresAt,omitzero" db:"-"`
Type PersonalAccessTokenType `json:"type" db:"type"` Scopes []string `json:"scopes" db:"-"`
PublicKey string `json:"-" db:"public_key"`
Scopes []string `json:"scopes" db:"scopes"`
} }
//go:generate enumer -type PersonalAccessTokenType -transform lower -trimprefix PersonalAccessTokenType //go:generate enumer -type AccessTokenType -transform lower -trimprefix AccessTokenType
type AccessTokenType uint8
type PersonalAccessTokenType uint8
const ( const (
PersonalAccessTokenTypeUnspecified PersonalAccessTokenType = iota AccessTokenTypeUnspecified AccessTokenType = iota
PersonalAccessTokenTypeBearer AccessTokenTypeBearer
PersonalAccessTokenTypeJWT AccessTokenTypeJWT
) )
type MachineKey struct { type MachineKey struct {
ID string `json:"id" db:"id"` ID string `json:"id" db:"-"`
PublicKey []byte `json:"-" db:"public_key"` PublicKey []byte `json:"publicKey" db:"-"`
CreatedAt time.Time `json:"createdAt,omitzero" db:"created_at"` CreatedAt time.Time `json:"createdAt,omitzero" db:"-"`
ExpiresAt time.Time `json:"expiresAt,omitzero" db:"expires_at"` ExpiresAt time.Time `json:"expiresAt,omitzero" db:"-"`
Type MachineKeyType `json:"type" db:"type"` Type MachineKeyType `json:"type" db:"-"`
} }
//go:generate enumer -type MachineKeyType -transform lower -trimprefix MachineKeyType //go:generate enumer -type MachineKeyType -transform lower -trimprefix MachineKeyType
@@ -165,35 +172,34 @@ type MachineKey struct {
type MachineKeyType uint8 type MachineKeyType uint8
const ( const (
MachineKeyTypeUnspecified MachineKeyType = iota MachineKeyTypeNone MachineKeyType = iota
MachineKeyTypeJSON MachineKeyTypeJSON
MachineKeyTypeNone
) )
type Passkey struct { type Passkey struct {
ID string `json:"id" db:"id"` ID string `json:"id" db:"-"`
KeyID []byte `json:"-" db:"key_id"` KeyID []byte `json:"keyId" db:"-"`
Name string `json:"name" db:"name"` Name string `json:"name" db:"-"`
SignCount uint32 `json:"-" db:"sign_count"` SignCount uint32 `json:"signCount" db:"-"`
PublicKey []byte `json:"-" db:"public_key"` PublicKey []byte `json:"publicKey" db:"-"`
AttestationType string `json:"attestationType" db:"attestation_type"` AttestationType string `json:"attestationType" db:"-"`
AuthenticatorAttestationGUID []byte `json:"aaGuid" db:"authenticator_attestation_guid"` AuthenticatorAttestationGUID []byte `json:"aaGuid" db:"-"`
Type PasskeyType `json:"type" db:"type"` Type PasskeyType `json:"type" db:"-"`
CreatedAt time.Time `json:"createdAt,omitzero" db:"created_at"` CreatedAt time.Time `json:"createdAt,omitzero" db:"-"`
UpdatedAt time.Time `json:"updatedAt,omitzero" db:"updated_at"` UpdatedAt time.Time `json:"updatedAt,omitzero" db:"-"`
VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"verified_at"` VerifiedAt time.Time `json:"verifiedAt,omitzero" db:"-"`
// Challenge is used during device registration // Challenge is used during device registration
Challenge []byte `json:"-" db:"challenge"` Challenge []byte `json:"challenge" db:"-"`
// RelyingPartyID is used during device registration // RelyingPartyID is used during device registration
RelyingPartyID string `json:"-" db:"relying_party_id"` RelyingPartyID string `json:"rpId" db:"-"`
// Initialization is used during user registration // Initialization is used during user registration
Initialization *Verification `json:"-" db:"initialization"` Initialization *Verification `json:"-" db:"-"`
} }
//go:generate enumer -type PasskeyType -transform lower -trimprefix PasskeyType //go:generate enumer -type PasskeyType -transform lower -trimprefix PasskeyType -json -sql
type PasskeyType uint8 type PasskeyType uint8
@@ -204,12 +210,12 @@ const (
) )
type IdentityProviderLink struct { type IdentityProviderLink struct {
ProviderID string `json:"providerId" db:"provider_id"` ProviderID string `json:"providerId" db:"-"`
ProvidedUserID string `json:"providedUserId" db:"provided_user_id"` ProvidedUserID string `json:"providedUserId" db:"-"`
ProvidedUsername string `json:"providedUsername" db:"provided_username"` ProvidedUsername string `json:"providedUsername" db:"-"`
CreatedAt time.Time `json:"createdAt,omitzero" db:"created_at"` CreatedAt time.Time `json:"createdAt,omitzero" db:"-"`
UpdatedAt time.Time `json:"updatedAt,omitzero" db:"updated_at"` UpdatedAt time.Time `json:"updatedAt,omitzero" db:"-"`
} }
//go:generate enumer -type UserType -transform lower -trimprefix UserType //go:generate enumer -type UserType -transform lower -trimprefix UserType
@@ -221,3 +227,12 @@ const (
UserTypeHuman UserTypeHuman
UserTypeMachine UserTypeMachine
) )
type HumanInvite struct {
AcceptedAt time.Time `json:"acceptedAt,omitzero" db:"-"`
// PendingVerification is the verification data for UnverifiedAddress
// If nil, no email change is in progress
PendingVerification *Verification `json:"pendingVerification,omitempty" db:"-"`
// FailedAttempts is the number of consecutive failed invite attempts
FailedAttempts uint8 `json:"failedAttempts,omitempty" db:"-"`
}
@@ -0,0 +1,60 @@
package domain
import (
"context"
"time"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
type UserIdentityProviderLink struct {
InstanceID string `json:"instanceID" db:"instance_id"`
UserID string `json:"userID" db:"user_id"`
IdentityProviderID string `json:"identityProviderID" db:"identity_provider_id"`
ProvidedID string `json:"providedID" db:"provided_id"`
ProvidedUsername string `json:"providedUsername" db:"provided_username"`
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
UpdatedAt time.Time `json:"updatedAt,omitempty" db:"updated_at"`
}
//go:generate mockgen -typed -package domainmock -destination ./mock/user_identity_provider_link.mock.go . UserIdentityProviderLinkRepository
type UserIdentityProviderLinkRepository interface {
Repository
userIdentityProviderLinkColumns
userIdentityProviderLinkConditions
userIdentityProviderLinkChanges
Get(ctx context.Context, client database.QueryExecutor, condition database.Condition, opts ...database.QueryOption) (*UserIdentityProviderLink, error)
List(ctx context.Context, client database.QueryExecutor, condition database.Condition, opts ...database.QueryOption) ([]*UserIdentityProviderLink, error)
Create(ctx context.Context, client database.QueryExecutor, link *UserIdentityProviderLink) error
Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error)
Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error)
}
type userIdentityProviderLinkColumns interface {
InstanceIDColumn() database.Column
UserIDColumn() database.Column
IdentityProviderIDColumn() database.Column
ProvidedIDColumn() database.Column
ProvidedUsernameColumn() database.Column
CreatedAtColumn() database.Column
UpdatedAtColumn() database.Column
}
type userIdentityProviderLinkConditions interface {
PrimaryKeyCondition(instanceID, idpID, providedID string) database.Condition
InstanceIDCondition(op database.TextOperation, id string) database.Condition
UserIDCondition(op database.TextOperation, id string) database.Condition
IdentityProviderIDCondition(op database.TextOperation, id string) database.Condition
ProvidedIDCondition(op database.TextOperation, id string) database.Condition
ProvidedUsernameCondition(op database.TextOperation, username string) database.Condition
}
type userIdentityProviderLinkChanges interface {
SetProvidedUsername(username string) database.Change
SetUpdatedAt(updatedAt time.Time) database.Change
SetProvidedUserID(providedID string) database.Change
}
+135 -76
View File
@@ -7,6 +7,7 @@ import (
"golang.org/x/text/language" "golang.org/x/text/language"
"github.com/zitadel/zitadel/backend/v3/storage/database" "github.com/zitadel/zitadel/backend/v3/storage/database"
"github.com/zitadel/zitadel/internal/crypto"
) )
//go:generate mockgen -typed -package domainmock -destination ./mock/user.mock.go . UserRepository //go:generate mockgen -typed -package domainmock -destination ./mock/user.mock.go . UserRepository
@@ -22,13 +23,6 @@ type UserRepository interface {
Human() HumanUserRepository Human() HumanUserRepository
Machine() MachineUserRepository Machine() MachineUserRepository
LoadMetadata() UserRepository
LoadPasskeys() UserRepository
LoadIdentityProviderLinks() UserRepository
LoadVerifications() UserRepository
LoadPATs() UserRepository
LoadKeys() UserRepository
userConditions userConditions
userChanges userChanges
userColumns userColumns
@@ -37,18 +31,18 @@ type UserRepository interface {
type userConditions interface { type userConditions interface {
PrimaryKeyCondition(instanceID, userID string) database.Condition PrimaryKeyCondition(instanceID, userID string) database.Condition
InstanceIDCondition(instanceID string) database.Condition InstanceIDCondition(instanceID string) database.Condition
OrgIDCondition(orgID string) database.Condition OrganizationIDCondition(orgID string) database.Condition
IDCondition(userID string) database.Condition IDCondition(userID string) database.Condition
UsernameCondition(op database.TextOperation, username string) database.Condition UsernameCondition(op database.TextOperation, username string) database.Condition
StateCondition(state UserState) database.Condition StateCondition(state UserState) database.Condition
TypeCondition(userType UserType) database.Condition TypeCondition(userType UserType) database.Condition
LoginNameCondition(op database.TextOperation, loginName string) database.Condition LoginNameCondition(op database.TextOperation, loginName string) database.Condition
userMetadataConditions ExistsMetadata(condition database.Condition) database.Condition
MetadataConditions() UserMetadataConditions
} }
type userMetadataConditions interface { type UserMetadataConditions interface {
ExistsMetadata(condition database.Condition) database.Condition
MetadataKeyCondition(op database.TextOperation, key string) database.Condition MetadataKeyCondition(op database.TextOperation, key string) database.Condition
MetadataValueCondition(op database.BytesOperation, value []byte) database.Condition MetadataValueCondition(op database.BytesOperation, value []byte) database.Condition
} }
@@ -62,8 +56,8 @@ type userChanges interface {
// SetUpdatedAt sets the updated at field // SetUpdatedAt sets the updated at field
// This is used to replay events // This is used to replay events
SetUpdatedAt(updatedAt time.Time) database.Change SetUpdatedAt(updatedAt time.Time) database.Change
// AddMetadata adds metadata for the user // SetMetadata adds metadata for the user
AddMetadata(metadata ...*Metadata) database.Change SetMetadata(metadata ...*Metadata) database.Change
// RemoveMetadata removes the metadata for the user // RemoveMetadata removes the metadata for the user
// Use one of the following conditions to specify which metadata to remove: // Use one of the following conditions to specify which metadata to remove:
// - [userMetadataConditions.MetadataKeyCondition] // - [userMetadataConditions.MetadataKeyCondition]
@@ -74,6 +68,8 @@ type userChanges interface {
type userColumns interface { type userColumns interface {
PrimaryKeyColumns() []database.Column PrimaryKeyColumns() []database.Column
InstanceIDColumn() database.Column
IDColumn() database.Column
UsernameColumn() database.Column UsernameColumn() database.Column
StateColumn() database.Column StateColumn() database.Column
TypeColumn() database.Column TypeColumn() database.Column
@@ -98,18 +94,32 @@ type humanConditions interface {
NicknameCondition(op database.TextOperation, nickname string) database.Condition NicknameCondition(op database.TextOperation, nickname string) database.Condition
DisplayNameCondition(op database.TextOperation, displayName string) database.Condition DisplayNameCondition(op database.TextOperation, displayName string) database.Condition
PreferredLanguageCondition(lang language.Tag) database.Condition PreferredLanguageCondition(lang language.Tag) database.Condition
EmailCondition(op database.TextOperation, email string) database.Condition
PhoneCondition(op database.TextOperation, phone string) database.Condition
PasskeyIDCondition(passkeyID string) database.Condition
IdentityProviderIDCondition(idpID string) database.Condition
ProvidedUserIDCondition(providedUserID string) database.Condition
ProvidedUsernameCondition(username string) database.Condition
humanPasskeyConditions // EmailCondition searches for the given email in both verified and unverified email columns
EmailCondition(op database.TextOperation, email string) database.Condition
// UnverifiedEmailCondition searches for the given email in the unverified email column
UnverifiedEmailCondition(op database.TextOperation, email string) database.Condition
// VerifiedEmailCondition searches for the given email in the verified email column
VerifiedEmailCondition(op database.TextOperation, email string) database.Condition
// PhoneCondition searches for the given phone number in both verified and unverified phone number columns
PhoneCondition(op database.TextOperation, phone string) database.Condition
// UnverifiedPhoneCondition searches for the given phone number in the unverified phone number column
UnverifiedPhoneCondition(op database.TextOperation, phone string) database.Condition
// VerifiedPhoneCondition searches for the given phone number in the verified phone number column
VerifiedPhoneCondition(op database.TextOperation, phone string) database.Condition
ExistsPasskey(condition database.Condition) database.Condition
PasskeyConditions() HumanPasskeyConditions
// ExistsVerification(condition database.Condition) database.Condition
// VerificationConditions() HumanVerificationConditions
ExistsIdentityProviderLink(condition database.Condition) database.Condition
IdentityProviderLinkConditions() HumanIdentityProviderLinkConditions
} }
type humanChanges interface { type humanChanges interface {
userChanges userChanges
// SetFirstName sets the first name field // SetFirstName sets the first name field
SetFirstName(firstName string) database.Change SetFirstName(firstName string) database.Change
// SetLastName sets the last name field // SetLastName sets the last name field
@@ -127,99 +137,148 @@ type humanChanges interface {
// SetAvatarKey sets the avatar key field // SetAvatarKey sets the avatar key field
// If avatarKey is nil, it will be set to NULL in the database // If avatarKey is nil, it will be set to NULL in the database
SetAvatarKey(avatarKey *string) database.Change SetAvatarKey(avatarKey *string) database.Change
// SetMultifactorInitializationSkippedAt sets the multifactor initialization skipped at field // SkipMultifactorInitializationAt sets the multifactor initialization skipped at field
SetMultifactorInitializationSkippedAt(skippedAt time.Time) database.Change SkipMultifactorInitializationAt(skippedAt time.Time) database.Change
// SkipMultifactorInitializationAt sets the multifactor initialization skipped at field
// SetPassword sets the password based on the verification SkipMultifactorInitialization() database.Change
SetPassword(verification VerificationType) database.Change
// SetPasswordChangeRequired sets whether a password change is required
SetPasswordChangeRequired(required bool) database.Change
// CheckPassword sets the password check based on the check type
// * [CheckTypeFailed] increments failed attempts
// * [CheckTypeSucceeded] to mark the check as succeeded, removes the check and updates verified at time
CheckPassword(check PasswordCheckType) database.Change
// SetVerification sets the verification based on the verification type // SetVerification sets the verification based on the verification type
SetVerification(id string, verification VerificationType) database.Change SetVerification(verification VerificationType) database.Change
humanPasswordChanges
humanEmailChanges humanEmailChanges
humanPhoneChanges humanPhoneChanges
humanTOTPChanges humanTOTPChanges
identityProviderLinkChanges identityProviderLinkChanges
humanPasskeyChanges humanPasskeyChanges
inviteChanges
}
type humanPasswordChanges interface {
// SetPassword overwrites the password field.
// It resets the password verification and the last successful password check time.
SetPassword(hash string) database.Change
// SetResetPassword handles the password reset process based on the verification type:
// * [VerificationTypeInit]: to initialize password reset, a verification will be created. The current password remains unchanged
// * [VerificationTypeSucceeded]: to mark the password as reset and remove the verification. The current password remains unchanged use [humanPasswordChanges.SetPassword] to set the new password.
// * [VerificationTypeUpdate]: to update the existing password reset verification. If a new code is requested, use [VerificationTypeInit].
// * [VerificationTypeFailed]: to increment the failed attempts of the verification.
SetResetPasswordVerification(verification VerificationType) database.Change
// SetPasswordChangeRequired sets whether a password change is required
SetPasswordChangeRequired(required bool) database.Change
// SetLastSuccessfulPasswordCheck sets the last successful password check time
// If checkedAt is zero, it will be set to NOW()
SetLastSuccessfulPasswordCheck(checkedAt time.Time) database.Change
// IncrementPasswordFailedAttempts increments the password failed attempts
IncrementPasswordFailedAttempts() database.Change
// ResetPasswordFailedAttempts resets the password failed attempts
ResetPasswordFailedAttempts() database.Change
} }
type humanEmailChanges interface { type humanEmailChanges interface {
// SetEmail sets the email based on the verification // SetEmail sets the verified email address
// * [VerificationTypeInit] to initialize email verification, previously verified email remains verified SetEmail(address string) database.Change
// * [VerificationTypeVerified] to mark email as verified, a verification must exist // SetUnverifiedEmail sets the unverified email address
// * [VerificationTypeUpdate] to update email verification, a verification must exist (e.g. resend code) // Make sure to add [humanEmailChanges.SetEmailVerification] to the changes list.
// * [VerificationTypeSkipped] to skip email verification, existing verification is removed (e.g. admin set email) SetUnverifiedEmail(address string) database.Change
SetEmail(verification VerificationType) database.Change // SetEmailVerification sets the email verification based on the verification
// CheckEmailOTP sets the OTP Email based on the check // * [VerificationTypeInit]: to overwrite a email verification, the previously verified email address remains verified.
// * [CheckTypeInit] to initialize a new check, previous check is overwritten // * [VerificationTypeSucceeded]: to mark the unverified email address as verified and remove the verification.
// * [CheckTypeFailed] increments failed attempts // * [VerificationTypeUpdate]: to update the existing email verification. If a new code is requested, use [VerificationTypeInit].
// * [CheckTypeSucceeded] to mark the check as succeeded, removes the check and updates verified at time // * [VerificationTypeFailed]: to increment the failed attempts of the verification.
CheckEmailOTP(check CheckType) database.Change SetEmailVerification(verification VerificationType) database.Change
// EnableEmailOTPAt enables the OTP Email // EnableEmailOTPAt enables the email OTP
// If enabledAt is zero, it will be set to NOW() // If enabledAt is zero, it will be set to NOW()
EnableEmailOTPAt(enabledAt time.Time) database.Change EnableEmailOTPAt(enabledAt time.Time) database.Change
// EnableEmailOTP sets the enabled at time to NOW() // EnableEmailOTP sets the enabled at time to NOW()
EnableEmailOTP() database.Change EnableEmailOTP() database.Change
// DisableEmailOTP clears the enabled at time // DisableEmailOTP clears the enabled at time
DisableEmailOTP() database.Change DisableEmailOTP() database.Change
// SetLastSuccessfulEmailOTPCheck sets the last successful email OTP check time
// If checkedAt is zero, it will be set to NOW()
// It resets the failed attempts
SetLastSuccessfulEmailOTPCheck(checkedAt time.Time) database.Change
// IncrementEmailOTPFailedAttempts increments the email OTP failed attempts
IncrementEmailOTPFailedAttempts() database.Change
// ResetEmailOTPFailedAttempts resets the email OTP failed attempts
ResetEmailOTPFailedAttempts() database.Change
} }
type humanPhoneChanges interface { type humanPhoneChanges interface {
// SetPhone sets the phone based on the verification // SetPhone sets the verified phone number
// * [VerificationTypeInit] to initialize phone verification, previously verified phone remains verified SetPhone(number string) database.Change
// * [VerificationTypeVerified] to mark phone as verified, a verification must exist // SetUnverifiedPhone sets the unverified phone number
// * [VerificationTypeUpdate] to update phone verification, a verification must exist (e.g. resend code) // Make sure to add [humanPhoneChanges.SetPhoneVerification] to the changes list.
// * [VerificationTypeSkipped] to skip phone verification, existing verification is removed (e.g. admin set phone) SetUnverifiedPhone(number string) database.Change
SetPhone(verification VerificationType) database.Change // SetPhoneVerification sets the phone verification based on the verification
// * [VerificationTypeInit]: to overwrite a phone verification, the previously verified phone number remains verified.
// * [VerificationTypeSucceeded]: to mark the unverified phone number as verified and remove the verification.
// * [VerificationTypeUpdate]: to update the existing phone verification. If a new code is requested, use [VerificationTypeInit].
// * [VerificationTypeFailed]: to increment the failed attempts of the verification.
SetPhoneVerification(verification VerificationType) database.Change
// RemovePhone removes the phone number // RemovePhone removes the phone number
RemovePhone() database.Change RemovePhone() database.Change
// CheckSMSOTP sets the OTP SMS based on the check // EnableSMSOTPAt enables the SMS OTP
// * [CheckTypeInit] to initialize a new check, previous check is overwritten
// * [CheckTypeFailed] increments failed attempts
// * [CheckTypeSucceeded] to mark the check as succeeded, removes the check and updates verified at time
CheckSMSOTP(check CheckType) database.Change
// EnableSMSOTPAt enables the OTP SMS
// If enabledAt is zero, it will be set to NOW() // If enabledAt is zero, it will be set to NOW()
EnableSMSOTPAt(enabledAt time.Time) database.Change EnableSMSOTPAt(enabledAt time.Time) database.Change
// EnableSMSOTP sets the enabled at time to NOW() // EnableSMSOTP sets the enabled at time to NOW()
EnableSMSOTP() database.Change EnableSMSOTP() database.Change
// DisableSMSOTP clears the enabled at time // DisableSMSOTP clears the enabled at time
DisableSMSOTP() database.Change DisableSMSOTP() database.Change
// SetLastSuccessfulSMSOTPCheck sets the last successful SMS OTP check time
// If checkedAt is zero, it will be set to NOW()
// It resets the failed attempts
SetLastSuccessfulSMSOTPCheck(checkedAt time.Time) database.Change
// IncrementSMSOTPFailedAttempts increments the SMS OTP failed attempts
IncrementSMSOTPFailedAttempts() database.Change
// ResetSMSOTPFailedAttempts resets the SMS OTP failed attempts
ResetSMSOTPFailedAttempts() database.Change
} }
type humanTOTPChanges interface { type humanTOTPChanges interface {
// SetTOTP changes the TOTP secret based on the verification // SetTOTP changes the TOTP secret and verification timestamp
// * [VerificationTypeInit] to initialize totp verification, previously verified totp remains verified SetTOTPSecret(secret *crypto.CryptoValue) database.Change
// * [VerificationTypeVerified] to mark totp as verified, a verification must exist // SetTOTPVerifiedAt sets the TOTP verified at time
// * [VerificationTypeUpdate] to update totp verification, a verification must exist (e.g. resend code) // If verifiedAt is zero, it will be set to NOW()
// * [VerificationTypeSkipped] to skip totp verification, existing verification is removed (e.g. admin set totp) SetTOTPVerifiedAt(verifiedAt time.Time) database.Change
SetTOTP(verification VerificationType) database.Change
// SetTOTPCheck sets the TOTP check based on the check type
// * [CheckTypeFailed] increments failed attempts
// * [CheckTypeSucceeded] to mark the check as succeeded, removes the check and updates verified at time
// * [CheckTypeInit] is not allowed for TOTP
CheckTOTP(check CheckType) database.Change
// RemoveTOTP removes the TOTP // RemoveTOTP removes the TOTP
RemoveTOTP() database.Change RemoveTOTP() database.Change
// SetLastSuccessfulTOTPCheck sets the last successful TOTP check time
// If checkedAt is zero, it will be set to NOW()
// It resets the failed attempts
SetLastSuccessfulTOTPCheck(checkedAt time.Time) database.Change
// IncrementTOTPFailedAttempts increments the TOTP failed attempts
IncrementTOTPFailedAttempts() database.Change
// ResetTOTPFailedAttempts resets the TOTP failed attempts
ResetTOTPFailedAttempts() database.Change
} }
type identityProviderLinkChanges interface { type identityProviderLinkChanges interface {
// AddIdentityProviderLink adds or updates an identity provider link // AddIdentityProviderLink adds or updates an identity provider link
AddIdentityProviderLink(link *IdentityProviderLink) database.Change AddIdentityProviderLink(link *IdentityProviderLink) database.Change
UpdateIdentityProviderLink(changes ...database.Change) database.Change UpdateIdentityProviderLink(condition database.Condition, changes ...database.Change) database.Change
// RemoveIdentityProviderLink removes an identity provider link based on the condition // RemoveIdentityProviderLink removes an identity provider link based on the condition
RemoveIdentityProviderLink(providerID, providedUserID string) database.Change RemoveIdentityProviderLink(providerID, providedUserID string) database.Change
// SetIdentityProviderLinkUsername sets the username for an identity provider link // SetIdentityProviderLinkUsername sets the username for an identity provider link
SetIdentityProviderLinkUsername(providerID, providedUserID, username string) database.Change SetIdentityProviderLinkUsername(username string) database.Change
// SetIdentityProviderLinkProvidedID sets the provided user ID for an identity provider link // SetIdentityProviderLinkProvidedID sets the provided user ID for an identity provider link
SetIdentityProviderLinkProvidedID(providerID, currentProvidedUserID, newProvidedUserID string) database.Change SetIdentityProviderLinkProvidedID(providedUserID string) database.Change
}
type inviteChanges interface {
// SetInviteVerification sets the invite verification based on the verification type:
// * [VerificationTypeInit]: to initialize invite verification, a verification will be created. The current accepted at time remains unchanged
// * [VerificationTypeSucceeded]: to mark the invite as accepted and remove the verification. The current accepted at time remains unchanged use [inviteChanges.AcceptInvite] to set the accepted at time.
// * [VerificationTypeUpdate]: to update the existing invite verification. If a new code is requested, use [VerificationTypeInit].
// * [VerificationTypeFailed]: to increment the failed attempts of the verification.
SetInviteVerification(verification VerificationType) database.Change
}
type HumanIdentityProviderLinkConditions interface {
ProviderIDCondition(providerID string) database.Condition
ProvidedUserIDCondition(providedUserID string) database.Condition
ProvidedUsernameCondition(op database.TextOperation, username string) database.Condition
} }
type humanColumns interface { type humanColumns interface {
@@ -256,7 +315,7 @@ type machineChanges interface {
// nil will set the secret to NULL in the database // nil will set the secret to NULL in the database
SetSecret(secret *string) database.Change SetSecret(secret *string) database.Change
// SetAccessTokenType sets the personal access token type field // SetAccessTokenType sets the personal access token type field
SetAccessTokenType(tokenType PersonalAccessTokenType) database.Change SetAccessTokenType(tokenType AccessTokenType) database.Change
// AddKey adds a key for the service account // AddKey adds a key for the service account
AddKey(key *MachineKey) database.Change AddKey(key *MachineKey) database.Change
@@ -273,11 +332,11 @@ type machineColumns interface {
userColumns userColumns
} }
type humanPasskeyConditions interface { type HumanPasskeyConditions interface {
PasskeyIDCondition(passkeyID string) database.Condition IDCondition(passkeyID string) database.Condition
PasskeyKeyIDCondition(keyID string) database.Condition KeyIDCondition(keyID string) database.Condition
PasskeyChallengeCondition(challenge string) database.Condition ChallengeCondition(challenge []byte) database.Condition
PasskeyTypeCondition(passkeyType PasskeyType) database.Condition TypeCondition(passkeyType PasskeyType) database.Condition
} }
type humanPasskeyChanges interface { type humanPasskeyChanges interface {
+38 -19
View File
@@ -1,13 +1,18 @@
package domain package domain
import "time" import (
"time"
"github.com/zitadel/zitadel/internal/crypto"
)
type Verification struct { type Verification struct {
Value *string `db:"value"` ID string `json:"id" db:"id"`
Code []byte `db:"code"` Code *crypto.CryptoValue `json:"code" db:"code"`
ExpiresAt *time.Time `db:"expires_at"` CreatedAt time.Time `json:"createdAt" db:"created_at"`
FailedAttempts uint8 `db:"failed_attempts"` UpdatedAt time.Time `json:"updatedAt" db:"updated_at"`
VerifiedAt time.Time `db:"verified_at"` ExpiresAt *time.Time `json:"expiresAt" db:"expires_at"`
FailedAttempts uint8 `json:"failedAttempts" db:"failed_attempts"`
} }
type VerificationType interface { type VerificationType interface {
@@ -16,15 +21,16 @@ type VerificationType interface {
// VerificationTypeInit indicates that an object which needs verification is created. // VerificationTypeInit indicates that an object which needs verification is created.
type VerificationTypeInit struct { type VerificationTypeInit struct {
// ID is the ID of the verification.
// The id must be set if the the object can have multiple verifications.
ID *string
// CreatedAt is the time when the verification was created. // CreatedAt is the time when the verification was created.
// If zero, the current time will be used. // If zero, the current time will be used.
CreatedAt time.Time CreatedAt time.Time
// Expiry is the duration after which the verification expires. // Expiry is the duration after which the verification expires.
Expiry *time.Duration Expiry *time.Duration
// Code is the code to be used for verification. // Code is the code to be used for verification.
Code []byte Code *crypto.CryptoValue
// Value is the value to be set after successful verification.
Value *string
} }
// isVerificationType implements [VerificationType]. // isVerificationType implements [VerificationType].
@@ -32,24 +38,31 @@ func (v *VerificationTypeInit) isVerificationType() {}
var _ VerificationType = (*VerificationTypeInit)(nil) var _ VerificationType = (*VerificationTypeInit)(nil)
// VerificationTypeVerified indicates that the verification was successful. // VerificationTypeSucceeded indicates that the verification was successful.
// If VerifiedAt is zero, the current time will be used. // If VerifiedAt is zero, the current time will be used.
// If the Value of the verification is present, it is used as the new value to be set. type VerificationTypeSucceeded struct {
type VerificationTypeVerified struct { // ID is the ID of the verification.
// The id must be set if the the object can have multiple verifications.
ID *string
// If zero, the current time will be used.
VerifiedAt time.Time VerifiedAt time.Time
} }
// isVerificationType implements [VerificationType]. // isVerificationType implements [VerificationType].
func (v *VerificationTypeVerified) isVerificationType() {} func (v *VerificationTypeSucceeded) isVerificationType() {}
var _ VerificationType = (*VerificationTypeVerified)(nil) var _ VerificationType = (*VerificationTypeSucceeded)(nil)
// VerificationTypeUpdate updates an existing verification. // VerificationTypeUpdate updates an existing verification.
// Non-nil fields get updated. // Non-nil fields get updated.
type VerificationTypeUpdate struct { type VerificationTypeUpdate struct {
Code []byte // ID is the ID of the verification.
Value *string // The id must be set if the the object can have multiple verifications.
ID *string
Code *crypto.CryptoValue
Expiry *time.Duration Expiry *time.Duration
// If zero, the current time will be used.
UpdatedAt time.Time
} }
// isVerificationType implements [VerificationType]. // isVerificationType implements [VerificationType].
@@ -58,10 +71,12 @@ func (v *VerificationTypeUpdate) isVerificationType() {}
var _ VerificationType = (*VerificationTypeUpdate)(nil) var _ VerificationType = (*VerificationTypeUpdate)(nil)
// VerificationTypeSkipped indicates that the verification was skipped. // VerificationTypeSkipped indicates that the verification was skipped.
// If Value is present, it is used as the new value to be set.
type VerificationTypeSkipped struct { type VerificationTypeSkipped struct {
VerifiedAt time.Time // ID is the ID of the verification.
Value *string // The id must be set if the the object can have multiple verifications.
ID *string
// If zero, the current time will be used.
SkippedAt time.Time
} }
// isVerificationType implements [VerificationType]. // isVerificationType implements [VerificationType].
@@ -70,6 +85,10 @@ func (v *VerificationTypeSkipped) isVerificationType() {}
var _ VerificationType = (*VerificationTypeSkipped)(nil) var _ VerificationType = (*VerificationTypeSkipped)(nil)
type VerificationTypeFailed struct { type VerificationTypeFailed struct {
// ID is the ID of the verification.
// The id must be set if the the object can have multiple verifications.
ID *string
// If zero, the current time will be used.
FailedAt time.Time FailedAt time.Time
} }
+79 -35
View File
@@ -5,12 +5,15 @@ import (
"slices" "slices"
"go.uber.org/mock/gomock" "go.uber.org/mock/gomock"
"github.com/zitadel/zitadel/backend/v3/instrumentation/logging"
) )
// Change represents a change to a column in a database table. // Change represents a change to a column in a database table.
// Its written in the SET clause of an UPDATE statement. // Its written in the SET clause of an UPDATE statement.
type Change interface { type Change interface {
gomock.Matcher gomock.Matcher
argWriter
// Write writes the change to the given statement builder. // Write writes the change to the given statement builder.
Write(builder *StatementBuilder) error Write(builder *StatementBuilder) error
// IsOnColumn checks if the change is on the given column. // IsOnColumn checks if the change is on the given column.
@@ -44,6 +47,25 @@ func (c *change[V]) String() string {
return "database.change" return "database.change"
} }
// WriteArg implements [Change].
func (c change[V]) WriteArg(builder *StatementBuilder) {
err := c.Write(builder)
logging.New(logging.StreamRuntime).Debug("write arg failed", "error", err)
}
// Write implements [Change].
func (c change[V]) Write(builder *StatementBuilder) error {
c.column.WriteUnqualified(builder)
builder.WriteString(" = ")
builder.WriteArg(c.value)
return nil
}
// IsOnColumn implements [Change].
func (c change[V]) IsOnColumn(col Column) bool {
return c.column.Equals(col)
}
var ( var (
_ Change = (*change[string])(nil) _ Change = (*change[string])(nil)
_ gomock.Matcher = (*change[string])(nil) _ gomock.Matcher = (*change[string])(nil)
@@ -67,22 +89,9 @@ func NewChangePtr[V Value](col Column, value *V) Change {
return NewChange(col, *value) return NewChange(col, *value)
} }
// Write implements [Change].
func (c change[V]) Write(builder *StatementBuilder) error {
c.column.WriteUnqualified(builder)
builder.WriteString(" = ")
builder.WriteArg(c.value)
return nil
}
// IsOnColumn implements [Change].
func (c change[V]) IsOnColumn(col Column) bool {
return c.column.Equals(col)
}
type Changes []Change type Changes []Change
func NewChanges(cols ...Change) Change { func NewChanges(cols ...Change) Changes {
return Changes(cols) return Changes(cols)
} }
@@ -152,6 +161,12 @@ func (c Changes) NoChange() bool {
return true return true
} }
// WriteArg implements [Change].
func (c Changes) WriteArg(builder *StatementBuilder) {
err := c.Write(builder)
logging.New(logging.StreamRuntime).Debug("write arg failed", "error", err)
}
var _ Change = Changes(nil) var _ Change = Changes(nil)
func NewChangeToNull(col Column) Change { func NewChangeToNull(col Column) Change {
@@ -194,26 +209,34 @@ func (c *changeToColumn) Write(builder *StatementBuilder) error {
return nil return nil
} }
var _ Change = (*changeToColumn)(nil) // WriteArg implements [Change].
func (c *changeToColumn) WriteArg(builder *StatementBuilder) {
type incrementColumnChange struct { err := c.Write(builder)
column Column logging.New(logging.StreamRuntime).Debug("write arg failed", "error", err)
} }
func NewIncrementColumnChange(col Column) Change { var _ Change = (*changeToColumn)(nil)
return &incrementColumnChange{
type incrementColumnChange[V Value] struct {
column Column
value V
}
func NewIncrementColumnChange[V Value](col Column, value V) *incrementColumnChange[V] {
return &incrementColumnChange[V]{
column: col, column: col,
value: value,
} }
} }
// IsOnColumn implements [Change]. // IsOnColumn implements [Change].
func (i *incrementColumnChange) IsOnColumn(col Column) bool { func (i incrementColumnChange[V]) IsOnColumn(col Column) bool {
return i.column.Equals(col) return i.column.Equals(col)
} }
// Matches implements [Change]. // Matches implements [Change].
func (i *incrementColumnChange) Matches(x any) bool { func (i *incrementColumnChange[V]) Matches(x any) bool {
toMatch, ok := x.(*incrementColumnChange) toMatch, ok := x.(*incrementColumnChange[V])
if !ok { if !ok {
return false return false
} }
@@ -221,20 +244,26 @@ func (i *incrementColumnChange) Matches(x any) bool {
} }
// String implements [Change]. // String implements [Change].
func (i *incrementColumnChange) String() string { func (i incrementColumnChange[V]) String() string {
return "database.incrementColumnChange" return "database.incrementColumnChange"
} }
// Write implements [Change]. // Write implements [Change].
func (i *incrementColumnChange) Write(builder *StatementBuilder) error { func (i incrementColumnChange[V]) Write(builder *StatementBuilder) error {
i.column.WriteUnqualified(builder) i.column.WriteUnqualified(builder)
builder.WriteString(" = ") builder.WriteString(" = ")
i.column.WriteUnqualified(builder) builder.WriteArg(i.value)
builder.WriteString(" + 1") builder.WriteString(" + 1")
return nil return nil
} }
var _ Change = (*incrementColumnChange)(nil) // WriteArg implements [Change].
func (i incrementColumnChange[V]) WriteArg(builder *StatementBuilder) {
err := i.Write(builder)
logging.New(logging.StreamRuntime).Debug("write arg failed", "error", err)
}
var _ Change = (*incrementColumnChange[any])(nil)
func NewChangeToStatement(col Column, stmt func(builder *StatementBuilder)) Change { func NewChangeToStatement(col Column, stmt func(builder *StatementBuilder)) Change {
return &changeToStatement{ return &changeToStatement{
@@ -293,6 +322,12 @@ func (c *changeToStatement) Write(builder *StatementBuilder) error {
return nil return nil
} }
// WriteArg implements [Change].
func (c *changeToStatement) WriteArg(builder *StatementBuilder) {
err := c.Write(builder)
logging.New(logging.StreamRuntime).Debug("write arg failed", "error", err)
}
var _ Change = (*changeToStatement)(nil) var _ Change = (*changeToStatement)(nil)
// CTEChange represents a change that uses a Common Table Expression (CTE). // CTEChange represents a change that uses a Common Table Expression (CTE).
@@ -322,7 +357,7 @@ type cteChange struct {
} }
// IsOnColumn implements [CTEChange]. // IsOnColumn implements [CTEChange].
func (c *cteChange) IsOnColumn(col Column) bool { func (c cteChange) IsOnColumn(col Column) bool {
return false return false
} }
@@ -335,11 +370,15 @@ func (c *cteChange) Matches(x any) bool {
var expectedCTEBuilder, actualCTEBuilder StatementBuilder var expectedCTEBuilder, actualCTEBuilder StatementBuilder
c.cte(&expectedCTEBuilder) c.cte(&expectedCTEBuilder)
if c.change != nil { if c.change != nil {
c.change(c.name).Write(&expectedCTEBuilder) if err := c.change(c.name).Write(&expectedCTEBuilder); err != nil {
return false
}
} }
toMatch.cte(&actualCTEBuilder) toMatch.cte(&actualCTEBuilder)
if toMatch.change != nil { if toMatch.change != nil {
toMatch.change(toMatch.name).Write(&actualCTEBuilder) if err := toMatch.change(toMatch.name).Write(&actualCTEBuilder); err != nil {
return false
}
} }
if expectedCTEBuilder.String() != actualCTEBuilder.String() { if expectedCTEBuilder.String() != actualCTEBuilder.String() {
@@ -359,21 +398,26 @@ func (c *cteChange) String() string {
} }
// Write implements [CTEChange]. // Write implements [CTEChange].
func (c *cteChange) Write(builder *StatementBuilder) error { func (c cteChange) Write(builder *StatementBuilder) error {
if c.change == nil { if c.change == nil {
return nil return nil
} }
c.change(c.name).Write(builder) return c.change(c.name).Write(builder)
return nil
} }
// WriteCTE implements [CTEChange]. // WriteCTE implements [CTEChange].
func (c *cteChange) WriteCTE(builder *StatementBuilder) { func (c cteChange) WriteCTE(builder *StatementBuilder) {
c.cte(builder) c.cte(builder)
} }
// NoChange implements [NoChange]. // NoChange implements [NoChange].
// It returns true if there is no change function defined. // It returns true if there is no change function defined.
func (c *cteChange) NoChange() bool { func (c cteChange) NoChange() bool {
return c.change == nil return c.change == nil
} }
// WriteArg implements [Change].
func (c cteChange) WriteArg(builder *StatementBuilder) {
err := c.Write(builder)
logging.New(logging.StreamRuntime).Debug("write arg failed", "error", err)
}
+16 -7
View File
@@ -42,23 +42,32 @@ func TestChangeWrite(t *testing.T) {
args: []any{42}, args: []any{42},
}, },
}, },
{
name: "change to NULL",
change: NewChangeToNull(NewColumn("table", "column")),
want: want{
stmt: "column = NULL",
args: nil,
},
},
{ {
name: "multiple changes", name: "multiple changes",
change: NewChanges( change: NewChanges(
NewChange(NewColumn("table", "column1"), "value1"), NewChange(NewColumn("table", "column1"), "value1"),
NewChangePtr[int](NewColumn("table", "column2"), nil), NewChangePtr[int](NewColumn("table", "column2"), nil),
NewChange(NewColumn("table", "column3"), 123), NewChange(NewColumn("table", "column3"), 123),
NewChangeToNull(NewColumn("table", "column4")),
), ),
want: want{ want: want{
stmt: "column1 = $1, column2 = NULL, column3 = $2", stmt: "column1 = $1, column2 = NULL, column3 = $2, column4 = NULL",
args: []any{"value1", 123}, args: []any{"value1", 123},
}, },
}, },
{ {
name: "increment change", name: "increment change",
change: NewIncrementColumnChange(NewColumn("table", "counter")), change: NewIncrementColumnChange(NewColumn("table", "counter"), NewColumn("table", "counter")),
want: want{ want: want{
stmt: "counter = counter + 1", stmt: "counter = table.counter + 1",
}, },
}, },
} { } {
@@ -111,11 +120,11 @@ func TestChangeToStatement(t *testing.T) {
name: "change to statement with existing builder args", name: "change to statement with existing builder args",
prefillBuilder: func(builder *StatementBuilder) { prefillBuilder: func(builder *StatementBuilder) {
builder.WriteString("UPDATE table SET ") builder.WriteString("UPDATE table SET ")
NewChanges( assert.NoError(t, NewChanges(
NewChange(NewColumn("table", "field1"), "asdf"), NewChange(NewColumn("table", "field1"), "asdf"),
NewChangeToNull(NewColumn("table", "field2")), NewChangeToNull(NewColumn("table", "field2")),
NewChangeToColumn(NewColumn("table", "field3"), NewColumn("table", "field4")), NewChangeToColumn(NewColumn("table", "field3"), NewColumn("table", "field4")),
).Write(builder) ).Write(builder))
builder.WriteString(", ") builder.WriteString(", ")
}, },
change: NewChangeToStatement(NewColumn("table", "column"), func(builder *StatementBuilder) { change: NewChangeToStatement(NewColumn("table", "column"), func(builder *StatementBuilder) {
@@ -135,7 +144,7 @@ func TestChangeToStatement(t *testing.T) {
if test.prefillBuilder != nil { if test.prefillBuilder != nil {
test.prefillBuilder(&builder) test.prefillBuilder(&builder)
} }
test.change.Write(&builder) assert.NoError(t, test.change.Write(&builder))
assert.Equal(t, test.want.stmt, builder.String()) assert.Equal(t, test.want.stmt, builder.String())
assert.Equal(t, builder.Args(), test.want.args) assert.Equal(t, builder.Args(), test.want.args)
}) })
@@ -250,7 +259,7 @@ func TestCTEChange(t *testing.T) {
if test.afterCTE != nil { if test.afterCTE != nil {
test.afterCTE(&builder) test.afterCTE(&builder)
} }
test.change.Write(&builder) assert.NoError(t, test.change.Write(&builder))
assert.Equal(t, test.want.stmt, builder.String()) assert.Equal(t, test.want.stmt, builder.String())
assert.Equal(t, builder.Args(), test.want.args) assert.Equal(t, builder.Args(), test.want.args)
+46 -28
View File
@@ -2,6 +2,18 @@ package database
import "go.uber.org/mock/gomock" import "go.uber.org/mock/gomock"
// Column represents a column in a database table.
type Column interface {
gomock.Matcher
argWriter
// WriteQualified writes the column with the table name as prefix.
WriteQualified(builder *StatementBuilder)
// WriteUnqualified writes the column without the table name as prefix.
WriteUnqualified(builder *StatementBuilder)
// Equals checks if two columns are equal.
Equals(col Column) bool
}
type Columns []Column type Columns []Column
// Matches implements [Column]. // Matches implements [Column].
@@ -59,24 +71,22 @@ func (c Columns) Equals(col Column) bool {
return true return true
} }
var _ Column = (Columns)(nil) // WriteArg implements [Column].
func (c Columns) WriteArg(builder *StatementBuilder) {
// Column represents a column in a database table. c.WriteQualified(builder)
type Column interface {
gomock.Matcher
// WriteQualified writes the column with the table name as prefix.
WriteQualified(builder *StatementBuilder)
// WriteUnqualified writes the column without the table name as prefix.
WriteUnqualified(builder *StatementBuilder)
// Equals checks if two columns are equal.
Equals(col Column) bool
} }
var _ Column = (Columns)(nil)
type column struct { type column struct {
table string table string
name string name string
} }
func NewColumn(table, name string) Column {
return &column{table: table, name: name}
}
// Matches implements [Column]. // Matches implements [Column].
func (c column) Matches(x any) bool { func (c column) Matches(x any) bool {
toMatch, ok := x.(*column) toMatch, ok := x.(*column)
@@ -91,10 +101,6 @@ func (c column) String() string {
return "database.column" return "database.column"
} }
func NewColumn(table, name string) Column {
return &column{table: table, name: name}
}
// WriteQualified implements [Column]. // WriteQualified implements [Column].
func (c column) WriteQualified(builder *StatementBuilder) { func (c column) WriteQualified(builder *StatementBuilder) {
builder.Grow(len(c.table) + len(c.name) + 1) builder.Grow(len(c.table) + len(c.name) + 1)
@@ -120,6 +126,26 @@ func (c *column) Equals(col Column) bool {
return c.table == toMatch.table && c.name == toMatch.name return c.table == toMatch.table && c.name == toMatch.name
} }
// WriteArg implements [Column].
func (c column) WriteArg(builder *StatementBuilder) {
c.WriteQualified(builder)
}
var _ Column = (*column)(nil)
type functionColumn struct {
fn function
col Column
}
type function string
const (
_ function = ""
functionLower function = "LOWER"
functionSHA256 function = "SHA256"
)
// LowerColumn returns a column that represents LOWER(col). // LowerColumn returns a column that represents LOWER(col).
func LowerColumn(col Column) Column { func LowerColumn(col Column) Column {
return &functionColumn{fn: functionLower, col: col} return &functionColumn{fn: functionLower, col: col}
@@ -130,11 +156,6 @@ func SHA256Column(col Column) Column {
return &functionColumn{fn: functionSHA256, col: col} return &functionColumn{fn: functionSHA256, col: col}
} }
type functionColumn struct {
fn function
col Column
}
// Matches implements [Column]. // Matches implements [Column].
func (c *functionColumn) Matches(x any) bool { func (c *functionColumn) Matches(x any) bool {
toMatch, ok := x.(*functionColumn) toMatch, ok := x.(*functionColumn)
@@ -155,14 +176,6 @@ func (c *functionColumn) String() string {
return "database.functionColumn" return "database.functionColumn"
} }
type function string
const (
_ function = ""
functionLower function = "LOWER"
functionSHA256 function = "SHA256"
)
// WriteQualified implements [Column]. // WriteQualified implements [Column].
func (c functionColumn) WriteQualified(builder *StatementBuilder) { func (c functionColumn) WriteQualified(builder *StatementBuilder) {
builder.Grow(len(c.fn) + 2) builder.Grow(len(c.fn) + 2)
@@ -193,4 +206,9 @@ func (c *functionColumn) Equals(col Column) bool {
return c.col.Equals(toMatch.col) return c.col.Equals(toMatch.col)
} }
// WriteArg implements [Column].
func (c functionColumn) WriteArg(builder *StatementBuilder) {
c.WriteQualified(builder)
}
var _ Column = (*functionColumn)(nil) var _ Column = (*functionColumn)(nil)
@@ -14,7 +14,6 @@ CREATE TABLE zitadel.authorizations
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (instance_id, id), PRIMARY KEY (instance_id, id),
-- FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users (instance_id, id) ON DELETE CASCADE,
FOREIGN KEY (instance_id, project_id) REFERENCES zitadel.projects (instance_id, id) ON DELETE CASCADE, FOREIGN KEY (instance_id, project_id) REFERENCES zitadel.projects (instance_id, id) ON DELETE CASCADE,
FOREIGN KEY (instance_id, grant_id) REFERENCES zitadel.project_grants (instance_id, id) ON DELETE CASCADE FOREIGN KEY (instance_id, grant_id) REFERENCES zitadel.project_grants (instance_id, id) ON DELETE CASCADE
); );
@@ -22,7 +22,6 @@ CREATE TABLE zitadel.sessions (
, PRIMARY KEY (instance_id, id) , PRIMARY KEY (instance_id, id)
, FOREIGN KEY (instance_id) REFERENCES zitadel.instances(id) , FOREIGN KEY (instance_id) REFERENCES zitadel.instances(id)
-- , FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users(instance_id, id) ON DELETE CASCADE
, FOREIGN KEY (instance_id, user_agent_id) REFERENCES zitadel.session_user_agents(instance_id, fingerprint_id) ON DELETE SET NULL (user_agent_id) , FOREIGN KEY (instance_id, user_agent_id) REFERENCES zitadel.session_user_agents(instance_id, fingerprint_id) ON DELETE SET NULL (user_agent_id)
); );
@@ -31,8 +31,6 @@ CREATE TABLE zitadel.identity_provider_intents
expires_at TIMESTAMPTZ, expires_at TIMESTAMPTZ,
PRIMARY KEY (instance_id, id), PRIMARY KEY (instance_id, id),
-- TODO(@adlerhurst): easiest would be to create the index in the user migrations so that we can merge this one but the problem is that the migration might fail if there are already intents created.
-- FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users (instance_id, id) ON DELETE CASCADE,
FOREIGN KEY (instance_id, idp_id) REFERENCES zitadel.identity_providers (instance_id, id) ON DELETE CASCADE FOREIGN KEY (instance_id, idp_id) REFERENCES zitadel.identity_providers (instance_id, id) ON DELETE CASCADE
); );
@@ -0,0 +1,16 @@
package migration
import (
_ "embed"
)
var (
//go:embed 013_user_table/up.sql
up013UserTable string
//go:embed 013_user_table/down.sql
down013UserTable string
)
func init() {
registerSQLMigration(13, up013UserTable, down013UserTable)
}
@@ -0,0 +1,14 @@
DROP TABLE IF EXISTS zitadel.user_identity_provider_links;
DROP TABLE IF EXISTS zitadel.user_passkeys;
DROP TYPE IF EXISTS zitadel.passkey_type;
DROP TABLE IF EXISTS zitadel.machine_keys;
DROP TABLE IF EXISTS zitadel.user_personal_access_tokens;
DROP TABLE IF EXISTS zitadel.user_metadata CASCADE;
ALTER TABLE zitadel.identity_provider_intents DROP CONSTRAINT IF EXISTS fk_idp_intent_user;
ALTER TABLE zitadel.sessions DROP CONSTRAINT IF EXISTS fk_session_user;
ALTER TABLE zitadel.authorizations DROP CONSTRAINT IF EXISTS fk_authorization_user;
DROP TABLE IF EXISTS zitadel.users;
DROP TYPE IF EXISTS zitadel.user_type;
DROP TYPE IF EXISTS zitadel.user_state;
@@ -0,0 +1,228 @@
CREATE TYPE zitadel.user_state AS ENUM (
'initial'
, 'active'
, 'inactive'
, 'locked'
, 'suspended'
);
CREATE TYPE zitadel.user_type AS ENUM (
'human'
, 'machine'
);
CREATE TABLE zitadel.users(
instance_id TEXT NOT NULL
, organization_id TEXT NOT NULL
, id TEXT NOT NULL CHECK (id <> '')
, username TEXT NOT NULL CHECK (username <> '')
, username_org_unique BOOLEAN DEFAULT FALSE NOT NULL -- this field MUST be filled if the username must be unique on organization level
, state zitadel.user_state NOT NULL DEFAULT 'active'
, type zitadel.user_type NOT NULL
, created_at TIMESTAMPTZ NOT NULL DEFAULT now()
, updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
, PRIMARY KEY (instance_id, id)
, FOREIGN KEY (instance_id, organization_id) REFERENCES zitadel.organizations(instance_id, id) ON DELETE CASCADE
-- human
, first_name TEXT CHECK ((type = 'machine' AND first_name IS NULL) OR (type = 'human' AND first_name <> ''))
, last_name TEXT CHECK ((type = 'machine' AND last_name IS NULL) OR (type = 'human' AND last_name <> ''))
, nickname TEXT CHECK ((type = 'machine' AND nickname IS NULL) OR (type = 'human'))
, display_name TEXT CHECK ((type = 'machine' AND display_name IS NULL) OR (type = 'human'))
, preferred_language TEXT CHECK ((type = 'machine' AND preferred_language IS NULL) OR (type = 'human'))
, gender SMALLINT CHECK ((type = 'machine' AND gender IS NULL) OR (type = 'human'))
, avatar_key TEXT CHECK ((type = 'machine' AND avatar_key IS NULL) OR (type = 'human'))
, multifactor_initialization_skipped_at TIMESTAMPTZ CHECK ((type = 'machine' AND multifactor_initialization_skipped_at IS NULL) OR (type = 'human'))
, password_hash TEXT CHECK ((type = 'machine' AND password_hash IS NULL) OR (type = 'human'))
, password_change_required BOOLEAN CHECK ((type = 'machine' AND password_change_required IS NULL) OR (type = 'human'))
, password_changed_at TIMESTAMPTZ CHECK ((type = 'machine' AND password_changed_at IS NULL) OR (type = 'human'))
, password_verification_id TEXT CHECK ((type = 'machine' AND password_verification_id IS NULL) OR (type = 'human')) -- used for reset password flow
, password_last_successful_check TIMESTAMPTZ CHECK ((type = 'machine' AND password_last_successful_check IS NULL) OR (type = 'human'))
, password_failed_attempts SMALLINT CHECK ((type = 'machine' AND password_failed_attempts IS NULL) OR (type = 'human') AND (password_failed_attempts >= 0))
, email TEXT CHECK ((type = 'machine' AND email IS NULL) OR (type = 'human'))
, unverified_email TEXT CHECK ((type = 'machine' AND unverified_email IS NULL) OR (type = 'human' AND unverified_email <> '')) -- after successful verification this column is not cleared.
, email_verified_at TIMESTAMPTZ CHECK ((type = 'machine' AND email_verified_at IS NULL) OR (type = 'human'))
, email_verification_id TEXT CHECK ((type = 'machine' AND email_verification_id IS NULL) OR (type = 'human' AND (email IS DISTINCT FROM unverified_email OR email_verification_id IS NULL)))
, email_otp_enabled_at TIMESTAMPTZ CHECK ((type = 'machine' AND email_otp_enabled_at IS NULL) OR (type = 'human'))
, email_otp_last_successful_check TIMESTAMPTZ CHECK ((type = 'machine' AND email_otp_last_successful_check IS NULL) OR (type = 'human'))
, email_otp_failed_attempts SMALLINT CHECK ((type = 'machine' AND email_otp_failed_attempts IS NULL) OR (type = 'human'))
, phone TEXT CHECK ((type = 'machine' AND phone IS NULL) OR (type = 'human'))
, unverified_phone TEXT CHECK ((type = 'machine' AND unverified_phone IS NULL) OR (type = 'human')) -- after successful verification this column is not cleared.
, phone_verified_at TIMESTAMPTZ CHECK ((type = 'machine' AND phone_verified_at IS NULL) OR (type = 'human'))
, phone_verification_id TEXT CHECK ((type = 'machine' AND phone_verification_id IS NULL) OR (type = 'human' AND (phone IS DISTINCT FROM unverified_phone OR phone_verification_id IS NULL)))
, sms_otp_enabled_at TIMESTAMPTZ CHECK ((type = 'machine' AND sms_otp_enabled_at IS NULL) OR (type = 'human'))
, sms_otp_last_successful_check TIMESTAMPTZ CHECK ((type = 'machine' AND sms_otp_last_successful_check IS NULL) OR (type = 'human'))
, sms_otp_failed_attempts SMALLINT CHECK ((type = 'machine' AND sms_otp_failed_attempts IS NULL) OR (type = 'human'))
, totp_secret BYTEA CHECK ((type = 'machine' AND totp_secret IS NULL) OR (type = 'human'))
, totp_verified_at TIMESTAMPTZ CHECK ((type = 'machine' AND totp_verified_at IS NULL) OR (type = 'human'))
, totp_last_successful_check TIMESTAMPTZ CHECK ((type = 'machine' AND totp_last_successful_check IS NULL) OR (type = 'human'))
, totp_failed_attempts SMALLINT CHECK ((type = 'machine' AND totp_failed_attempts IS NULL) OR (type = 'human'))
, invite_verification_id TEXT CHECK ((type = 'machine' AND invite_verification_id IS NULL) OR (type = 'human'))
, invite_accepted_at TIMESTAMPTZ CHECK ((type = 'machine' AND invite_accepted_at IS NULL) OR (type = 'human'))
, invite_failed_attempts SMALLINT CHECK ((type = 'machine' AND invite_failed_attempts IS NULL) OR (type = 'human'))
-- foreign keys for verifications are created in the verification migration
-- machine
, name TEXT CHECK ((type = 'human' AND name IS NULL) OR (type = 'machine'))
, description TEXT CHECK ((type = 'human' AND description IS NULL) OR (type = 'machine'))
, secret TEXT CHECK ((type = 'human' AND secret IS NULL) OR (type = 'machine'))
, access_token_type SMALLINT CHECK ((type = 'human' AND access_token_type IS NULL) OR (type = 'machine'))
);
-- previously created tables
ALTER TABLE zitadel.identity_provider_intents ADD CONSTRAINT fk_idp_intent_user FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users (instance_id, id) ON DELETE CASCADE;
ALTER TABLE zitadel.sessions ADD CONSTRAINT fk_session_user FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users(instance_id, id) ON DELETE CASCADE;
ALTER TABLE zitadel.authorizations ADD CONSTRAINT fk_authorization_user FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users (instance_id, id) ON DELETE CASCADE;
-- user
CREATE UNIQUE INDEX ON zitadel.users(instance_id, organization_id, username) WHERE username_org_unique IS TRUE; --TODO(adlerhurst): does that work if a username is already present on a user without org unique?
CREATE UNIQUE INDEX ON zitadel.users(instance_id, username) WHERE username_org_unique IS FALSE;
CREATE INDEX idx_user_username ON zitadel.users (username);
CREATE INDEX idx_user_username_lower ON zitadel.users (lower(username));
CREATE INDEX idx_machine_name ON zitadel.users (name);
CREATE INDEX idx_human_email ON zitadel.users (email);
CREATE INDEX idx_human_email_lower ON zitadel.users (lower(email));
CREATE INDEX idx_human_phone ON zitadel.users (phone);
CREATE INDEX idx_human_phone_lower ON zitadel.users (lower(phone));
-- human
CREATE UNIQUE INDEX ON zitadel.users(password_verification_id) WHERE password_verification_id IS NOT NULL;
CREATE UNIQUE INDEX ON zitadel.users(email_verification_id) WHERE email_verification_id IS NOT NULL;
CREATE UNIQUE INDEX ON zitadel.users(phone_verification_id) WHERE phone_verification_id IS NOT NULL;
CREATE TRIGGER trigger_set_updated_at
BEFORE UPDATE ON zitadel.users
FOR EACH ROW
WHEN (NEW.updated_at IS NULL)
EXECUTE FUNCTION zitadel.set_updated_at();
-- ----------------------------------------------------------------
-- user metadata
-- ----------------------------------------------------------------
CREATE TABLE zitadel.user_metadata (
instance_id TEXT NOT NULL
, user_id TEXT NOT NULL
, key TEXT NOT NULL CHECK (key <> '')
, value BYTEA NOT NULL
, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
, updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
, PRIMARY KEY (instance_id, user_id, key)
, FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users (instance_id, id) ON DELETE CASCADE
);
CREATE INDEX idx_user_metadata_key ON zitadel.user_metadata (key);
CREATE INDEX idx_user_metadata_value ON zitadel.user_metadata (sha256(value));
CREATE TRIGGER trg_set_updated_at_user_metadata
BEFORE INSERT OR UPDATE ON zitadel.user_metadata
FOR EACH ROW
WHEN (NEW.updated_at IS NULL)
EXECUTE FUNCTION zitadel.set_updated_at();
-- ----------------------------------------------------------------
-- personal access tokens
-- ----------------------------------------------------------------
CREATE TABLE zitadel.user_personal_access_tokens(
instance_id TEXT NOT NULL
, user_id TEXT NOT NULL
, id TEXT NOT NULL
, created_at TIMESTAMPTZ NOT NULL DEFAULT now()
, expires_at TIMESTAMPTZ
, scopes TEXT[]
, PRIMARY KEY (instance_id, id)
, FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users(instance_id, id) ON DELETE CASCADE
);
-- ----------------------------------------------------------------
-- machine keys
-- ----------------------------------------------------------------
CREATE TABLE zitadel.machine_keys(
instance_id TEXT NOT NULL
, user_id TEXT NOT NULL
, id TEXT NOT NULL
, created_at TIMESTAMPTZ NOT NULL DEFAULT now()
, expires_at TIMESTAMPTZ
, type SMALLINT NOT NULL CHECK (type >= 0)
, public_key BYTEA NOT NULL
, PRIMARY KEY (instance_id, id)
, FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users(instance_id, id) ON DELETE CASCADE
);
-- ----------------------------------------------------------------
-- passkeys
-- ----------------------------------------------------------------
CREATE TYPE zitadel.passkey_type AS ENUM (
'passwordless'
, 'u2f'
);
CREATE TABLE zitadel.user_passkeys(
instance_id TEXT NOT NULL
, token_id TEXT NOT NULL
, key_id BYTEA NOT NULL
, user_id TEXT NOT NULL
, created_at TIMESTAMPTZ NOT NULL DEFAULT now()
, updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
, verified_at TIMESTAMPTZ
, type zitadel.passkey_type NOT NULL
, name TEXT NOT NULL CHECK (name <> '')
, sign_count INT NOT NULL DEFAULT 0 CHECK (sign_count >= 0)
, challenge BYTEA NOT NULL
, public_key BYTEA NOT NULL
, attestation_type TEXT NOT NULL CHECK (attestation_type <> '')
, authenticator_attestation_guid BYTEA NOT NULL
, relying_party_id TEXT NOT NULL CHECK (relying_party_id <> '')
, PRIMARY KEY (instance_id, token_id)
, FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users(instance_id, id) ON DELETE CASCADE
);
CREATE INDEX idx_user_passkeys_challenge ON zitadel.user_passkeys (sha256(challenge));
CREATE INDEX idx_user_passkeys_key_id ON zitadel.user_passkeys (key_id);
CREATE INDEX idx_user_passkeys_type ON zitadel.user_passkeys (type);
-- ----------------------------------------------------------------
-- identity provider links
-- ----------------------------------------------------------------
CREATE TABLE zitadel.user_identity_provider_links(
instance_id TEXT NOT NULL
, identity_provider_id TEXT NOT NULL
, user_id TEXT NOT NULL
, provided_user_id TEXT NOT NULL CHECK(provided_user_id <> '')
, provided_username TEXT NOT NULL
, created_at TIMESTAMPTZ NOT NULL DEFAULT now()
, updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
, PRIMARY KEY (instance_id, identity_provider_id, provided_user_id)
, FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users(instance_id, id) ON DELETE CASCADE
, FOREIGN KEY (instance_id, identity_provider_id) REFERENCES zitadel.identity_providers(instance_id, id) ON DELETE CASCADE
);
@@ -0,0 +1,16 @@
package migration
import (
_ "embed"
)
var (
//go:embed 014_verification_table/up.sql
up014VerificationTable string
//go:embed 014_verification_table/down.sql
down014VerificationTable string
)
func init() {
registerSQLMigration(14, up014VerificationTable, down014VerificationTable)
}
@@ -0,0 +1,7 @@
ALTER TABLE zitadel.users DROP CONSTRAINT IF EXISTS fk_unverified_password;
ALTER TABLE zitadel.users DROP CONSTRAINT IF EXISTS fk_unverified_email;
ALTER TABLE zitadel.users DROP CONSTRAINT IF EXISTS fk_unverified_phone;
DROP TRIGGER IF EXISTS user_verification_integrity_trigger ON zitadel.users;
DROP FUNCTION IF EXISTS zitadel.ensure_user_verification_integrity() CASCADE;
DROP TABLE IF EXISTS zitadel.verifications CASCADE;
@@ -0,0 +1,61 @@
CREATE TABLE zitadel.verifications(
instance_id TEXT NOT NULL
, user_id TEXT
, id TEXT NOT NULL DEFAULT gen_random_uuid()::TEXT
, code BYTEA
, created_at TIMESTAMPTZ NOT NULL DEFAULT now()
, updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
, expiry INTERVAL
, failed_attempts SMALLINT NOT NULL DEFAULT 0 CHECK (failed_attempts >= 0)
, PRIMARY KEY (instance_id, id)
, FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users(instance_id, id) ON DELETE CASCADE
);
ALTER TABLE zitadel.users ADD CONSTRAINT fk_unverified_password FOREIGN KEY (instance_id, password_verification_id) REFERENCES zitadel.verifications(instance_id, id) ON DELETE SET NULL (password_verification_id);
ALTER TABLE zitadel.users ADD CONSTRAINT fk_unverified_email FOREIGN KEY (instance_id, email_verification_id) REFERENCES zitadel.verifications(instance_id, id) ON DELETE SET NULL (email_verification_id);
ALTER TABLE zitadel.users ADD CONSTRAINT fk_unverified_phone FOREIGN KEY (instance_id, phone_verification_id) REFERENCES zitadel.verifications(instance_id, id) ON DELETE SET NULL (phone_verification_id);
CREATE OR REPLACE FUNCTION zitadel.ensure_user_verification_integrity() RETURNS trigger AS $$
BEGIN
IF (NEW.password_verification_id IS DISTINCT FROM OLD.password_verification_id) THEN
DELETE FROM zitadel.verifications
WHERE instance_id = NEW.instance_id
AND id = OLD.password_verification_id;
END IF;
IF (NEW.email_verification_id IS DISTINCT FROM OLD.email_verification_id) THEN
DELETE FROM zitadel.verifications
WHERE instance_id = NEW.instance_id
AND id = OLD.email_verification_id;
END IF;
IF (NEW.phone_verification_id IS DISTINCT FROM OLD.phone_verification_id) THEN
DELETE FROM zitadel.verifications
WHERE instance_id = NEW.instance_id
AND id = OLD.phone_verification_id;
END IF;
IF (NEW.invite_verification_id IS DISTINCT FROM OLD.invite_verification_id) THEN
DELETE FROM zitadel.verifications
WHERE instance_id = NEW.instance_id
AND id = OLD.invite_verification_id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER user_verification_integrity_trigger
AFTER UPDATE ON zitadel.users
FOR EACH ROW
EXECUTE FUNCTION zitadel.ensure_user_verification_integrity();
CREATE TRIGGER trigger_set_updated_at
BEFORE UPDATE ON zitadel.verifications
FOR EACH ROW
WHEN (NEW.updated_at IS NULL)
EXECUTE FUNCTION zitadel.set_updated_at();
@@ -435,6 +435,8 @@ func TestServer_AuthorizationReduces(t *testing.T) {
} }
func createAndEnsureAuthorization(t *testing.T, instanceID, orgID, userID, projectID string, roles []string, retryDuration time.Duration, tick time.Duration) *authorization_v2.CreateAuthorizationResponse { func createAndEnsureAuthorization(t *testing.T, instanceID, orgID, userID, projectID string, roles []string, retryDuration time.Duration, tick time.Duration) *authorization_v2.CreateAuthorizationResponse {
t.Helper()
// create authorization // create authorization
createdAuthorization, err := AuthorizationClient.CreateAuthorization(CTX, &authorization_v2.CreateAuthorizationRequest{ createdAuthorization, err := AuthorizationClient.CreateAuthorization(CTX, &authorization_v2.CreateAuthorizationRequest{
UserId: userID, UserId: userID,
@@ -454,11 +456,13 @@ func createAndEnsureAuthorization(t *testing.T, instanceID, orgID, userID, proje
assert.Equal(collect, domain.AuthorizationStateActive, az.State) assert.Equal(collect, domain.AuthorizationStateActive, az.State)
assert.Equal(collect, createdAuthorization.GetCreationDate().AsTime().UTC(), az.CreatedAt.UTC()) assert.Equal(collect, createdAuthorization.GetCreationDate().AsTime().UTC(), az.CreatedAt.UTC())
assert.Equal(collect, createdAuthorization.GetCreationDate().AsTime().UTC(), az.UpdatedAt.UTC()) assert.Equal(collect, createdAuthorization.GetCreationDate().AsTime().UTC(), az.UpdatedAt.UTC())
}, retryDuration, tick, "authorization not found within %v: %v", retryDuration, err) }, retryDuration, tick, "authorization %q not found within %v: %v", createdAuthorization.Id, retryDuration, err)
return createdAuthorization return createdAuthorization
} }
func prepareProjectAndProjectRoles(t *testing.T, orgID string, roles []string) string { func prepareProjectAndProjectRoles(t *testing.T, orgID string, roles []string) string {
t.Helper()
project, err := ProjectClient.CreateProject(CTX, &project_v2beta.CreateProjectRequest{ project, err := ProjectClient.CreateProject(CTX, &project_v2beta.CreateProjectRequest{
OrganizationId: orgID, OrganizationId: orgID,
Name: integration.ProjectName(), Name: integration.ProjectName(),
@@ -477,7 +481,7 @@ func prepareProjectAndProjectRoles(t *testing.T, orgID string, roles []string) s
projectRepo.PrimaryKeyCondition(Instance.ID(), project.Id), projectRepo.PrimaryKeyCondition(Instance.ID(), project.Id),
)) ))
require.NoError(collect, err) require.NoError(collect, err)
}, retryDuration, tick, "project not found") }, retryDuration, tick, "project %q not found within %v: %v", project.Id, retryDuration, err)
for _, role := range roles { for _, role := range roles {
_, err = ProjectClient.AddProjectRole(CTX, &project_v2beta.AddProjectRoleRequest{ _, err = ProjectClient.AddProjectRole(CTX, &project_v2beta.AddProjectRoleRequest{
@@ -2,7 +2,7 @@
package events_test package events_test
// TODO(adlerhurst): Uncomment once users table is created and FK can be enforced // The tests of this file fail because we would need to mock an ldap, OIDC and Oauth server.
// import ( // import (
// "net" // "net"
@@ -325,7 +325,7 @@ func TestServer_SessionReduces(t *testing.T) {
Metadata: metadata, Metadata: metadata,
UserAgent: userAgent, UserAgent: userAgent,
}, dbSession) }, dbSession)
}, retryDuration, tick, "session not found within %v: %v", retryDuration, err) }, retryDuration, tick, "session %q not found within %v: %v", createdSession.GetSessionId(), retryDuration, err)
}) })
t.Run("checks with challenges set reduces", func(t *testing.T) { t.Run("checks with challenges set reduces", func(t *testing.T) {
File diff suppressed because it is too large Load Diff
+112
View File
@@ -0,0 +1,112 @@
package database
type coalesce struct {
values []any
}
func Coalesce(values ...any) *coalesce {
return &coalesce{values: values}
}
// WriteArg implements [Change].
func (c *coalesce) WriteArg(builder *StatementBuilder) {
c.WriteQualified(builder)
}
// IsOnColumn implements [Change].
func (c coalesce) IsOnColumn(col Column) bool {
for _, value := range c.values {
if change, ok := value.(Change); ok {
if change.IsOnColumn(col) {
return true
}
}
}
return false
}
// Write implements [Change].
func (c coalesce) Write(builder *StatementBuilder) error {
builder.WriteString("COALESCE(")
for i, value := range c.values {
if i > 0 {
builder.WriteString(", ")
}
builder.WriteArg(value)
}
builder.WriteString(")")
return nil
}
// Equals implements [Column].
func (c *coalesce) Equals(col Column) bool {
if col == nil {
return c == nil
}
other, ok := col.(*coalesce)
if !ok || len(other.values) != len(c.values) {
return false
}
for i, value := range c.values {
if value != other.values[i] {
return false
}
}
return true
}
// Matches implements [Column].
func (c *coalesce) Matches(x any) bool {
toMatch, ok := x.(*coalesce)
if !ok || len(toMatch.values) != len(c.values) {
return false
}
for i, value := range c.values {
if value != toMatch.values[i] {
return false
}
}
return true
}
// String implements [Column].
func (c *coalesce) String() string {
return "database.coalesce"
}
// WriteQualified implements [Column].
func (c *coalesce) WriteQualified(builder *StatementBuilder) {
builder.WriteString("COALESCE(")
for i, value := range c.values {
if i > 0 {
builder.WriteString(", ")
}
if col, ok := value.(Column); ok {
col.WriteQualified(builder)
continue
}
builder.WriteArg(value)
}
builder.WriteString(")")
}
// WriteUnqualified implements [Column].
func (c *coalesce) WriteUnqualified(builder *StatementBuilder) {
builder.WriteString("COALESCE(")
for i, value := range c.values {
if i > 0 {
builder.WriteString(", ")
}
if col, ok := value.(Column); ok {
col.WriteUnqualified(builder)
continue
}
builder.WriteArg(value)
}
builder.WriteString(")")
}
var (
_ Column = (*coalesce)(nil)
_ Change = (*coalesce)(nil)
)
+9
View File
@@ -176,6 +176,7 @@ func NewJsonChanges(col database.Column, changes ...JsonUpdate) database.Change
} }
} }
// WriteArg implements [gomock.Matcher].
func (c *jsonChanges) Matches(x any) bool { func (c *jsonChanges) Matches(x any) bool {
toMatch, ok := x.(*jsonChanges) toMatch, ok := x.(*jsonChanges)
if !ok { if !ok {
@@ -205,10 +206,12 @@ func (c *jsonChanges) Matches(x any) bool {
return true return true
} }
// WriteArg implements [database.Change].
func (c *jsonChanges) String() string { func (c *jsonChanges) String() string {
return "database.json.jsonChange" return "database.json.jsonChange"
} }
// WriteArg implements [database.Change].
func (c jsonChanges) Write(builder *database.StatementBuilder) error { func (c jsonChanges) Write(builder *database.StatementBuilder) error {
c.column.WriteUnqualified(builder) c.column.WriteUnqualified(builder)
builder.WriteString(" = ") builder.WriteString(" = ")
@@ -220,6 +223,12 @@ func (c jsonChanges) Write(builder *database.StatementBuilder) error {
return c.changes[len(c.changes)-1].writeUpdate(builder, c, len(c.changes)-2) return c.changes[len(c.changes)-1].writeUpdate(builder, c, len(c.changes)-2)
} }
// WriteArg implements [database.Change].
func (c jsonChanges) IsOnColumn(col database.Column) bool { func (c jsonChanges) IsOnColumn(col database.Column) bool {
return c.column.Equals(col) return c.column.Equals(col)
} }
// WriteArg implements [database.Change].
func (c jsonChanges) WriteArg(builder *database.StatementBuilder) {
c.column.WriteArg(builder)
}
+1 -1
View File
@@ -31,7 +31,7 @@ func (b wrappedValue[V]) WriteArg(builder *StatementBuilder) {
var _ argWriter = (*wrappedValue[string])(nil) var _ argWriter = (*wrappedValue[string])(nil)
type Value interface { type Value interface {
Boolean | Number | Text | Instruction | Bytes Boolean | Number | Text | Instruction | Bytes | any
} }
//go:generate enumer -type NumberOperation,TextOperation,BytesOperation -linecomment -output ./operators_enumer.go //go:generate enumer -type NumberOperation,TextOperation,BytesOperation -linecomment -output ./operators_enumer.go
@@ -36,17 +36,6 @@ func (a authorization) qualifiedAuthorizationRolesTableName() string {
// repository // repository
// ------------------------------------------------------------- // -------------------------------------------------------------
const insertAuthorizationStmt = `INSERT INTO zitadel.authorizations (
instance_id, id, user_id, grant_id, project_id, state, created_at, updated_at
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING created_at, updated_at`
const insertAuthorizationWithRolesStmt = `WITH roles AS (
INSERT INTO zitadel.authorization_roles
(instance_id, authorization_id, grant_id, project_id, role_key)
VALUES ($1, $2, $4, $5, unnest($9::text[])))` + insertAuthorizationStmt
// Create implements [domain.AuthorizationRepository]. // Create implements [domain.AuthorizationRepository].
func (a authorization) Create(ctx context.Context, client database.QueryExecutor, authorization *domain.Authorization) error { func (a authorization) Create(ctx context.Context, client database.QueryExecutor, authorization *domain.Authorization) error {
var ( var (
@@ -59,17 +48,12 @@ func (a authorization) Create(ctx context.Context, client database.QueryExecutor
updatedAt = authorization.UpdatedAt updatedAt = authorization.UpdatedAt
} }
builder := database.NewStatementBuilder(insertAuthorizationWithRolesStmt, builder := database.NewStatementBuilder("WITH roles AS (INSERT INTO zitadel.authorization_roles (instance_id, authorization_id, grant_id, project_id, role_key)"+
authorization.InstanceID, " VALUES ($1, $2, $3, $4, unnest($5::text[]))) INSERT INTO zitadel.authorizations (instance_id, id, grant_id, project_id, user_id, state, created_at, updated_at) VALUES ($1, $2, $3, $4, $6, $7, ",
authorization.ID, authorization.InstanceID, authorization.ID, authorization.GrantID, authorization.ProjectID, authorization.Roles, authorization.UserID, authorization.State,
authorization.UserID,
authorization.GrantID,
authorization.ProjectID,
authorization.State,
createdAt,
updatedAt,
authorization.Roles,
) )
builder.WriteArgs(createdAt, updatedAt)
builder.WriteString(") RETURNING created_at, updated_at")
if err := client.QueryRow( if err := client.QueryRow(
ctx, ctx,
@@ -191,10 +175,10 @@ func (a authorization) setRoles(ctx context.Context, client database.QueryExecut
// set the roles // set the roles
builder.WriteString(updateAuthorizationRoleStmt) builder.WriteString(updateAuthorizationRoleStmt)
err := database.Changes(changes).Write(builder) if err := database.Changes(changes).Write(builder); err != nil {
if err != nil {
return 0, err return 0, err
} }
builder.WriteString(updateAuthorizationRoleStmtWhere) builder.WriteString(updateAuthorizationRoleStmtWhere)
return client.Exec(ctx, builder.String(), builder.Args()...) return client.Exec(ctx, builder.String(), builder.Args()...)
@@ -29,10 +29,8 @@ func TestCreateAuthorization(t *testing.T) {
// create project roles // create project roles
role1 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role1") role1 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role1")
role2 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role2") role2 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role2")
// TODO: uncomment when user table is available userID := createHumanUser(t, tx, instanceID, organizationID)
// userID := createUser(t, tx, instanceID, organizationID) require.NotNil(t, userID)
// require.NotNil(t, userID)
userID := integration.ID()
authorizationRepo := repository.AuthorizationRepository() authorizationRepo := repository.AuthorizationRepository()
@@ -116,19 +114,18 @@ func TestCreateAuthorization(t *testing.T) {
}, },
wantErr: new(database.ForeignKeyError), wantErr: new(database.ForeignKeyError),
}, },
// TODO: uncomment when user table is available {
// { name: "non-existent user",
// name: "non-existent user", authorization: &domain.Authorization{
// authorization: &domain.Authorization{ ID: integration.ID(),
// ID: integration.ID(), UserID: "random-id",
// UserID: "random-id", ProjectID: projectID,
// ProjectID: projectID, InstanceID: instanceID,
// InstanceID: instanceID, State: domain.AuthorizationStateActive,
// State: domain.AuthorizationStateActive, Roles: nil,
// Roles: nil, },
// }, wantErr: new(database.ForeignKeyError),
// wantErr: new(database.ForeignKeyError), },
// },
{ {
name: "duplicate authorization", name: "duplicate authorization",
authorization: &domain.Authorization{ authorization: &domain.Authorization{
@@ -265,10 +262,8 @@ func TestGetAuthorization(t *testing.T) {
role1 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role1") role1 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role1")
role2 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role2") role2 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role2")
// TODO: uncomment when user table is available userID := createHumanUser(t, tx, instanceID, organizationID)
// userID := createUser(t, tx, instanceID, organizationID) require.NotNil(t, userID)
// require.NotNil(t, userID)
userID := integration.ID()
// create authorization with roles // create authorization with roles
authorizationRepo := repository.AuthorizationRepository() authorizationRepo := repository.AuthorizationRepository()
@@ -458,13 +453,10 @@ func TestListAuthorization(t *testing.T) {
project2Role1 := createProjectRole(t, tx, instanceID, organizationID, project2ID, "project2Role1") project2Role1 := createProjectRole(t, tx, instanceID, organizationID, project2ID, "project2Role1")
project2Role2 := createProjectRole(t, tx, instanceID, organizationID, project2ID, "project2Role2") project2Role2 := createProjectRole(t, tx, instanceID, organizationID, project2ID, "project2Role2")
// TODO: uncomment when user table is available user1ID := createHumanUser(t, tx, instanceID, organizationID)
// user1ID := createUser(t, tx, instanceID, organizationID) require.NotNil(t, user1ID)
// require.NotNil(t, user1ID) user2ID := createHumanUser(t, tx, instanceID, organizationID)
user1ID := integration.ID() require.NotNil(t, user2ID)
// user2ID := createUser(t, tx, instanceID, organizationID)
// require.NotNil(t, user2ID)
user2ID := integration.ID()
// create authorization with roles for user1 for project1 // create authorization with roles for user1 for project1
authorizationRepo := repository.AuthorizationRepository() authorizationRepo := repository.AuthorizationRepository()
@@ -890,11 +882,12 @@ func TestUpdateAuthorization(t *testing.T) {
instanceID := createInstance(t, tx) instanceID := createInstance(t, tx)
organizationID := createOrganization(t, tx, instanceID) organizationID := createOrganization(t, tx, instanceID)
projectID := createProject(t, tx, instanceID, organizationID) projectID := createProject(t, tx, instanceID, organizationID)
userID := createHumanUser(t, tx, instanceID, organizationID)
authorizationRepo := repository.AuthorizationRepository() authorizationRepo := repository.AuthorizationRepository()
activeAuthorization := &domain.Authorization{ activeAuthorization := &domain.Authorization{
ID: integration.ID(), ID: integration.ID(),
UserID: integration.ID(), UserID: userID,
ProjectID: projectID, ProjectID: projectID,
InstanceID: instanceID, InstanceID: instanceID,
State: domain.AuthorizationStateActive, State: domain.AuthorizationStateActive,
@@ -907,7 +900,7 @@ func TestUpdateAuthorization(t *testing.T) {
inactiveAuthorization := &domain.Authorization{ inactiveAuthorization := &domain.Authorization{
ID: integration.ID(), ID: integration.ID(),
UserID: integration.ID(), UserID: userID,
ProjectID: projectID, ProjectID: projectID,
InstanceID: instanceID, InstanceID: instanceID,
State: domain.AuthorizationStateInactive, State: domain.AuthorizationStateInactive,
@@ -1012,10 +1005,12 @@ func TestAuthorizationUpdate_setRoles(t *testing.T) {
role5 := createProjectRole(t, tx, instanceID, organizationID, project2ID, "role5") role5 := createProjectRole(t, tx, instanceID, organizationID, project2ID, "role5")
role6 := createProjectRole(t, tx, instanceID, organizationID, project2ID, "role6") role6 := createProjectRole(t, tx, instanceID, organizationID, project2ID, "role6")
userID := createHumanUser(t, tx, instanceID, organizationID)
authorizationRepo := repository.AuthorizationRepository() authorizationRepo := repository.AuthorizationRepository()
authorization1 := &domain.Authorization{ authorization1 := &domain.Authorization{
ID: integration.ID(), ID: integration.ID(),
UserID: integration.ID(), UserID: userID,
ProjectID: projectID, ProjectID: projectID,
InstanceID: instanceID, InstanceID: instanceID,
State: domain.AuthorizationStateActive, State: domain.AuthorizationStateActive,
@@ -1028,7 +1023,7 @@ func TestAuthorizationUpdate_setRoles(t *testing.T) {
authorization2 := &domain.Authorization{ authorization2 := &domain.Authorization{
ID: integration.ID(), ID: integration.ID(),
UserID: integration.ID(), UserID: userID,
ProjectID: project2ID, ProjectID: project2ID,
InstanceID: instanceID, InstanceID: instanceID,
State: domain.AuthorizationStateActive, State: domain.AuthorizationStateActive,
@@ -1132,11 +1127,12 @@ func TestDeleteAuthorization(t *testing.T) {
projectID := createProject(t, tx, instanceID, organizationID) projectID := createProject(t, tx, instanceID, organizationID)
role1 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role1") role1 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role1")
role2 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role2") role2 := createProjectRole(t, tx, instanceID, organizationID, projectID, "role2")
userID := createHumanUser(t, tx, instanceID, organizationID)
authorizationRepo := repository.AuthorizationRepository() authorizationRepo := repository.AuthorizationRepository()
authorizationWithRoles := &domain.Authorization{ authorizationWithRoles := &domain.Authorization{
ID: integration.ID(), ID: integration.ID(),
UserID: integration.ID(), UserID: userID,
ProjectID: projectID, ProjectID: projectID,
InstanceID: instanceID, InstanceID: instanceID,
State: domain.AuthorizationStateActive, State: domain.AuthorizationStateActive,
@@ -1149,7 +1145,7 @@ func TestDeleteAuthorization(t *testing.T) {
authorizationWithoutRoles := &domain.Authorization{ authorizationWithoutRoles := &domain.Authorization{
ID: integration.ID(), ID: integration.ID(),
UserID: integration.ID(), UserID: userID,
ProjectID: projectID, ProjectID: projectID,
InstanceID: instanceID, InstanceID: instanceID,
State: domain.AuthorizationStateActive, State: domain.AuthorizationStateActive,
@@ -1162,7 +1158,7 @@ func TestDeleteAuthorization(t *testing.T) {
deletedAuthorization := &domain.Authorization{ deletedAuthorization := &domain.Authorization{
ID: integration.ID(), ID: integration.ID(),
UserID: integration.ID(), UserID: userID,
ProjectID: projectID, ProjectID: projectID,
InstanceID: instanceID, InstanceID: instanceID,
State: domain.AuthorizationStateActive, State: domain.AuthorizationStateActive,
@@ -1182,7 +1178,7 @@ func TestDeleteAuthorization(t *testing.T) {
grantID := createProjectGrant(t, tx, instanceID, organizationID, grantedOrganizationID, projectID, []string{role1}) grantID := createProjectGrant(t, tx, instanceID, organizationID, grantedOrganizationID, projectID, []string{role1})
authorizationProjectGrant := &domain.Authorization{ authorizationProjectGrant := &domain.Authorization{
ID: integration.ID(), ID: integration.ID(),
UserID: integration.ID(), UserID: userID,
ProjectID: projectID, ProjectID: projectID,
GrantID: gu.Ptr(grantID), GrantID: gu.Ptr(grantID),
InstanceID: instanceID, InstanceID: instanceID,
@@ -2,7 +2,6 @@ package repository
import ( import (
"context" "context"
"fmt"
"net/url" "net/url"
"time" "time"
@@ -95,7 +94,6 @@ func (i idpIntentRepository) Get(ctx context.Context, client database.QueryExecu
var builder database.StatementBuilder var builder database.StatementBuilder
builder.WriteString(queryIDPIntentStmt) builder.WriteString(queryIDPIntentStmt)
options.Write(&builder) options.Write(&builder)
fmt.Println(builder.String())
return scanIDPIntent(ctx, client, &builder) return scanIDPIntent(ctx, client, &builder)
} }
@@ -315,6 +315,8 @@ func TestUpdateIDPIntent(t *testing.T) {
err = idpIntentRepo.Create(t.Context(), tx, &intent2) err = idpIntentRepo.Create(t.Context(), tx, &intent2)
require.NoError(t, err) require.NoError(t, err)
userID := createHumanUser(t, tx, instanceID, orgID)
now := time.Now() now := time.Now()
tomorrow := now.AddDate(0, 0, 1) tomorrow := now.AddDate(0, 0, 1)
tt := []struct { tt := []struct {
@@ -344,7 +346,7 @@ func TestUpdateIDPIntent(t *testing.T) {
idpIntentRepo.SetIDPUser([]byte("update user")), idpIntentRepo.SetIDPUser([]byte("update user")),
idpIntentRepo.SetIDPUserID("idp user id updated"), idpIntentRepo.SetIDPUserID("idp user id updated"),
idpIntentRepo.SetIDPUsername("idp username updated"), idpIntentRepo.SetIDPUsername("idp username updated"),
idpIntentRepo.SetUserID("some-user-id"), idpIntentRepo.SetUserID(userID),
idpIntentRepo.SetIDPAccessToken([]byte(`{"secret": "g1g4 s3cr3t 4cc3ss t0k3n"}`)), idpIntentRepo.SetIDPAccessToken([]byte(`{"secret": "g1g4 s3cr3t 4cc3ss t0k3n"}`)),
idpIntentRepo.SetIDPIDToken("idp id token"), idpIntentRepo.SetIDPIDToken("idp id token"),
idpIntentRepo.SetSucceededAt(now), idpIntentRepo.SetSucceededAt(now),
@@ -355,7 +357,7 @@ func TestUpdateIDPIntent(t *testing.T) {
toReturn.IDPUser = []byte("update user") toReturn.IDPUser = []byte("update user")
toReturn.IDPUserID = "idp user id updated" toReturn.IDPUserID = "idp user id updated"
toReturn.IDPUsername = "idp username updated" toReturn.IDPUsername = "idp username updated"
toReturn.UserID = "some-user-id" toReturn.UserID = userID
toReturn.IDPAccessToken = []byte(`{"secret": "g1g4 s3cr3t 4cc3ss t0k3n"}`) toReturn.IDPAccessToken = []byte(`{"secret": "g1g4 s3cr3t 4cc3ss t0k3n"}`)
toReturn.IDPIDToken = "idp id token" toReturn.IDPIDToken = "idp id token"
toReturn.SucceededAt = &now toReturn.SucceededAt = &now
@@ -373,7 +375,7 @@ func TestUpdateIDPIntent(t *testing.T) {
idpIntentRepo.SetIDPUser([]byte("update user")), idpIntentRepo.SetIDPUser([]byte("update user")),
idpIntentRepo.SetIDPUserID("idp user id updated"), idpIntentRepo.SetIDPUserID("idp user id updated"),
idpIntentRepo.SetIDPUsername("idp username updated"), idpIntentRepo.SetIDPUsername("idp username updated"),
idpIntentRepo.SetUserID("some-user-id"), idpIntentRepo.SetUserID(userID),
idpIntentRepo.SetAssertion([]byte(`{"assertion": "val1"}`)), idpIntentRepo.SetAssertion([]byte(`{"assertion": "val1"}`)),
idpIntentRepo.SetSucceededAt(now), idpIntentRepo.SetSucceededAt(now),
idpIntentRepo.SetExpiresAt(tomorrow), idpIntentRepo.SetExpiresAt(tomorrow),
@@ -383,7 +385,7 @@ func TestUpdateIDPIntent(t *testing.T) {
toReturn.IDPUser = []byte("update user") toReturn.IDPUser = []byte("update user")
toReturn.IDPUserID = "idp user id updated" toReturn.IDPUserID = "idp user id updated"
toReturn.IDPUsername = "idp username updated" toReturn.IDPUsername = "idp username updated"
toReturn.UserID = "some-user-id" toReturn.UserID = userID
toReturn.Assertion = []byte(`{"assertion": "val1"}`) toReturn.Assertion = []byte(`{"assertion": "val1"}`)
toReturn.SucceededAt = &now toReturn.SucceededAt = &now
toReturn.ExpiresAt = &tomorrow toReturn.ExpiresAt = &tomorrow
@@ -400,7 +402,7 @@ func TestUpdateIDPIntent(t *testing.T) {
idpIntentRepo.SetIDPUser([]byte("update user")), idpIntentRepo.SetIDPUser([]byte("update user")),
idpIntentRepo.SetIDPUserID("idp user id updated"), idpIntentRepo.SetIDPUserID("idp user id updated"),
idpIntentRepo.SetIDPUsername("idp username updated"), idpIntentRepo.SetIDPUsername("idp username updated"),
idpIntentRepo.SetUserID("some-user-id"), idpIntentRepo.SetUserID(userID),
idpIntentRepo.SetIDPEntryAttributes(marshalledAttrs), idpIntentRepo.SetIDPEntryAttributes(marshalledAttrs),
idpIntentRepo.SetSucceededAt(now), idpIntentRepo.SetSucceededAt(now),
idpIntentRepo.SetExpiresAt(tomorrow), idpIntentRepo.SetExpiresAt(tomorrow),
@@ -410,7 +412,7 @@ func TestUpdateIDPIntent(t *testing.T) {
toReturn.IDPUser = []byte("update user") toReturn.IDPUser = []byte("update user")
toReturn.IDPUserID = "idp user id updated" toReturn.IDPUserID = "idp user id updated"
toReturn.IDPUsername = "idp username updated" toReturn.IDPUsername = "idp username updated"
toReturn.UserID = "some-user-id" toReturn.UserID = userID
toReturn.EntryAttributes = entryAttrs toReturn.EntryAttributes = entryAttrs
toReturn.SucceededAt = &now toReturn.SucceededAt = &now
toReturn.ExpiresAt = &tomorrow toReturn.ExpiresAt = &tomorrow
@@ -0,0 +1,33 @@
package repository_test
import (
"slices"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/backend/v3/domain"
)
func assertMetadata(t *testing.T, expected, gotten []*domain.Metadata) {
t.Helper()
assert.Len(t, gotten, len(expected), "metadata length mismatch")
for _, exp := range expected {
var actual *domain.Metadata
gotten = slices.DeleteFunc(gotten, func(m *domain.Metadata) bool {
if exp.Key != m.Key || exp.InstanceID != m.InstanceID {
return false
}
actual = m
return true
})
require.NotNil(t, actual, "metadata with key %s and instance %s not found", exp.Key, exp.InstanceID)
assert.Equal(t, exp.Value, actual.Value, "metadata value mismatch for key %s and instance %s", exp.Key, exp.InstanceID)
assert.NotZero(t, actual.CreatedAt, "metadata created at is zero for key %s and instance %s", exp.Key, exp.InstanceID)
assert.NotZero(t, actual.UpdatedAt, "metadata updated at is zero for key %s and instance %s", exp.Key, exp.InstanceID)
}
assert.Empty(t, gotten, "unmatched metadata found")
}
@@ -123,7 +123,9 @@ func (p projectGrant) Update(ctx context.Context, client database.QueryExecutor,
// now we add the logic to do the required changes based on the given project grant // now we add the logic to do the required changes based on the given project grant
builder.WriteString(updateProjectGrantRoleStmt) builder.WriteString(updateProjectGrantRoleStmt)
database.Changes(changes).Write(builder) if err := database.Changes(changes).Write(builder); err != nil {
return 0, err
}
builder.WriteString(updateProjectGrantRoleStmtWhere) builder.WriteString(updateProjectGrantRoleStmtWhere)
return client.Exec(ctx, builder.String(), builder.Args()...) return client.Exec(ctx, builder.String(), builder.Args()...)
@@ -85,7 +85,9 @@ func updateOne[Target updatable](ctx context.Context, client database.QueryExecu
builder := database.NewStatementBuilder("UPDATE ") builder := database.NewStatementBuilder("UPDATE ")
builder.WriteString(target.qualifiedTableName()) builder.WriteString(target.qualifiedTableName())
builder.WriteString(" SET ") builder.WriteString(" SET ")
database.Changes(changes).Write(builder) if err := database.Changes(changes).Write(builder); err != nil {
return 0, err
}
writeCondition(builder, condition) writeCondition(builder, condition)
return client.Exec(ctx, builder.String(), builder.Args()...) return client.Exec(ctx, builder.String(), builder.Args()...)
@@ -15,6 +15,7 @@ import (
"github.com/zitadel/zitadel/backend/v3/domain" "github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database" "github.com/zitadel/zitadel/backend/v3/storage/database"
"github.com/zitadel/zitadel/backend/v3/storage/database/dialect/postgres"
"github.com/zitadel/zitadel/backend/v3/storage/database/dialect/postgres/embedded" "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/postgres/embedded"
"github.com/zitadel/zitadel/backend/v3/storage/database/repository" "github.com/zitadel/zitadel/backend/v3/storage/database/repository"
"github.com/zitadel/zitadel/internal/integration" "github.com/zitadel/zitadel/internal/integration"
@@ -31,30 +32,48 @@ func runTests(m *testing.M) int {
var err error var err error
ctx := context.Background() ctx := context.Background()
pool, stop, err = newEmbeddedDB(ctx) pool, stop, err = newEmbeddedDB(ctx)
defer stop()
if err != nil { if err != nil {
log.Printf("error with embedded postgres database: %v", err) log.Printf("error with embedded postgres database: %v", err)
return 1 return 1
} }
defer stop() defer func() {
r := recover()
pool.Close(ctx)
stop()
if r != nil {
panic(r)
}
}()
return m.Run() return m.Run()
} }
func newEmbeddedDB(ctx context.Context) (pool database.PoolTest, stop func(), err error) { func newEmbeddedDB(ctx context.Context) (pool database.PoolTest, stop func(), err error) {
connector, stop, err := embedded.StartEmbedded() var connector database.Connector
if err != nil { if url := os.Getenv("ZITADEL_TEST_POSTGRES_URL"); url != "" {
return nil, nil, fmt.Errorf("unable to start embedded postgres: %w", err) log.Println("using database provided by env")
connector, err = postgres.DecodeConfig(url)
if err != nil {
return nil, nil, fmt.Errorf("unable to connect to provided postgres: %w", err)
}
stop = func() {}
} else {
connector, stop, err = embedded.StartEmbedded()
if err != nil {
return nil, nil, fmt.Errorf("unable to start embedded postgres: %w", err)
}
} }
pool_, err := connector.Connect(ctx) pool_, err := connector.Connect(ctx)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("unable to connect to embedded postgres: %w", err) return nil, stop, fmt.Errorf("unable to connect to embedded postgres: %w", err)
} }
pool = pool_.(database.PoolTest) pool = pool_.(database.PoolTest)
err = pool.MigrateTest(ctx) err = pool.MigrateTest(ctx)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("unable to migrate database: %w", err) return nil, stop, fmt.Errorf("unable to migrate database: %w", err)
} }
return pool, stop, err return pool, stop, err
} }
@@ -64,7 +83,8 @@ func transactionForRollback(t *testing.T) (tx database.Transaction, rollback fun
tx, err := pool.Begin(t.Context(), nil) tx, err := pool.Begin(t.Context(), nil)
require.NoError(t, err) require.NoError(t, err)
return tx, func() { return tx, func() {
err := tx.Rollback(t.Context()) // context.Background to ensure rollback does not return an error if test is already done
err := tx.Rollback(context.Background())
require.NoError(t, err) require.NoError(t, err)
} }
} }
@@ -74,12 +94,13 @@ func savepointForRollback(t *testing.T, tx database.Transaction) (savepoint data
savepoint, err := tx.Begin(t.Context()) savepoint, err := tx.Begin(t.Context())
require.NoError(t, err) require.NoError(t, err)
return savepoint, func() { return savepoint, func() {
err := savepoint.Rollback(t.Context()) // context.Background to ensure rollback does not return an error if test is already done
err := savepoint.Rollback(context.Background())
require.NoError(t, err) require.NoError(t, err)
} }
} }
func createInstance(t *testing.T, tx database.Transaction) (instanceID string) { func createInstance(t *testing.T, tx database.QueryExecutor) (instanceID string) {
t.Helper() t.Helper()
instance := domain.Instance{ instance := domain.Instance{
ID: gofakeit.UUID(), ID: gofakeit.UUID(),
@@ -97,7 +118,7 @@ func createInstance(t *testing.T, tx database.Transaction) (instanceID string) {
return instance.ID return instance.ID
} }
func createOrganization(t *testing.T, tx database.Transaction, instanceID string) (orgID string) { func createOrganization(t *testing.T, tx database.QueryExecutor, instanceID string) (orgID string) {
t.Helper() t.Helper()
org := domain.Organization{ org := domain.Organization{
InstanceID: instanceID, InstanceID: instanceID,
@@ -112,7 +133,7 @@ func createOrganization(t *testing.T, tx database.Transaction, instanceID string
return org.ID return org.ID
} }
func createProject(t *testing.T, tx database.Transaction, instanceID, orgID string) (projectID string) { func createProject(t *testing.T, tx database.QueryExecutor, instanceID, orgID string) (projectID string) {
t.Helper() t.Helper()
project := domain.Project{ project := domain.Project{
InstanceID: instanceID, InstanceID: instanceID,
@@ -128,7 +149,7 @@ func createProject(t *testing.T, tx database.Transaction, instanceID, orgID stri
return project.ID return project.ID
} }
func createProjectRole(t *testing.T, tx database.Transaction, instanceID, orgID, projectID, key string) string { func createProjectRole(t *testing.T, tx database.QueryExecutor, instanceID, orgID, projectID, key string) string {
t.Helper() t.Helper()
if key == "" { if key == "" {
key = integration.RoleKey() key = integration.RoleKey()
@@ -210,3 +231,46 @@ func createIDPIntent(t *testing.T, tx database.Transaction, instanceID, idpID st
return intent.ID return intent.ID
} }
func createMachineUser(t *testing.T, tx database.QueryExecutor, instanceID, orgID string) (userID string) {
t.Helper()
user := domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: gofakeit.UUID(),
Username: gofakeit.Username(),
State: domain.UserStateActive,
Machine: &domain.MachineUser{
Name: gofakeit.Name(),
},
}
userRepo := repository.UserRepository()
err := userRepo.Create(t.Context(), tx, &user)
require.NoError(t, err)
return user.ID
}
func createHumanUser(t *testing.T, tx database.QueryExecutor, instanceID, orgID string) string {
t.Helper()
user := &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: gofakeit.UUID(),
Username: gofakeit.Username(),
State: domain.UserStateActive,
Human: &domain.HumanUser{
FirstName: gofakeit.FirstName(),
LastName: gofakeit.LastName(),
Email: domain.HumanEmail{
Address: gofakeit.Email(),
},
Password: domain.HumanPassword{
Hash: "hashed-password",
},
},
}
userRepo := repository.UserRepository()
err := userRepo.Create(t.Context(), tx, user)
require.NoError(t, err)
return user.ID
}
@@ -176,7 +176,9 @@ func (s session) Create(ctx context.Context, client database.QueryExecutor, sess
) )
fingerprintID = session.UserAgent.FingerprintID fingerprintID = session.UserAgent.FingerprintID
} }
builder.WriteString(`INSERT INTO ` + s.qualifiedTableName() + ` (instance_id, id, lifetime, creator_id, user_agent_id, created_at, updated_at) VALUES ( `) builder.WriteString(`INSERT INTO `)
builder.WriteString(s.qualifiedTableName())
builder.WriteString(` (instance_id, id, lifetime, creator_id, user_agent_id, created_at, updated_at) VALUES ( `)
builder.WriteArgs(session.InstanceID, session.ID, session.Lifetime, session.CreatorID, fingerprintID, createdAt, updatedAt) builder.WriteArgs(session.InstanceID, session.ID, session.Lifetime, session.CreatorID, fingerprintID, createdAt, updatedAt)
builder.WriteString(` ) RETURNING created_at, updated_at`) builder.WriteString(` ) RETURNING created_at, updated_at`)
return client.QueryRow(ctx, builder.String(), builder.Args()...).Scan(&session.CreatedAt, &session.UpdatedAt) return client.QueryRow(ctx, builder.String(), builder.Args()...).Scan(&session.CreatedAt, &session.UpdatedAt)
@@ -232,6 +232,9 @@ func TestSession_Update(t *testing.T) {
err = instanceRepo.Create(t.Context(), tx, &instance) err = instanceRepo.Create(t.Context(), tx, &instance)
require.NoError(t, err) require.NoError(t, err)
orgID := createOrganization(t, tx, instanceId)
userID := createHumanUser(t, tx, instanceId, orgID)
testNow := time.Now() testNow := time.Now()
tests := []struct { tests := []struct {
name string name string
@@ -474,7 +477,7 @@ func TestSession_Update(t *testing.T) {
// update with updated values // update with updated values
session.Factors = []domain.SessionFactor{ session.Factors = []domain.SessionFactor{
&domain.SessionFactorUser{ &domain.SessionFactorUser{
UserID: "user-id", UserID: userID,
LastVerifiedAt: testNow, LastVerifiedAt: testNow,
}, },
} }
@@ -482,7 +485,7 @@ func TestSession_Update(t *testing.T) {
}, },
update: []database.Change{ update: []database.Change{
sessionRepo.SetFactor(&domain.SessionFactorUser{ sessionRepo.SetFactor(&domain.SessionFactorUser{
UserID: "user-id", UserID: userID,
LastVerifiedAt: testNow, LastVerifiedAt: testNow,
}), }),
}, },
@@ -748,7 +751,7 @@ func TestSession_Update(t *testing.T) {
session.TokenID = "new-token" session.TokenID = "new-token"
session.Factors = []domain.SessionFactor{ session.Factors = []domain.SessionFactor{
&domain.SessionFactorUser{ &domain.SessionFactorUser{
UserID: "user-id", UserID: userID,
LastVerifiedAt: testNow, LastVerifiedAt: testNow,
}, },
&domain.SessionFactorPassword{ &domain.SessionFactorPassword{
@@ -794,7 +797,7 @@ func TestSession_Update(t *testing.T) {
sessionRepo.SetUpdatedAt(testNow), sessionRepo.SetUpdatedAt(testNow),
sessionRepo.SetLifetime(time.Hour * 48), sessionRepo.SetLifetime(time.Hour * 48),
sessionRepo.SetFactor(&domain.SessionFactorUser{ sessionRepo.SetFactor(&domain.SessionFactorUser{
UserID: "user-id", UserID: userID,
LastVerifiedAt: testNow, LastVerifiedAt: testNow,
}), }),
sessionRepo.SetFactor(&domain.SessionFactorPassword{ sessionRepo.SetFactor(&domain.SessionFactorPassword{
@@ -846,7 +849,7 @@ func TestSession_Update(t *testing.T) {
updatedRows, err := sessionRepo.Update(t.Context(), tx, updatedRows, err := sessionRepo.Update(t.Context(), tx,
sessionRepo.PrimaryKeyCondition(session.InstanceID, session.ID), sessionRepo.PrimaryKeyCondition(session.InstanceID, session.ID),
sessionRepo.SetFactor(&domain.SessionFactorUser{ sessionRepo.SetFactor(&domain.SessionFactorUser{
UserID: "user-id", UserID: userID,
LastVerifiedAt: testNow, LastVerifiedAt: testNow,
}), }),
sessionRepo.SetFactor(&domain.SessionFactorPassword{ sessionRepo.SetFactor(&domain.SessionFactorPassword{
@@ -859,7 +862,7 @@ func TestSession_Update(t *testing.T) {
// update with updated values // update with updated values
session.Factors = []domain.SessionFactor{ session.Factors = []domain.SessionFactor{
&domain.SessionFactorUser{ &domain.SessionFactorUser{
UserID: "user-id", UserID: userID,
LastVerifiedAt: testNow, LastVerifiedAt: testNow,
}, },
} }
@@ -1101,9 +1104,12 @@ func TestSession_List(t *testing.T) {
err = instanceRepo.Create(t.Context(), tx, &instance) err = instanceRepo.Create(t.Context(), tx, &instance)
require.NoError(t, err) require.NoError(t, err)
orgID := createOrganization(t, tx, instanceId)
userIDs := []string{createHumanUser(t, tx, instanceId, orgID), createHumanUser(t, tx, instanceId, orgID)}
// create sessions // create sessions
sessions := make([]*domain.Session, 5) sessions := make([]*domain.Session, 5)
for i := 0; i < 5; i++ { for i := range 5 {
session := &domain.Session{ session := &domain.Session{
InstanceID: instanceId, InstanceID: instanceId,
ID: strconv.Itoa(i), ID: strconv.Itoa(i),
@@ -1138,7 +1144,7 @@ func TestSession_List(t *testing.T) {
session.Metadata = metadata session.Metadata = metadata
changes = append(changes, sessionRepo.SetMetadata(metadata)) changes = append(changes, sessionRepo.SetMetadata(metadata))
userFactor := &domain.SessionFactorUser{ userFactor := &domain.SessionFactorUser{
UserID: "user-" + strconv.Itoa(i%2), // two users: user-0 and user-1 UserID: userIDs[i%2],
LastVerifiedAt: time.Now(), LastVerifiedAt: time.Now(),
} }
session.Factors.AppendTo(userFactor) session.Factors.AppendTo(userFactor)
@@ -0,0 +1,479 @@
package repository
import (
"context"
"encoding/json"
"time"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
"github.com/zitadel/zitadel/internal/zerrors"
)
// -------------------------------------------------------------
// repository
// -------------------------------------------------------------
func UserRepository() domain.UserRepository {
return new(user)
}
func MachineUserRepository() domain.MachineUserRepository {
return &userMachine{user: user{}}
}
type user struct {
verification verification
tableName string
machineKey
userPersonalAccessToken
userMetadata
userPasskey
userIdentityProviderLink
}
func (u user) HumanRepository() domain.HumanUserRepository {
return userHuman{user: u}
}
// existingUser is used to get the columns and conditions for the CTE that selects the existing user in update and delete operations.
var existingUser = user{tableName: "existing_user"}
// Create implements [domain.UserRepository].
func (u user) Create(ctx context.Context, client database.QueryExecutor, user *domain.User) error {
var create func(context.Context, *database.StatementBuilder, database.QueryExecutor, *domain.User) error
switch {
case user.Human != nil:
create = userHuman{user: u}.create
case user.Machine != nil:
create = userMachine{user: u}.create
default:
return zerrors.ThrowInvalidArgument(nil, "REPOS-KxMnG", "no user type defined")
}
// we need to cheat a bit here to be able to use CTEChanges
// we pretend we have an existing user to be able to use the existing change mechanisms
builder := database.NewStatementBuilder("WITH existing_user AS (SELECT $1 AS instance_id, $2 AS organization_id, $3 AS id)", user.InstanceID, user.OrganizationID, user.ID)
return create(ctx, builder, client, user)
}
// Delete implements [domain.UserRepository].
func (u user) Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) {
if err := checkPKCondition(u, condition); err != nil {
return 0, err
}
builder := database.NewStatementBuilder("DELETE FROM zitadel.users")
writeCondition(builder, condition)
return client.Exec(ctx, builder.String(), builder.Args()...)
}
var queryUserStmt = "SELECT users.instance_id, users.organization_id, users.id, users.username" +
", users.state, users.created_at, users.updated_at" +
// metadata
`, jsonb_agg(DISTINCT jsonb_build_object('instanceId', user_metadata.instance_id, 'key', user_metadata.key, 'value', encode(user_metadata.value, 'base64'), 'createdAt', user_metadata.created_at, 'updatedAt', user_metadata.updated_at)) FILTER (WHERE user_metadata.user_id IS NOT NULL) AS metadata` +
// machine
`, CASE WHEN users.type = 'machine' THEN jsonb_build_object('name', users.name` +
`, 'description', users.description, 'secret', users.secret` +
`, 'accessTokenType', users.access_token_type` +
`, 'keys', jsonb_agg(DISTINCT jsonb_build_object('id', machine_keys.id, 'publicKey', encode(machine_keys.public_key, 'base64'), 'createdAt', machine_keys.created_at, 'expiresAt', machine_keys.expires_at, 'type', machine_keys.type)) FILTER (WHERE machine_keys.user_id IS NOT NULL)` +
`, 'pats', jsonb_agg(DISTINCT jsonb_build_object('id', user_personal_access_tokens.id, 'createdAt', user_personal_access_tokens.created_at, 'expiresAt', user_personal_access_tokens.expires_at, 'scopes', user_personal_access_tokens.scopes)) FILTER (WHERE user_personal_access_tokens.user_id IS NOT NULL)` +
`) END AS machine` +
// human
`, CASE WHEN users.type = 'human' THEN jsonb_build_object('firstName', users.first_name, 'lastName', users.last_name` +
`, 'nickname', users.nickname, 'displayName', users.display_name` +
`, 'preferredLanguage', users.preferred_language, 'gender', users.gender` +
`, 'avatarKey', users.avatar_key` +
`, 'multifactorInitializationSkippedAt', users.multifactor_initialization_skipped_at` +
`, 'password', jsonb_build_object('hash', users.password_hash, 'isChangeRequired', users.password_change_required, 'changedAt', users.password_changed_at, 'failedAttempts', users.password_failed_attempts, 'lastSuccessfullyCheckedAt', users.password_last_successful_check, 'pendingVerification', ` + verificationQuery(userHuman{}.passwordVerificationIDColumn()) + `)` +
`, 'email', jsonb_build_object('address', users.email, 'unverifiedAddress', users.unverified_email, 'verifiedAt', users.email_verified_at, 'otp', jsonb_build_object('enabledAt', users.email_otp_enabled_at, 'lastSuccessfullyCheckedAt', users.email_otp_last_successful_check, 'failedAttempts', users.email_otp_failed_attempts), 'pendingVerification', ` + verificationQuery(userHuman{}.emailVerificationIDColumn()) + `)` +
`, 'phone', CASE WHEN users.phone IS NOT NULL OR users.phone_verification_id IS NOT NULL THEN jsonb_build_object('number', users.phone, 'unverifiedNumber', users.unverified_phone, 'verifiedAt', users.phone_verified_at, 'otp', jsonb_build_object('enabledAt', users.sms_otp_enabled_at, 'lastSuccessfullyCheckedAt', users.sms_otp_last_successful_check, 'failedAttempts', users.sms_otp_failed_attempts), 'pendingVerification', ` + verificationQuery(userHuman{}.phoneVerificationIDColumn()) + `) ELSE NULL END` +
`, 'totp', CASE WHEN users.totp_secret IS NOT NULL THEN jsonb_build_object('secret', encode(users.totp_secret, 'escape')::JSONB, 'verifiedAt', users.totp_verified_at, 'lastSuccessfullyCheckedAt', users.totp_last_successful_check, 'failedAttempts', users.totp_failed_attempts) ELSE NULL END` +
`, 'passkeys', jsonb_agg(DISTINCT jsonb_build_object('id', user_passkeys.token_id, 'keyId', encode(user_passkeys.key_id, 'base64'), 'type', user_passkeys.type, 'name', user_passkeys.name, 'signCount', user_passkeys.sign_count, 'challenge', encode(user_passkeys.challenge, 'base64'), 'publicKey', encode(user_passkeys.public_key, 'base64'), 'attestationType', user_passkeys.attestation_type, 'aaGuid', encode(user_passkeys.authenticator_attestation_guid, 'base64'), 'rpId', user_passkeys.relying_party_id, 'createdAt', user_passkeys.created_at, 'updatedAt', user_passkeys.updated_at, 'verifiedAt', user_passkeys.verified_at)) FILTER (WHERE user_passkeys.user_id IS NOT NULL)` +
`, 'verifications', (SELECT jsonb_agg(jsonb_build_object('id', verifications.id, 'code', encode(verifications.code, 'escape')::JSONB, 'createdAt', verifications.created_at, 'updatedAt', verifications.updated_at, 'expiresAt', verifications.created_at+verifications.expiry, 'failedAttempts', verifications.failed_attempts)) FROM zitadel.verifications WHERE verifications.instance_id = users.instance_id AND verifications.user_id = users.id AND verifications.id NOT IN (COALESCE(users.password_verification_id, ''), COALESCE(users.email_verification_id, ''), COALESCE(users.phone_verification_id, ''), COALESCE(users.invite_verification_id, '')))` +
`, 'identityProviderLinks', jsonb_agg(DISTINCT jsonb_build_object('providerId', user_identity_provider_links.identity_provider_id, 'providedUserId', user_identity_provider_links.provided_user_id, 'providedUsername', user_identity_provider_links.provided_username, 'createdAt', user_identity_provider_links.created_at, 'updatedAt', user_identity_provider_links.updated_at)) FILTER (WHERE user_identity_provider_links.user_id IS NOT NULL)` +
`, 'invite', CASE WHEN users.invite_verification_id IS NOT NULL OR users.invite_accepted_at IS NOT NULL THEN jsonb_build_object('acceptedAt', users.invite_accepted_at, 'failedAttempts', users.invite_failed_attempts, 'pendingVerification', ` + verificationQuery(userHuman{}.inviteVerificationIDColumn()) + `) ELSE NULL END` +
`) END AS human FROM zitadel.users`
func verificationQuery(column database.Column) string {
var builder database.StatementBuilder
builder.WriteString("CASE WHEN ")
column.WriteQualified(&builder)
builder.WriteString(` IS NOT NULL THEN (SELECT row_to_json(res.*) FROM (SELECT verifications.id, encode(verifications.code, 'escape')::JSONB AS code, verifications.created_at as "createdAt", verifications.updated_at as "updatedAt", verifications.created_at+verifications.expiry AS "expiresAt", verifications.failed_attempts as "failedAttempts" FROM zitadel.verifications WHERE verifications.instance_id = users.instance_id AND verifications.id = `)
column.WriteQualified(&builder)
builder.WriteString(`) AS res) ELSE NULL END`)
return builder.String()
}
// Get implements [domain.UserRepository].
func (u user) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.User, error) {
options := new(database.QueryOpts)
for _, opt := range u.appendQueryOpts(opts) {
opt(options)
}
if !options.Condition.IsRestrictingColumn(u.InstanceIDColumn()) {
return nil, database.NewMissingConditionError(u.InstanceIDColumn())
}
builder := database.NewStatementBuilder(queryUserStmt)
options.Write(builder)
return scanUser(ctx, client, builder)
}
// List implements [domain.UserRepository].
func (u user) List(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) ([]*domain.User, error) {
options := new(database.QueryOpts)
for _, opt := range u.appendQueryOpts(opts) {
opt(options)
}
if !options.Condition.IsRestrictingColumn(u.InstanceIDColumn()) {
return nil, database.NewMissingConditionError(u.InstanceIDColumn())
}
builder := database.NewStatementBuilder(queryUserStmt)
options.Write(builder)
return scanUsers(ctx, client, builder)
}
func (u user) appendQueryOpts(opts []database.QueryOption) []database.QueryOption {
return append(opts,
u.joinMachineKeys(),
u.joinPATs(),
u.joinMetadata(),
u.joinVerifications(),
u.joinPasskeys(),
u.joinIdentityProviderLinks(),
database.WithGroupBy(u.PrimaryKeyColumns()...),
)
}
// Update implements [domain.UserRepository].
func (u user) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) {
if err := checkPKCondition(u, condition); err != nil {
return 0, err
}
if len(changes) == 0 {
return 0, database.ErrNoChanges
}
if !database.Changes(changes).IsOnColumn(u.updatedAtColumn()) {
changes = append(changes, u.clearUpdatedAt())
}
builder := database.NewStatementBuilder("WITH existing_user AS (SELECT * FROM zitadel.users")
writeCondition(builder, condition)
builder.WriteString(") ")
for i, change := range changes {
sessionCTE(change, i, 0, builder)
}
builder.WriteString("UPDATE zitadel.users SET ")
if err := database.Changes(changes).Write(builder); err != nil {
return 0, err
}
builder.WriteString(" FROM existing_user")
writeCondition(builder, database.And(
database.NewColumnCondition(u.IDColumn(), existingUser.IDColumn()),
database.NewColumnCondition(u.InstanceIDColumn(), existingUser.InstanceIDColumn()),
))
return client.Exec(ctx, builder.String(), builder.Args()...)
}
func (u user) unqualifiedTableName() string {
if u.tableName != "" {
return u.tableName
}
return "users"
}
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
// SetState implements [domain.UserRepository].
func (u user) SetState(state domain.UserState) database.Change {
return database.NewChange(u.StateColumn(), state)
}
// SetUpdatedAt implements [domain.UserRepository].
func (u user) SetUpdatedAt(updatedAt time.Time) database.Change {
return database.NewChange(u.updatedAtColumn(), updatedAt)
}
// SetUsername implements [domain.UserRepository].
func (u user) SetUsername(username string) database.Change {
return database.NewChange(u.UsernameColumn(), username)
}
func (u user) clearUpdatedAt() database.Change {
return database.NewChange(u.updatedAtColumn(), database.NullInstruction)
}
// -------------------------------------------------------------
// conditions
// -------------------------------------------------------------
// IDCondition implements [domain.UserRepository].
func (u user) IDCondition(userID string) database.Condition {
return database.NewTextCondition(u.IDColumn(), database.TextOperationEqual, userID)
}
// InstanceIDCondition implements [domain.UserRepository].
func (u user) InstanceIDCondition(instanceID string) database.Condition {
return database.NewTextCondition(u.InstanceIDColumn(), database.TextOperationEqual, instanceID)
}
// LoginNameCondition implements [domain.UserRepository].
func (u user) LoginNameCondition(op database.TextOperation, loginName string) database.Condition {
panic("unimplemented")
}
// OrganizationIDCondition implements [domain.UserRepository].
func (u user) OrganizationIDCondition(orgID string) database.Condition {
return database.NewTextCondition(u.organizationIDColumn(), database.TextOperationEqual, orgID)
}
// PrimaryKeyCondition implements [domain.UserRepository].
func (u user) PrimaryKeyCondition(instanceID string, userID string) database.Condition {
return database.And(
u.InstanceIDCondition(instanceID),
u.IDCondition(userID),
)
}
// StateCondition implements [domain.UserRepository].
func (u user) StateCondition(state domain.UserState) database.Condition {
return database.NewNumberCondition(u.StateColumn(), database.NumberOperationEqual, state)
}
// TypeCondition implements [domain.UserRepository].
func (u user) TypeCondition(userType domain.UserType) database.Condition {
return database.NewNumberCondition(u.TypeColumn(), database.NumberOperationEqual, userType)
}
// UsernameCondition implements [domain.UserRepository].
func (u user) UsernameCondition(op database.TextOperation, username string) database.Condition {
return database.NewTextCondition(u.UsernameColumn(), op, username)
}
// ExistsMetadata implements [domain.UserRepository].
func (u user) ExistsMetadata(condition database.Condition) database.Condition {
return database.Exists(
u.userMetadata.qualifiedTableName(),
database.And(
database.NewColumnCondition(u.InstanceIDColumn(), u.userMetadata.instanceIDColumn()),
database.NewColumnCondition(u.IDColumn(), u.userMetadata.userIDColumn()),
condition,
),
)
}
// ExistsPasskey implements [domain.HumanUserRepository].
func (u user) ExistsPasskey(condition database.Condition) database.Condition {
return database.Exists(
u.userPasskey.qualifiedTableName(),
database.And(
database.NewColumnCondition(u.InstanceIDColumn(), u.userPasskey.instanceIDColumn()),
database.NewColumnCondition(u.IDColumn(), u.userPasskey.userIDColumn()),
condition,
),
)
}
// ExistsIdentityProviderLink implements [domain.HumanUserRepository].
func (u user) ExistsIdentityProviderLink(condition database.Condition) database.Condition {
return database.Exists(
u.userIdentityProviderLink.qualifiedTableName(),
database.And(
database.NewColumnCondition(u.InstanceIDColumn(), u.userIdentityProviderLink.instanceIDColumn()),
database.NewColumnCondition(u.IDColumn(), u.userIdentityProviderLink.userIDColumn()),
condition,
),
)
}
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
// PrimaryKeyColumns implements [domain.UserRepository].
func (u user) PrimaryKeyColumns() []database.Column {
return database.Columns{
u.InstanceIDColumn(),
u.IDColumn(),
}
}
// CreatedAtColumn implements [domain.UserRepository].
func (u user) CreatedAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "created_at")
}
// StateColumn implements [domain.UserRepository].
func (u user) StateColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "state")
}
// TypeColumn implements [domain.UserRepository].
func (u user) TypeColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "type")
}
// UsernameColumn implements [domain.UserRepository].
func (u user) UsernameColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "username")
}
// IDColumn implements [domain.UserRepository].
func (u user) IDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "id")
}
func (u user) InstanceIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "instance_id")
}
func (u user) updatedAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "updated_at")
}
func (u user) organizationIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "organization_id")
}
// -------------------------------------------------------------
// scanners
// -------------------------------------------------------------
type rawUser struct {
domain.User
Machine *json.RawMessage `json:"machine,omitempty" db:"machine"`
Human *json.RawMessage `json:"human,omitempty" db:"human"`
}
func (u *rawUser) toDomain() (*domain.User, error) {
if u.Machine != nil {
err := json.Unmarshal(*u.Machine, &u.User.Machine)
if err != nil {
return nil, err
}
} else if u.Human != nil {
err := json.Unmarshal(*u.Human, &u.User.Human)
if err != nil {
return nil, err
}
}
return &u.User, nil
}
func scanUser(ctx context.Context, client database.QueryExecutor, builder *database.StatementBuilder) (*domain.User, error) {
rows, err := client.Query(ctx, builder.String(), builder.Args()...)
if err != nil {
return nil, err
}
var user rawUser
if err = rows.(database.CollectableRows).CollectExactlyOneRow(&user); err != nil {
return nil, err
}
return user.toDomain()
}
func scanUsers(ctx context.Context, client database.QueryExecutor, builder *database.StatementBuilder) ([]*domain.User, error) {
rows, err := client.Query(ctx, builder.String(), builder.Args()...)
if err != nil {
return nil, err
}
var users []rawUser
if err = rows.(database.CollectableRows).Collect(&users); err != nil {
return nil, err
}
result := make([]*domain.User, len(users))
for i, user := range users {
domainUser, err := user.toDomain()
if err != nil {
return nil, err
}
result[i] = domainUser
}
return result, nil
}
// -------------------------------------------------------------
// sub repositories
// -------------------------------------------------------------
// Human implements [domain.UserRepository].
func (u user) Human() domain.HumanUserRepository {
return userHuman{user: u}
}
// Machine implements [domain.UserRepository].
func (u user) Machine() domain.MachineUserRepository {
return userMachine{user: u}
}
func (u user) joinMachineKeys() database.QueryOption {
return database.WithLeftJoin(
u.machineKey.qualifiedTableName(),
database.And(
database.NewColumnCondition(u.InstanceIDColumn(), u.machineKey.instanceIDColumn()),
database.NewColumnCondition(u.IDColumn(), u.machineKey.userIDColumn()),
),
)
}
func (u user) joinPATs() database.QueryOption {
return database.WithLeftJoin(
u.userPersonalAccessToken.qualifiedTableName(),
database.And(
database.NewColumnCondition(u.InstanceIDColumn(), u.userPersonalAccessToken.instanceIDColumn()),
database.NewColumnCondition(u.IDColumn(), u.userPersonalAccessToken.userIDColumn()),
),
)
}
func (u user) joinMetadata() database.QueryOption {
return database.WithLeftJoin(
u.userMetadata.qualifiedTableName(),
database.And(
database.NewColumnCondition(u.InstanceIDColumn(), u.userMetadata.instanceIDColumn()),
database.NewColumnCondition(u.IDColumn(), u.userMetadata.userIDColumn()),
),
)
}
func (u user) joinPasskeys() database.QueryOption {
return database.WithLeftJoin(
u.userPasskey.qualifiedTableName(),
database.And(
database.NewColumnCondition(u.InstanceIDColumn(), u.userPasskey.instanceIDColumn()),
database.NewColumnCondition(u.IDColumn(), u.userPasskey.userIDColumn()),
),
)
}
func (u user) joinVerifications() database.QueryOption {
return database.WithLeftJoin(
u.verification.qualifiedTableName(),
database.And(
database.NewColumnCondition(u.InstanceIDColumn(), u.verification.instanceIDColumn()),
database.NewColumnCondition(u.IDColumn(), u.verification.userIDColumn()),
),
)
}
func (u user) joinIdentityProviderLinks() database.QueryOption {
return database.WithLeftJoin(
u.userIdentityProviderLink.qualifiedTableName(),
database.And(
database.NewColumnCondition(u.InstanceIDColumn(), u.userIdentityProviderLink.instanceIDColumn()),
database.NewColumnCondition(u.IDColumn(), u.userIdentityProviderLink.userIDColumn()),
),
)
}
@@ -0,0 +1,486 @@
package repository
import (
"context"
"fmt"
"maps"
"slices"
"strings"
"time"
"github.com/muhlemmer/gu"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/instrumentation/logging"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
// -------------------------------------------------------------
// repository
// -------------------------------------------------------------
type userHuman struct {
user
}
var existingHumanUser = userHuman{
user: user{
tableName: "existing_user",
},
}
func HumanUserRepository() domain.HumanUserRepository {
return &userHuman{
user: user{},
}
}
func (u userHuman) create(ctx context.Context, builder *database.StatementBuilder, client database.QueryExecutor, user *domain.User) error {
var createdAt any = database.NowInstruction
if !user.CreatedAt.IsZero() {
createdAt = user.CreatedAt
}
columnValues := map[string]any{
"instance_id": user.InstanceID,
"organization_id": user.OrganizationID,
"id": user.ID,
"username": user.Username,
"state": user.State,
"type": "human",
"first_name": user.Human.FirstName,
"last_name": user.Human.LastName,
"created_at": createdAt,
"updated_at": createdAt,
}
if !user.Human.MultifactorInitializationSkippedAt.IsZero() {
columnValues["multifactor_initialization_skipped_at"] = user.Human.MultifactorInitializationSkippedAt
}
columnValues = u.setOptionalProfileColumns(columnValues, user.Human)
ctes := make(map[string]database.CTEChange)
columnValues, ctes = u.setPasswordColumns(columnValues, ctes, user, createdAt)
columnValues, ctes = u.setEmailColumns(columnValues, ctes, user, createdAt)
columnValues, ctes = u.setPhoneColumns(columnValues, ctes, user, createdAt)
columnValues, ctes = u.setInviteColumns(columnValues, ctes, user, createdAt)
for i, passkey := range user.Human.Passkeys {
ctes[fmt.Sprintf("passkey_%d", i)] = u.AddPasskey(passkey).(database.CTEChange)
}
if user.Human.TOTP != nil {
columnValues["totp_secret"] = user.Human.TOTP.Secret
if !user.Human.TOTP.VerifiedAt.IsZero() {
columnValues["totp_verified_at"] = user.Human.TOTP.VerifiedAt
}
}
for i, link := range user.Human.IdentityProviderLinks {
name := fmt.Sprintf("idp_link_%d", i)
ctes[name] = u.AddIdentityProviderLink(link).(database.CTEChange)
}
for i, verification := range user.Human.Verifications {
ctes[fmt.Sprintf("verification_%d", i)] = u.SetVerification(&domain.VerificationTypeInit{
ID: gu.Ptr(verification.ID),
CreatedAt: user.CreatedAt,
Code: verification.Code,
}).(database.CTEChange)
}
for i, metadata := range user.Metadata {
ctes[fmt.Sprintf("metadata_%d", i)] = u.SetMetadata(metadata).(database.CTEChange)
}
// write CTE changes
for name, cte := range ctes {
cte.SetName(name)
builder.WriteString(", ")
builder.WriteString(name)
builder.WriteString(" AS (")
cte.WriteCTE(builder)
builder.WriteString(")")
}
columns := slices.Sorted(maps.Keys(columnValues))
// write final insert
builder.WriteString(" INSERT INTO zitadel.users (")
builder.WriteString(strings.Join(columns, ", "))
builder.WriteString(") VALUES (")
for i, column := range columns {
if i > 0 {
builder.WriteString(", ")
}
value := columnValues[column]
if fn, ok := value.(func(builder *database.StatementBuilder)); ok {
fn(builder)
continue
}
builder.WriteArg(value)
}
builder.WriteString(") RETURNING created_at, updated_at")
return client.QueryRow(ctx, builder.String(), builder.Args()...).Scan(&user.CreatedAt, &user.UpdatedAt)
}
func (u userHuman) setPasswordColumns(columnValues map[string]any, ctes map[string]database.CTEChange, user *domain.User, createdAt any) (map[string]any, map[string]database.CTEChange) {
if user.Human.Password.PendingVerification != nil {
verification := &domain.VerificationTypeInit{
CreatedAt: user.CreatedAt,
Code: user.Human.Password.PendingVerification.Code,
}
if user.Human.Password.PendingVerification.ID != "" {
verification.ID = &user.Human.Password.PendingVerification.ID
}
if user.Human.Password.PendingVerification.ExpiresAt != nil && !user.Human.Password.PendingVerification.ExpiresAt.IsZero() {
verification.Expiry = gu.Ptr(time.Since(*user.Human.Password.PendingVerification.ExpiresAt))
}
ctes["password_verification"] = u.SetResetPasswordVerification(verification).(database.CTEChange)
columnValues["password_verification_id"] = func(builder *database.StatementBuilder) {
builder.WriteString(`(SELECT id FROM password_verification)`)
}
} else if user.Human.Password.Hash != "" {
columnValues["password_hash"] = user.Human.Password.Hash
columnValues["password_changed_at"] = createdAt
if !user.Human.Password.ChangedAt.IsZero() {
columnValues["password_changed_at"] = user.Human.Password.ChangedAt
}
}
return columnValues, ctes
}
func (u userHuman) setEmailColumns(columnValues map[string]any, ctes map[string]database.CTEChange, user *domain.User, createdAt any) (map[string]any, map[string]database.CTEChange) {
if user.Human.Email.PendingVerification != nil {
verification := &domain.VerificationTypeInit{
CreatedAt: user.CreatedAt,
Code: user.Human.Email.PendingVerification.Code,
}
if user.Human.Email.PendingVerification.ID != "" {
verification.ID = &user.Human.Email.PendingVerification.ID
}
if user.Human.Email.PendingVerification.ExpiresAt != nil && !user.Human.Email.PendingVerification.ExpiresAt.IsZero() {
verification.Expiry = gu.Ptr(time.Since(*user.Human.Email.PendingVerification.ExpiresAt))
}
ctes["email_verification"] = u.SetEmailVerification(verification).(database.CTEChange)
columnValues["email_verification_id"] = func(builder *database.StatementBuilder) {
builder.WriteString(`(SELECT id FROM email_verification)`)
}
}
if user.Human.Email.Address != "" {
columnValues["email"] = user.Human.Email.Address
columnValues["unverified_email"] = user.Human.Email.Address
columnValues["email_verified_at"] = createdAt
if !user.Human.Email.VerifiedAt.IsZero() {
columnValues["email_verified_at"] = user.Human.Email.VerifiedAt
}
}
if user.Human.Email.UnverifiedAddress != "" {
columnValues["unverified_email"] = user.Human.Email.UnverifiedAddress
}
return columnValues, ctes
}
func (u userHuman) setPhoneColumns(columnValues map[string]any, ctes map[string]database.CTEChange, user *domain.User, createdAt any) (map[string]any, map[string]database.CTEChange) {
if user.Human.Phone == nil {
return columnValues, ctes
}
if user.Human.Phone.PendingVerification != nil {
verification := &domain.VerificationTypeInit{
CreatedAt: user.CreatedAt,
Code: user.Human.Phone.PendingVerification.Code,
}
if user.Human.Phone.PendingVerification.ID != "" {
verification.ID = &user.Human.Phone.PendingVerification.ID
}
if user.Human.Phone.PendingVerification.ExpiresAt != nil && !user.Human.Phone.PendingVerification.ExpiresAt.IsZero() {
verification.Expiry = gu.Ptr(time.Since(*user.Human.Phone.PendingVerification.ExpiresAt))
}
ctes["phone_verification"] = u.SetPhoneVerification(verification).(database.CTEChange)
columnValues["phone_verification_id"] = func(builder *database.StatementBuilder) {
builder.WriteString(`(SELECT id FROM phone_verification)`)
}
}
if user.Human.Phone.Number != "" {
columnValues["phone"] = user.Human.Phone.Number
columnValues["unverified_phone"] = user.Human.Phone.Number
columnValues["phone_verified_at"] = createdAt
if !user.Human.Phone.VerifiedAt.IsZero() {
columnValues["phone_verified_at"] = user.Human.Phone.VerifiedAt
}
}
if user.Human.Phone.UnverifiedNumber != "" {
columnValues["unverified_phone"] = user.Human.Phone.UnverifiedNumber
}
return columnValues, ctes
}
func (u userHuman) setInviteColumns(columnValues map[string]any, ctes map[string]database.CTEChange, user *domain.User, createdAt any) (map[string]any, map[string]database.CTEChange) {
if user.Human.Invite == nil {
return columnValues, ctes
}
if user.Human.Invite.PendingVerification != nil {
verification := &domain.VerificationTypeInit{
CreatedAt: user.CreatedAt,
Code: user.Human.Invite.PendingVerification.Code,
}
if user.Human.Invite.PendingVerification.ID != "" {
verification.ID = &user.Human.Invite.PendingVerification.ID
}
if user.Human.Invite.PendingVerification.ExpiresAt != nil && !user.Human.Invite.PendingVerification.ExpiresAt.IsZero() {
verification.Expiry = gu.Ptr(time.Since(*user.Human.Invite.PendingVerification.ExpiresAt))
}
ctes["invite_verification"] = u.SetInviteVerification(verification).(database.CTEChange)
}
if !user.Human.Invite.AcceptedAt.IsZero() {
columnValues["invite_accepted_at"] = createdAt
}
return columnValues, ctes
}
func (u userHuman) setOptionalProfileColumns(columnValues map[string]any, human *domain.HumanUser) map[string]any {
if !human.PreferredLanguage.IsRoot() {
columnValues["preferred_language"] = human.PreferredLanguage
}
if human.DisplayName != "" {
columnValues["display_name"] = human.DisplayName
}
if human.Nickname != "" {
columnValues["nickname"] = human.Nickname
}
if human.Gender != domain.HumanGenderUnspecified {
columnValues["gender"] = human.Gender
}
if human.AvatarKey != "" {
columnValues["avatar_key"] = human.AvatarKey
}
if human.Password.IsChangeRequired {
columnValues["password_change_required"] = true
}
return columnValues
}
func (u userHuman) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) {
if !condition.IsRestrictingColumn(u.TypeColumn()) {
condition = database.And(condition, u.TypeCondition(domain.UserTypeHuman))
}
return u.user.Update(ctx, client, condition, changes...)
}
var _ domain.HumanUserRepository = (*userHuman)(nil)
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
// SetAvatarKey implements [domain.HumanUserRepository].
func (u userHuman) SetAvatarKey(avatarKey *string) database.Change {
return database.NewChangePtr(u.avatarKeyColumn(), avatarKey)
}
// SetDisplayName implements [domain.HumanUserRepository].
func (u userHuman) SetDisplayName(displayName string) database.Change {
return database.NewChange(u.DisplayNameColumn(), displayName)
}
// SetFirstName implements [domain.HumanUserRepository].
func (u userHuman) SetFirstName(firstName string) database.Change {
return database.NewChange(u.FirstNameColumn(), firstName)
}
// SetGender implements [domain.HumanUserRepository].
func (u userHuman) SetGender(gender domain.HumanGender) database.Change {
return database.NewChange(u.genderColumn(), gender)
}
// SetLastName implements [domain.HumanUserRepository].
func (u userHuman) SetLastName(lastName string) database.Change {
return database.NewChange(u.LastNameColumn(), lastName)
}
// SkipMultifactorInitializationAt implements [domain.HumanUserRepository].
func (u userHuman) SkipMultifactorInitializationAt(skippedAt time.Time) database.Change {
if skippedAt.IsZero() {
return u.SkipMultifactorInitialization()
}
return database.NewChange(u.multifactorInitializationSkippedAtColumn(), skippedAt)
}
// SkipMultifactorInitialization implements [domain.HumanUserRepository].
func (u userHuman) SkipMultifactorInitialization() database.Change {
return database.NewChange(u.multifactorInitializationSkippedAtColumn(), database.NowInstruction)
}
// SetNickname implements [domain.HumanUserRepository].
func (u userHuman) SetNickname(nickname string) database.Change {
return database.NewChange(u.NicknameColumn(), nickname)
}
// SetPreferredLanguage implements [domain.HumanUserRepository].
func (u userHuman) SetPreferredLanguage(preferredLanguage language.Tag) database.Change {
if preferredLanguage == language.Und {
return database.NewChangeToNull(u.preferredLanguageColumn())
}
return database.NewChange(u.preferredLanguageColumn(), preferredLanguage.String())
}
// SetVerification implements [domain.HumanUserRepository].
func (u userHuman) SetVerification(verification domain.VerificationType) database.Change {
switch typ := verification.(type) {
case *domain.VerificationTypeInit:
return database.NewCTEChange(func(builder *database.StatementBuilder) {
var (
createdAt any = database.NowInstruction
expiry any = database.NullInstruction
id any = database.DefaultInstruction
)
if !typ.CreatedAt.IsZero() {
createdAt = typ.CreatedAt
}
if typ.Expiry != nil {
expiry = *typ.Expiry
}
if typ.ID != nil {
id = *typ.ID
}
builder.WriteString("INSERT INTO zitadel.verifications(instance_id, user_id, id, code, created_at, expiry) SELECT instance_id, id, ")
builder.WriteArgs(id, typ.Code, createdAt, expiry)
builder.WriteString(" FROM ")
builder.WriteString(existingHumanUser.unqualifiedTableName())
builder.WriteString(" RETURNING id")
}, nil)
case *domain.VerificationTypeSucceeded:
return database.NewCTEChange(func(builder *database.StatementBuilder) {
builder.WriteString("DELETE FROM zitadel.verifications USING existing_user")
writeCondition(builder, database.And(
database.NewColumnCondition(u.verification.instanceIDColumn(), existingHumanUser.InstanceIDColumn()),
database.NewColumnCondition(u.verification.userIDColumn(), existingHumanUser.IDColumn()),
database.NewTextCondition(u.verification.idColumn(), database.TextOperationEqual, *typ.ID),
))
}, nil)
case *domain.VerificationTypeUpdate:
changes := make(database.Changes, 0, 3)
if typ.Code != nil {
changes = append(changes, database.NewChange(u.verification.codeColumn(), typ.Code))
}
if typ.Expiry != nil {
changes = append(changes, database.NewChange(u.verification.expiryColumn(), *typ.Expiry))
}
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("UPDATE zitadel.verifications SET ")
err := changes.Write(builder)
logging.New(logging.StreamRuntime).Debug("write changes in cte failed", "error", err)
builder.WriteString(" FROM existing_user")
writeCondition(builder, database.And(
database.NewColumnCondition(u.verification.instanceIDColumn(), existingHumanUser.InstanceIDColumn()),
database.NewColumnCondition(u.verification.userIDColumn(), existingHumanUser.IDColumn()),
database.NewTextCondition(u.verification.idColumn(), database.TextOperationEqual, *typ.ID),
))
},
nil,
)
case *domain.VerificationTypeSkipped:
panic("skip verification is not supported for verifications")
case *domain.VerificationTypeFailed:
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("UPDATE ")
builder.WriteString(u.verification.qualifiedTableName())
builder.WriteString(" SET ")
err := database.NewIncrementColumnChange(u.verification.failedAttemptsColumn(), database.Coalesce(u.verification.failedAttemptsColumn(), 0)).Write(builder)
logging.New(logging.StreamRuntime).Debug("write cte failed", "error", err)
builder.WriteString(" FROM existing_user")
writeCondition(builder, database.And(
database.NewColumnCondition(u.verification.instanceIDColumn(), existingHumanUser.InstanceIDColumn()),
database.NewColumnCondition(u.verification.userIDColumn(), existingHumanUser.IDColumn()),
database.NewTextCondition(u.verification.idColumn(), database.TextOperationEqual, *typ.ID),
))
},
nil,
)
}
panic(fmt.Sprintf("undefined verification type %T", verification))
}
// -------------------------------------------------------------
// conditions
// -------------------------------------------------------------
// DisplayNameCondition implements [domain.HumanUserRepository].
func (u userHuman) DisplayNameCondition(op database.TextOperation, displayName string) database.Condition {
return database.NewTextCondition(u.DisplayNameColumn(), op, displayName)
}
// FirstNameCondition implements [domain.HumanUserRepository].
func (u userHuman) FirstNameCondition(op database.TextOperation, firstName string) database.Condition {
return database.NewTextCondition(u.FirstNameColumn(), op, firstName)
}
// LastNameCondition implements [domain.HumanUserRepository].
func (u userHuman) LastNameCondition(op database.TextOperation, lastName string) database.Condition {
return database.NewTextCondition(u.LastNameColumn(), op, lastName)
}
// NicknameCondition implements [domain.HumanUserRepository].
func (u userHuman) NicknameCondition(op database.TextOperation, nickname string) database.Condition {
return database.NewTextCondition(u.NicknameColumn(), op, nickname)
}
// PreferredLanguageCondition implements [domain.HumanUserRepository].
func (u userHuman) PreferredLanguageCondition(lang language.Tag) database.Condition {
return database.NewTextCondition(u.preferredLanguageColumn(), database.TextOperationEqual, lang.String())
}
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
// DisplayNameColumn implements [domain.HumanUserRepository].
func (u userHuman) DisplayNameColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "display_name")
}
func (u userHuman) genderColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "gender")
}
func (u userHuman) avatarKeyColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "avatar_key")
}
// FirstNameColumn implements [domain.HumanUserRepository].
func (u userHuman) FirstNameColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "first_name")
}
// LastNameColumn implements [domain.HumanUserRepository].
func (u userHuman) LastNameColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "last_name")
}
// NicknameColumn implements [domain.HumanUserRepository].
func (u userHuman) NicknameColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "nickname")
}
func (u userHuman) multifactorInitializationSkippedAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "multifactor_initialization_skipped_at")
}
func (u userHuman) preferredLanguageColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "preferred_language")
}
// -------------------------------------------------------------
// scanners
// -------------------------------------------------------------
// -------------------------------------------------------------
// sub repositories
// -------------------------------------------------------------
@@ -0,0 +1,132 @@
package repository
import (
"fmt"
"time"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
func (u userHuman) SetEmail(email string) database.Change {
return database.NewChange(u.EmailColumn(), email)
}
func (u userHuman) SetUnverifiedEmail(email string) database.Change {
return database.NewChange(u.unverifiedEmailColumn(), email)
}
// SetEmailVerification implements [domain.HumanUserRepository].
func (u userHuman) SetEmailVerification(verification domain.VerificationType) database.Change {
switch typ := verification.(type) {
case *domain.VerificationTypeInit:
return u.verification.init(typ, existingHumanUser.unqualifiedTableName(), existingHumanUser.emailVerificationIDColumn())
case *domain.VerificationTypeUpdate:
return u.verification.update(typ, existingHumanUser.unqualifiedTableName(),
existingHumanUser.InstanceIDColumn(), existingHumanUser.emailVerificationIDColumn())
case *domain.VerificationTypeSucceeded:
return database.NewChanges(
u.verification.verified(typ, existingUser.unqualifiedTableName(), existingUser.InstanceIDColumn(),
existingHumanUser.emailVerificationIDColumn(), u.emailVerifiedAtColumn(), u.failedEmailOTPAttemptsColumn(),
),
database.NewChangeToColumn(u.EmailColumn(), u.unverifiedEmailColumn()),
)
case *domain.VerificationTypeFailed:
return u.verification.failed(existingHumanUser.unqualifiedTableName(), existingHumanUser.InstanceIDColumn(), existingHumanUser.emailVerificationIDColumn())
case *domain.VerificationTypeSkipped:
return u.verification.skipped(typ, u.emailVerifiedAtColumn(), u.emailVerificationIDColumn(), u.failedEmailOTPAttemptsColumn())
}
panic(fmt.Sprintf("type not allowed for email verification change %T", verification))
}
// EnableEmailOTPAt implements [domain.HumanUserRepository].
func (u userHuman) EnableEmailOTPAt(enabledAt time.Time) database.Change {
return database.NewChange(u.emailOTPEnabledAtColumn(), enabledAt)
}
// EnableEmailOTP implements [domain.HumanUserRepository].
func (u userHuman) EnableEmailOTP() database.Change {
return database.NewChange(u.emailOTPEnabledAtColumn(), database.NowInstruction)
}
// DisableEmailOTP implements [domain.HumanUserRepository].
func (u userHuman) DisableEmailOTP() database.Change {
return database.NewChangeToNull(u.emailOTPEnabledAtColumn())
}
func (u userHuman) SetLastSuccessfulEmailOTPCheck(checkedAt time.Time) database.Change {
if checkedAt.IsZero() {
return database.NewChanges(
database.NewChange(u.lastSuccessfulEmailOTPCheckColumn(), database.NowInstruction),
u.ResetEmailOTPFailedAttempts(),
)
}
return database.NewChanges(
database.NewChange(u.lastSuccessfulEmailOTPCheckColumn(), checkedAt),
u.ResetEmailOTPFailedAttempts(),
)
}
func (u userHuman) IncrementEmailOTPFailedAttempts() database.Change {
return database.NewIncrementColumnChange(u.failedEmailOTPAttemptsColumn(), database.Coalesce(u.failedEmailOTPAttemptsColumn(), 0))
}
func (u userHuman) ResetEmailOTPFailedAttempts() database.Change {
return database.NewChange(u.failedEmailOTPAttemptsColumn(), 0)
}
// -------------------------------------------------------------
// conditions
// -------------------------------------------------------------
// EmailCondition implements [domain.HumanUserRepository].
func (u userHuman) EmailCondition(op database.TextOperation, email string) database.Condition {
return database.Or(u.VerifiedEmailCondition(op, email), u.UnverifiedEmailCondition(op, email))
}
// UnverifiedEmailCondition implements [domain.HumanUserRepository].
func (u userHuman) UnverifiedEmailCondition(op database.TextOperation, email string) database.Condition {
return database.NewTextCondition(u.unverifiedEmailColumn(), op, email)
}
// VerifiedEmailCondition implements [domain.HumanUserRepository].
func (u userHuman) VerifiedEmailCondition(op database.TextOperation, email string) database.Condition {
return database.NewTextCondition(u.EmailColumn(), op, email)
}
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
// EmailColumn implements [domain.HumanUserRepository].
func (u userHuman) EmailColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "email")
}
func (u userHuman) unverifiedEmailColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "unverified_email")
}
func (u userHuman) emailOTPEnabledAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "email_otp_enabled_at")
}
func (u userHuman) emailVerifiedAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "email_verified_at")
}
func (u userHuman) emailVerificationIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "email_verification_id")
}
func (u userHuman) failedEmailOTPAttemptsColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "email_otp_failed_attempts")
}
func (u userHuman) lastSuccessfulEmailOTPCheckColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "email_otp_last_successful_check")
}
@@ -0,0 +1,92 @@
package repository
import (
"fmt"
"time"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
func (u userHuman) SetPassword(password string) database.Change {
return database.NewChange(u.passwordHashColumn(), password)
}
// SetResetPasswordVerification implements [domain.HumanUserRepository].
func (u userHuman) SetResetPasswordVerification(verification domain.VerificationType) database.Change {
switch typ := verification.(type) {
case *domain.VerificationTypeInit:
return u.verification.init(typ, existingUser.unqualifiedTableName(), existingHumanUser.passwordVerificationIDColumn())
case *domain.VerificationTypeUpdate:
return u.verification.update(typ, existingHumanUser.unqualifiedTableName(),
existingHumanUser.InstanceIDColumn(), existingHumanUser.passwordVerificationIDColumn(),
)
case *domain.VerificationTypeSucceeded:
return u.verification.verified(typ, existingHumanUser.unqualifiedTableName(), existingHumanUser.InstanceIDColumn(),
existingHumanUser.passwordVerificationIDColumn(), u.passwordVerifiedAtColumn(), u.failedPasswordAttemptsColumn(),
)
case *domain.VerificationTypeSkipped:
return u.verification.skipped(typ, u.passwordVerifiedAtColumn(), u.passwordVerificationIDColumn(), u.failedPasswordAttemptsColumn())
case *domain.VerificationTypeFailed:
return u.verification.failed(existingHumanUser.unqualifiedTableName(), existingHumanUser.InstanceIDColumn(), existingHumanUser.passwordVerificationIDColumn())
}
panic(fmt.Sprintf("undefined verification type %T", verification))
}
// SetPasswordChangeRequired implements [domain.HumanUserRepository].
func (u userHuman) SetPasswordChangeRequired(required bool) database.Change {
return database.NewChange(u.passwordChangeRequiredColumn(), required)
}
func (u userHuman) SetLastSuccessfulPasswordCheck(checkedAt time.Time) database.Change {
if checkedAt.IsZero() {
return database.NewChanges(
database.NewChange(u.lastSuccessfulPasswordCheckColumn(), database.NowInstruction),
u.ResetPasswordFailedAttempts(),
)
}
return database.NewChanges(
database.NewChange(u.lastSuccessfulPasswordCheckColumn(), checkedAt),
u.ResetPasswordFailedAttempts(),
)
}
func (u userHuman) IncrementPasswordFailedAttempts() database.Change {
return database.NewIncrementColumnChange(u.failedPasswordAttemptsColumn(), database.Coalesce(u.failedPasswordAttemptsColumn(), 0))
}
func (u userHuman) ResetPasswordFailedAttempts() database.Change {
return database.NewChange(u.failedPasswordAttemptsColumn(), 0)
}
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
func (u userHuman) passwordHashColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "password_hash")
}
func (u userHuman) passwordChangeRequiredColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "password_change_required")
}
func (u userHuman) passwordVerifiedAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "password_changed_at")
}
func (u userHuman) passwordVerificationIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "password_verification_id")
}
func (u userHuman) lastSuccessfulPasswordCheckColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "password_last_successful_check")
}
func (u userHuman) failedPasswordAttemptsColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "password_failed_attempts")
}
@@ -0,0 +1,148 @@
package repository
import (
"fmt"
"time"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
// SetPhone implements [domain.HumanUserRepository].
func (u userHuman) SetPhone(phone string) database.Change {
return database.NewChange(u.phoneColumn(), phone)
}
// SetUnverifiedPhone implements [domain.HumanUserRepository].
func (u userHuman) SetUnverifiedPhone(phone string) database.Change {
return database.NewChange(u.unverifiedPhoneColumn(), phone)
}
// SetPhoneVerification implements [domain.HumanUserRepository].
func (u userHuman) SetPhoneVerification(verification domain.VerificationType) database.Change {
switch typ := verification.(type) {
case *domain.VerificationTypeInit:
return u.verification.init(typ, existingHumanUser.unqualifiedTableName(), existingHumanUser.phoneVerificationIDColumn())
case *domain.VerificationTypeUpdate:
return u.verification.update(typ, existingHumanUser.unqualifiedTableName(),
existingHumanUser.InstanceIDColumn(), existingHumanUser.phoneVerificationIDColumn(),
)
case *domain.VerificationTypeSucceeded:
return database.NewChanges(
u.verification.verified(typ, existingHumanUser.unqualifiedTableName(), existingHumanUser.InstanceIDColumn(),
existingHumanUser.phoneVerificationIDColumn(), u.phoneVerifiedAtColumn(), u.failedSMSOTPAttemptsColumn(),
),
database.NewChangeToColumn(u.phoneColumn(), u.unverifiedPhoneColumn()),
)
case *domain.VerificationTypeFailed:
return u.verification.failed(existingHumanUser.unqualifiedTableName(), existingHumanUser.InstanceIDColumn(), existingHumanUser.phoneVerificationIDColumn())
case *domain.VerificationTypeSkipped:
return u.verification.skipped(typ, u.phoneVerifiedAtColumn(), u.phoneVerificationIDColumn(), u.failedSMSOTPAttemptsColumn())
}
panic(fmt.Sprintf("type not allowed for phone verification change %T", verification))
}
// RemovePhone implements [domain.HumanUserRepository].
func (u userHuman) RemovePhone() database.Change {
return database.NewChanges(
database.NewChangeToNull(u.phoneColumn()),
database.NewChangeToNull(u.phoneVerifiedAtColumn()),
database.NewChangeToNull(u.phoneVerificationIDColumn()),
database.NewChangeToNull(u.smsOTPEnabledAtColumn()),
database.NewChangeToNull(u.lastSuccessfulSMSOTPCheckColumn()),
database.NewChangeToNull(u.failedSMSOTPAttemptsColumn()),
)
}
// EnableSMSOTPAt implements [domain.HumanUserRepository].
func (u userHuman) EnableSMSOTPAt(enabledAt time.Time) database.Change {
return database.NewChange(u.smsOTPEnabledAtColumn(), enabledAt)
}
// EnableSMSOTP implements [domain.HumanUserRepository].
func (u userHuman) EnableSMSOTP() database.Change {
return database.NewChange(u.smsOTPEnabledAtColumn(), database.NowInstruction)
}
// DisableSMSOTP implements [domain.HumanUserRepository].
func (u userHuman) DisableSMSOTP() database.Change {
return database.NewChangeToNull(u.smsOTPEnabledAtColumn())
}
func (u userHuman) SetLastSuccessfulSMSOTPCheck(checkedAt time.Time) database.Change {
if checkedAt.IsZero() {
return database.NewChanges(
database.NewChange(u.lastSuccessfulSMSOTPCheckColumn(), database.NowInstruction),
u.ResetSMSOTPFailedAttempts(),
)
}
return database.NewChanges(
database.NewChange(u.lastSuccessfulSMSOTPCheckColumn(), checkedAt),
u.ResetSMSOTPFailedAttempts(),
)
}
// IncrementSMSOTPFailedAttempts implements [domain.HumanUserRepository].
func (u userHuman) IncrementSMSOTPFailedAttempts() database.Change {
return database.NewIncrementColumnChange(u.failedSMSOTPAttemptsColumn(), database.Coalesce(u.failedSMSOTPAttemptsColumn(), 0))
}
// ResetSMSOTPFailedAttempts implements [domain.HumanUserRepository].
func (u userHuman) ResetSMSOTPFailedAttempts() database.Change {
return database.NewChange(u.failedSMSOTPAttemptsColumn(), 0)
}
// -------------------------------------------------------------
// conditions
// -------------------------------------------------------------
// PhoneCondition implements [domain.HumanUserRepository].
func (u userHuman) PhoneCondition(op database.TextOperation, phone string) database.Condition {
return database.Or(u.UnverifiedPhoneCondition(op, phone), u.VerifiedPhoneCondition(op, phone))
}
// UnverifiedPhoneCondition implements [domain.HumanUserRepository].
func (u userHuman) UnverifiedPhoneCondition(op database.TextOperation, phone string) database.Condition {
return database.NewTextCondition(u.unverifiedPhoneColumn(), op, phone)
}
// VerifiedPhoneCondition implements [domain.HumanUserRepository].
func (u userHuman) VerifiedPhoneCondition(op database.TextOperation, phone string) database.Condition {
return database.NewTextCondition(u.phoneColumn(), op, phone)
}
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
func (u userHuman) phoneColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "phone")
}
func (u userHuman) unverifiedPhoneColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "unverified_phone")
}
func (u userHuman) phoneVerifiedAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "phone_verified_at")
}
func (u userHuman) phoneVerificationIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "phone_verification_id")
}
func (u userHuman) smsOTPEnabledAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "sms_otp_enabled_at")
}
func (u userHuman) lastSuccessfulSMSOTPCheckColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "sms_otp_last_successful_check")
}
func (u userHuman) failedSMSOTPAttemptsColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "sms_otp_failed_attempts")
}
@@ -0,0 +1,598 @@
package repository_test
import (
"context"
"testing"
"time"
"github.com/brianvoe/gofakeit/v6"
"github.com/stretchr/testify/require"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
"github.com/zitadel/zitadel/backend/v3/storage/database/repository"
"github.com/zitadel/zitadel/internal/crypto"
)
func Test_humanUser_create(t *testing.T) {
tx, rollback := transactionForRollback(t)
t.Cleanup(rollback)
// tx := pool
userRepo := repository.UserRepository()
instanceID := createInstance(t, tx)
orgID := createOrganization(t, tx, instanceID)
createdAt := time.Now().Round(time.Millisecond).UTC()
existingUserID := createMachineUser(t, tx, instanceID, orgID)
password := gofakeit.Password(true, true, true, true, false, 16)
type args struct {
user *domain.User
}
type want struct {
err error
user *domain.User
}
type test struct {
name string
args args
want want
}
tests := []test{
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
firstName := gofakeit.FirstName()
lastName := gofakeit.LastName()
email := gofakeit.Email()
return test{
name: "minimal representation",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Email: domain.HumanEmail{
UnverifiedAddress: email,
},
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Email: domain.HumanEmail{
UnverifiedAddress: email,
},
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
firstName := gofakeit.FirstName()
lastName := gofakeit.LastName()
email := gofakeit.Email()
return test{
name: "including optional profile fields",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Nickname: "Nick",
DisplayName: firstName + " " + lastName,
PreferredLanguage: language.Georgian,
Gender: domain.HumanGenderFemale,
AvatarKey: "http://localhost:8080/my/profile/picture",
MultifactorInitializationSkippedAt: createdAt,
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
},
Email: domain.HumanEmail{
Address: email,
},
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Nickname: "Nick",
DisplayName: firstName + " " + lastName,
PreferredLanguage: language.Georgian,
Gender: domain.HumanGenderFemale,
AvatarKey: "http://localhost:8080/my/profile/picture",
MultifactorInitializationSkippedAt: createdAt,
Email: domain.HumanEmail{
Address: email,
UnverifiedAddress: email,
VerifiedAt: createdAt,
},
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
ChangedAt: createdAt,
},
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
firstName := gofakeit.FirstName()
lastName := gofakeit.LastName()
email := gofakeit.Email()
code := &crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "aes256",
KeyID: "key-id",
Crypted: []byte("crypted"),
}
return test{
name: "with unverified email without expiry",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
},
Email: domain.HumanEmail{
UnverifiedAddress: email,
PendingVerification: &domain.Verification{
ID: "test",
Code: code,
},
},
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Email: domain.HumanEmail{
UnverifiedAddress: email,
PendingVerification: &domain.Verification{
ID: "test",
Code: code,
CreatedAt: createdAt,
UpdatedAt: createdAt,
},
},
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
ChangedAt: createdAt,
},
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
firstName := gofakeit.FirstName()
lastName := gofakeit.LastName()
email := gofakeit.Email()
phone := gofakeit.Phone()
code := &crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "aes256",
KeyID: "key-id",
Crypted: []byte("crypted"),
}
return test{
name: "with unverified phone without expiry",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
},
Email: domain.HumanEmail{
Address: email,
UnverifiedAddress: email,
VerifiedAt: createdAt,
},
Phone: &domain.HumanPhone{
UnverifiedNumber: phone,
PendingVerification: &domain.Verification{
ID: "id",
Code: code,
},
},
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Email: domain.HumanEmail{
Address: email,
UnverifiedAddress: email,
VerifiedAt: createdAt,
},
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
ChangedAt: createdAt,
},
Phone: &domain.HumanPhone{
UnverifiedNumber: phone,
PendingVerification: &domain.Verification{
CreatedAt: createdAt,
UpdatedAt: createdAt,
ID: "id",
Code: code,
},
},
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
firstName := gofakeit.FirstName()
lastName := gofakeit.LastName()
email := gofakeit.Email()
passkeys := []*domain.Passkey{
{
ID: gofakeit.UUID(),
KeyID: []byte(gofakeit.UUID()),
Type: domain.PasskeyTypePasswordless,
Name: "passwordless",
PublicKey: []byte("public key"),
AttestationType: "don't know",
AuthenticatorAttestationGUID: []byte("aaguid"),
CreatedAt: createdAt,
UpdatedAt: createdAt,
Challenge: []byte("challenge"),
VerifiedAt: createdAt,
RelyingPartyID: "rpid",
},
{
ID: gofakeit.UUID(),
KeyID: []byte(gofakeit.UUID()),
Type: domain.PasskeyTypeU2F,
Name: "u2f",
PublicKey: []byte("public key"),
AttestationType: "don't know",
AuthenticatorAttestationGUID: []byte("aaguid"),
CreatedAt: createdAt,
UpdatedAt: createdAt,
Challenge: []byte("challenge"),
VerifiedAt: createdAt,
RelyingPartyID: "rpid",
},
}
return test{
name: "with verified passkeys",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
},
Email: domain.HumanEmail{
Address: email,
},
Passkeys: passkeys,
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Email: domain.HumanEmail{
Address: email,
UnverifiedAddress: email,
VerifiedAt: createdAt,
},
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
ChangedAt: createdAt,
},
Passkeys: passkeys,
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
firstName := gofakeit.FirstName()
lastName := gofakeit.LastName()
email := gofakeit.Email()
code := &crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "aes256",
KeyID: "key-id",
Crypted: []byte("crypted"),
}
verifications := []*domain.Verification{
{
ID: gofakeit.UUID(),
Code: code,
},
{
ID: gofakeit.UUID(),
Code: code,
},
}
return test{
name: "with verifications",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
},
Email: domain.HumanEmail{
Address: email,
},
Verifications: verifications,
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Email: domain.HumanEmail{
Address: email,
UnverifiedAddress: email,
VerifiedAt: createdAt,
},
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
ChangedAt: createdAt,
},
Verifications: verifications,
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
firstName := gofakeit.FirstName()
lastName := gofakeit.LastName()
email := gofakeit.Email()
return test{
name: "with totp",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
},
Email: domain.HumanEmail{
Address: email,
},
TOTP: &domain.HumanTOTP{
VerifiedAt: createdAt,
Secret: &crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "aes-256",
KeyID: "id",
Crypted: []byte("secret"),
},
},
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Human: &domain.HumanUser{
FirstName: firstName,
LastName: lastName,
Email: domain.HumanEmail{
Address: email,
UnverifiedAddress: email,
VerifiedAt: createdAt,
},
Password: domain.HumanPassword{
Hash: password,
IsChangeRequired: true,
ChangedAt: createdAt,
},
TOTP: &domain.HumanTOTP{
VerifiedAt: createdAt,
Secret: &crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "aes-256",
KeyID: "id",
Crypted: []byte("secret"),
},
},
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
return test{
name: "already exists",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: existingUserID,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
},
},
},
want: want{
err: new(database.UniqueError),
},
}
}(),
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
savepoint, err := tx.Begin(t.Context())
require.NoError(t, err)
t.Cleanup(func() {
err := savepoint.Rollback(context.Background())
if err != nil {
t.Log("rollback savepoint failed", err)
}
})
err = userRepo.Create(t.Context(), savepoint, tt.args.user)
require.ErrorIs(t, err, tt.want.err)
if tt.want.err != nil {
return
}
got, err := userRepo.Get(t.Context(), savepoint, database.WithCondition(
userRepo.PrimaryKeyCondition(tt.want.user.InstanceID, tt.want.user.ID),
))
require.NoError(t, err)
assertUser(t, tt.want.user, got)
})
}
}
@@ -0,0 +1,82 @@
package repository
import (
"time"
"github.com/zitadel/zitadel/backend/v3/storage/database"
"github.com/zitadel/zitadel/internal/crypto"
)
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
// SetTOTPSecret implements [domain.HumanUserRepository].
func (u userHuman) SetTOTPSecret(secret *crypto.CryptoValue) database.Change {
return database.NewChange(u.totpSecretColumn(), secret)
}
// SetTOTPVerifiedAt implements [domain.HumanUserRepository].
func (u userHuman) SetTOTPVerifiedAt(verifiedAt time.Time) database.Change {
if verifiedAt.IsZero() {
return database.NewChange(u.totpVerifiedAtColumn(), database.NowInstruction)
}
return database.NewChange(u.totpVerifiedAtColumn(), verifiedAt)
}
// RemoveTOTP implements [domain.HumanUserRepository].
func (u userHuman) RemoveTOTP() database.Change {
return database.NewChanges(
database.NewChangeToNull(u.totpSecretColumn()),
database.NewChangeToNull(u.totpVerifiedAtColumn()),
database.NewChangeToNull(u.lastSuccessfulTOTPCheckColumn()),
)
}
// SetLastSuccessfulTOTPCheck implements [domain.HumanUserRepository].
func (u userHuman) SetLastSuccessfulTOTPCheck(checkedAt time.Time) database.Change {
if checkedAt.IsZero() {
return database.NewChanges(
database.NewChange(u.lastSuccessfulTOTPCheckColumn(), database.NowInstruction),
u.ResetTOTPFailedAttempts(),
)
}
return database.NewChanges(
database.NewChange(u.lastSuccessfulTOTPCheckColumn(), checkedAt),
u.ResetTOTPFailedAttempts(),
)
}
// IncrementTOTPFailedAttempts implements [domain.HumanUserRepository].
func (u userHuman) IncrementTOTPFailedAttempts() database.Change {
return database.NewIncrementColumnChange(u.totpFailedAttemptsColumn(), database.Coalesce(u.totpFailedAttemptsColumn(), 0))
}
// ResetTOTPFailedAttempts implements [domain.HumanUserRepository].
func (u userHuman) ResetTOTPFailedAttempts() database.Change {
return database.NewChange(u.totpFailedAttemptsColumn(), 0)
}
// -------------------------------------------------------------
// conditions
// -------------------------------------------------------------
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
func (u userHuman) totpSecretColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "totp_secret")
}
func (u userHuman) totpVerifiedAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "totp_verified_at")
}
func (u userHuman) lastSuccessfulTOTPCheckColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "totp_last_successful_check")
}
func (u userHuman) totpFailedAttemptsColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "totp_failed_attempts")
}
@@ -0,0 +1,161 @@
package repository
import (
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/instrumentation/logging"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
type userIdentityProviderLink struct{}
func (u userIdentityProviderLink) unqualifiedTableName() string {
return "user_identity_provider_links"
}
func (u userIdentityProviderLink) qualifiedTableName() string {
return "zitadel.user_identity_provider_links"
}
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
// AddIdentityProviderLink implements [domain.HumanUserRepository].
func (u userIdentityProviderLink) AddIdentityProviderLink(link *domain.IdentityProviderLink) database.Change {
var createdAt, updatedAt any = database.NowInstruction, database.NowInstruction
if !link.CreatedAt.IsZero() {
createdAt = link.CreatedAt
}
if !link.UpdatedAt.IsZero() {
updatedAt = link.UpdatedAt
}
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("INSERT INTO ")
builder.WriteString(u.qualifiedTableName())
builder.WriteString("(instance_id, user_id, provided_user_id, provided_username, identity_provider_id, created_at, updated_at) SELECT ")
database.Columns{
existingHumanUser.InstanceIDColumn(),
existingHumanUser.IDColumn(),
}.WriteQualified(builder)
builder.WriteString(", ")
builder.WriteArgs(
link.ProvidedUserID,
link.ProvidedUsername,
link.ProviderID,
createdAt,
updatedAt,
)
builder.WriteString(" FROM ")
builder.WriteString(existingHumanUser.unqualifiedTableName())
builder.WriteString(" RETURNING *")
}, nil,
)
}
// UpdateIdentityProviderLink implements [domain.HumanUserRepository].
func (u userIdentityProviderLink) UpdateIdentityProviderLink(condition database.Condition, changes ...database.Change) database.Change {
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("UPDATE zitadel.user_identity_provider_links SET ")
err := database.Changes(changes).Write(builder)
logging.New(logging.StreamRuntime).Debug("write changes in cte failed", "error", err)
builder.WriteString(" FROM ")
builder.WriteString(existingHumanUser.unqualifiedTableName())
writeCondition(builder, database.And(
database.NewColumnCondition(existingHumanUser.InstanceIDColumn(), u.instanceIDColumn()),
database.NewColumnCondition(existingHumanUser.IDColumn(), u.userIDColumn()),
condition,
))
}, nil,
)
}
// RemoveIdentityProviderLink implements [domain.HumanUserRepository].
func (u userIdentityProviderLink) RemoveIdentityProviderLink(providerID string, providedUserID string) database.Change {
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("DELETE FROM ")
builder.WriteString(u.qualifiedTableName())
builder.WriteString(" USING ")
builder.WriteString(existingHumanUser.unqualifiedTableName())
writeCondition(builder, database.And(
database.NewColumnCondition(
existingHumanUser.InstanceIDColumn(),
u.instanceIDColumn(),
),
database.NewColumnCondition(
existingHumanUser.IDColumn(),
u.userIDColumn(),
),
database.NewTextCondition(
u.providerIDColumn(),
database.TextOperationEqual,
providerID,
),
database.NewTextCondition(
u.providedUserIDColumn(),
database.TextOperationEqual,
providedUserID,
),
))
}, nil,
)
}
// SetIdentityProviderLinkUsername implements [domain.HumanUserRepository].
func (u userIdentityProviderLink) SetIdentityProviderLinkUsername(username string) database.Change {
return database.NewChange(u.providedUsernameColumn(), username)
}
// SetIdentityProviderLinkProvidedID implements [domain.HumanUserRepository].
func (u userIdentityProviderLink) SetIdentityProviderLinkProvidedID(providedUserID string) database.Change {
return database.NewChange(u.providedUserIDColumn(), providedUserID)
}
// -------------------------------------------------------------
// conditions
// -------------------------------------------------------------
// IdentityProviderLinkConditions implements [domain.HumanUserRepository].
func (u userIdentityProviderLink) IdentityProviderLinkConditions() domain.HumanIdentityProviderLinkConditions {
return u
}
// ProviderIDCondition implements [domain.HumanUserRepository].
func (u userIdentityProviderLink) ProviderIDCondition(idpID string) database.Condition {
return database.NewTextCondition(u.providerIDColumn(), database.TextOperationEqual, idpID)
}
// ProvidedUserIDCondition implements [domain.HumanUserRepository].
func (u userIdentityProviderLink) ProvidedUserIDCondition(providedUserID string) database.Condition {
return database.NewTextCondition(u.providedUserIDColumn(), database.TextOperationEqual, providedUserID)
}
// ProvidedUsernameCondition implements [domain.HumanUserRepository].
func (u userIdentityProviderLink) ProvidedUsernameCondition(op database.TextOperation, username string) database.Condition {
return database.NewTextCondition(u.providedUsernameColumn(), op, username)
}
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
func (u userIdentityProviderLink) instanceIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "instance_id")
}
func (u userIdentityProviderLink) userIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "user_id")
}
func (u userIdentityProviderLink) providerIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "identity_provider_id")
}
func (u userIdentityProviderLink) providedUserIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "provided_user_id")
}
func (u userIdentityProviderLink) providedUsernameColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "provided_username")
}
@@ -0,0 +1,49 @@
package repository
import (
"fmt"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
// SetInviteVerification implements [domain.HumanUserRepository].
func (u userHuman) SetInviteVerification(verification domain.VerificationType) database.Change {
switch typ := verification.(type) {
case *domain.VerificationTypeInit:
return u.verification.init(typ, existingUser.unqualifiedTableName(), existingHumanUser.inviteVerificationIDColumn())
case *domain.VerificationTypeUpdate:
return u.verification.update(typ, existingHumanUser.unqualifiedTableName(),
existingHumanUser.InstanceIDColumn(), existingHumanUser.inviteVerificationIDColumn(),
)
case *domain.VerificationTypeSucceeded:
return u.verification.verified(typ, existingHumanUser.unqualifiedTableName(), existingHumanUser.InstanceIDColumn(),
existingHumanUser.inviteVerificationIDColumn(), u.inviteAcceptedAtColumn(), u.failedInviteAttemptsColumn(),
)
case *domain.VerificationTypeSkipped:
return u.verification.skipped(typ, u.inviteAcceptedAtColumn(), u.inviteVerificationIDColumn(), u.failedInviteAttemptsColumn())
case *domain.VerificationTypeFailed:
return u.verification.failed(existingHumanUser.unqualifiedTableName(), existingHumanUser.InstanceIDColumn(), existingHumanUser.inviteVerificationIDColumn())
}
panic(fmt.Sprintf("undefined verification type %T", verification))
}
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
func (u userHuman) inviteVerificationIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "invite_verification_id")
}
func (u userHuman) inviteAcceptedAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "invite_accepted_at")
}
func (u userHuman) failedInviteAttemptsColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "invite_failed_attempts")
}
@@ -0,0 +1,103 @@
package repository
import (
"context"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
type userMachine struct {
user
machineKey
userPersonalAccessToken
}
func (u userMachine) create(ctx context.Context, builder *database.StatementBuilder, client database.QueryExecutor, user *domain.User) error {
changes := make(database.Changes, 0, len(user.Machine.Keys)+len(user.Machine.PATs))
for _, key := range user.Machine.Keys {
changes = append(changes, u.AddKey(key))
}
for _, pat := range user.Machine.PATs {
changes = append(changes, u.AddPersonalAccessToken(pat))
}
for _, metadata := range user.Metadata {
changes = append(changes, u.SetMetadata(metadata))
}
for i, change := range changes {
sessionCTE(change, i, 0, builder)
}
builder.WriteString("INSERT INTO zitadel.users (" +
"instance_id, organization_id, id, username, state, type" +
", name, description, secret, access_token_type, created_at, updated_at) VALUES (",
)
var createdAt any = database.NowInstruction
if !user.CreatedAt.IsZero() {
createdAt = user.CreatedAt
}
builder.WriteArgs(
user.InstanceID, user.OrganizationID, user.ID, user.Username, user.State, "machine",
user.Machine.Name, user.Machine.Description, user.Machine.Secret, uint8(user.Machine.AccessTokenType),
createdAt, createdAt,
)
builder.WriteString(") RETURNING created_at, updated_at")
return client.QueryRow(ctx, builder.String(), builder.Args()...).Scan(&user.CreatedAt, &user.UpdatedAt)
}
// Update implements [domain.MachineUserRepository].
func (u userMachine) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) {
if !condition.IsRestrictingColumn(u.TypeColumn()) {
condition = database.And(condition, u.TypeCondition(domain.UserTypeMachine))
}
return u.user.Update(ctx, client, condition, changes...)
}
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
// SetAccessTokenType implements [domain.MachineUserRepository].
func (u userMachine) SetAccessTokenType(tokenType domain.AccessTokenType) database.Change {
return database.NewChange(u.accessTokenTypeColumn(), tokenType)
}
// SetDescription implements [domain.MachineUserRepository].
func (u userMachine) SetDescription(description string) database.Change {
return database.NewChange(u.descriptionColumn(), description)
}
// SetName implements [domain.MachineUserRepository].
func (u userMachine) SetName(name string) database.Change {
return database.NewChange(u.nameColumn(), name)
}
// SetSecret implements [domain.MachineUserRepository].
func (u userMachine) SetSecret(secret *string) database.Change {
return database.NewChangePtr(u.secretColumn(), secret)
}
var _ domain.MachineUserRepository = (*userMachine)(nil)
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
func (u userMachine) nameColumn() database.Column {
return database.NewColumn(u.user.unqualifiedTableName(), "name")
}
func (u userMachine) descriptionColumn() database.Column {
return database.NewColumn(u.user.unqualifiedTableName(), "description")
}
func (u userMachine) accessTokenTypeColumn() database.Column {
return database.NewColumn(u.user.unqualifiedTableName(), "access_token_type")
}
func (u userMachine) secretColumn() database.Column {
return database.NewColumn(u.user.unqualifiedTableName(), "secret")
}
@@ -0,0 +1,64 @@
package repository
import (
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
type machineKey struct{}
// AddKey implements [domain.MachineUserRepository].
func (u machineKey) AddKey(key *domain.MachineKey) database.Change {
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("INSERT INTO zitadel.machine_keys (" +
"instance_id, user_id, id, created_at, expires_at, type, public_key" +
") SELECT instance_id, id, ",
)
var createdAt any = database.NowInstruction
if !key.CreatedAt.IsZero() {
createdAt = key.CreatedAt
}
var expiresAt any = database.NullInstruction
if !key.ExpiresAt.IsZero() {
expiresAt = key.ExpiresAt
}
builder.WriteArgs(key.ID, createdAt, expiresAt, key.Type, key.PublicKey)
builder.WriteString(" FROM existing_user")
},
nil,
)
}
// RemoveKey implements [domain.MachineUserRepository].
func (u machineKey) RemoveKey(id string) database.Change {
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("DELETE FROM zitadel.machine_keys WHERE " +
"(instance_id, user_id, id) = (SELECT instance_id, id, ")
builder.WriteArg(id)
builder.WriteString(" FROM existing_user)")
},
nil,
)
}
func (u machineKey) qualifiedTableName() string {
return "zitadel.machine_keys"
}
func (u machineKey) unqualifiedTableName() string {
return "machine_keys"
}
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
func (u machineKey) instanceIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "instance_id")
}
func (u machineKey) userIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "user_id")
}
@@ -0,0 +1,394 @@
package repository_test
import (
"context"
"testing"
"time"
"github.com/brianvoe/gofakeit/v6"
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
"github.com/zitadel/zitadel/backend/v3/storage/database/repository"
)
func Test_machineUser_create(t *testing.T) {
tx, rollback := transactionForRollback(t)
t.Cleanup(rollback)
userRepo := repository.UserRepository()
instanceID := createInstance(t, tx)
orgID := createOrganization(t, tx, instanceID)
createdAt := time.Now().Round(time.Second)
existingUserID := createMachineUser(t, tx, instanceID, orgID)
type args struct {
user *domain.User
}
type want struct {
err error
user *domain.User
}
type test struct {
name string
args args
want want
}
tests := []test{
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
return test{
name: "minimal representation",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
return test{
name: "with secret",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
Secret: "secret",
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
Secret: "secret",
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
return test{
name: "with access token type",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
AccessTokenType: domain.AccessTokenTypeBearer,
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
AccessTokenType: domain.AccessTokenTypeBearer,
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
keys := []*domain.MachineKey{
{
ID: gofakeit.UUID(),
PublicKey: []byte("public key"),
CreatedAt: createdAt,
ExpiresAt: createdAt.Add(24 * time.Hour),
Type: domain.MachineKeyTypeJSON,
},
{
ID: gofakeit.UUID(),
PublicKey: []byte("public key"),
CreatedAt: createdAt,
ExpiresAt: createdAt.Add(24 * time.Hour),
Type: domain.MachineKeyTypeJSON,
},
}
return test{
name: "with keys",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
Keys: keys,
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
Keys: keys,
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
pats := []*domain.PersonalAccessToken{
{
ID: gofakeit.UUID(),
CreatedAt: createdAt,
ExpiresAt: createdAt.Add(24 * time.Hour),
},
{
ID: gofakeit.UUID(),
CreatedAt: createdAt,
ExpiresAt: createdAt.Add(24 * time.Hour),
Scopes: []string{"some", "scopes"},
},
}
return test{
name: "with keys",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
PATs: pats,
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
PATs: pats,
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
id := gofakeit.UUID()
pats := []*domain.PersonalAccessToken{
{
ID: gofakeit.UUID(),
CreatedAt: createdAt,
ExpiresAt: createdAt.Add(24 * time.Hour),
},
}
keys := []*domain.MachineKey{
{
ID: gofakeit.UUID(),
PublicKey: []byte("public key"),
CreatedAt: createdAt,
ExpiresAt: createdAt.Add(24 * time.Hour),
Type: domain.MachineKeyTypeJSON,
},
}
return test{
name: "all fields set",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Metadata: []*domain.Metadata{
{
Key: "meta1",
Value: []byte("value1"),
CreatedAt: createdAt,
UpdatedAt: createdAt,
},
{
Key: "meta2",
Value: []byte("123"),
CreatedAt: createdAt,
UpdatedAt: createdAt,
},
},
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
PATs: pats,
Keys: keys,
Secret: "secret",
AccessTokenType: domain.AccessTokenTypeJWT,
},
},
},
want: want{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: id,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
UpdatedAt: createdAt,
Metadata: []*domain.Metadata{
{
InstanceID: instanceID,
Key: "meta1",
Value: []byte("value1"),
CreatedAt: createdAt,
UpdatedAt: createdAt,
},
{
InstanceID: instanceID,
Key: "meta2",
Value: []byte("123"),
CreatedAt: createdAt,
UpdatedAt: createdAt,
},
},
Machine: &domain.MachineUser{
Name: "machine",
Description: "description",
PATs: pats,
Keys: keys,
Secret: "secret",
AccessTokenType: domain.AccessTokenTypeJWT,
},
},
},
}
}(),
func() test {
username := gofakeit.Username()
return test{
name: "already exists",
args: args{
user: &domain.User{
InstanceID: instanceID,
OrganizationID: orgID,
ID: existingUserID,
Username: username,
State: domain.UserStateActive,
CreatedAt: createdAt,
Machine: &domain.MachineUser{
Name: "machine",
},
},
},
want: want{
err: new(database.UniqueError),
},
}
}(),
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
savepoint, err := tx.Begin(t.Context())
require.NoError(t, err)
t.Cleanup(func() {
err := savepoint.Rollback(context.Background())
if err != nil {
t.Log("rollback savepoint failed", err)
}
})
err = userRepo.Create(t.Context(), savepoint, tt.args.user)
require.ErrorIs(t, err, tt.want.err)
if tt.want.err != nil {
return
}
got, err := userRepo.Get(t.Context(), savepoint, database.WithCondition(
userRepo.PrimaryKeyCondition(tt.want.user.InstanceID, tt.want.user.ID),
))
require.NoError(t, err)
assertUser(t, tt.want.user, got)
})
}
}
@@ -0,0 +1,121 @@
package repository
import (
"strings"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
type userMetadata struct{}
func (userMetadata) qualifiedTableName() string {
return "zitadel.user_metadata"
}
func (userMetadata) unqualifiedTableName() string {
return "user_metadata"
}
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
// SetMetadata implements [domain.UserRepository].
func (u userMetadata) SetMetadata(metadata ...*domain.Metadata) database.Change {
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("INSERT INTO zitadel.user_metadata(instance_id, user_id, key, value, created_at, updated_at)")
builder.WriteString(" SELECT existing_user.instance_id, existing_user.id, md.key::TEXT, md.value::BYTEA, md.created_at::TIMESTAMPTZ, md.updated_at::TIMESTAMPTZ")
builder.WriteString(" FROM existing_user CROSS JOIN (VALUES ")
for i, md := range metadata {
if i > 0 {
builder.WriteString(", ")
}
builder.WriteRune('(')
// The complex placeholder handling is needed to append the type casts
// if we use WriteArgs directly, pgx resolves all args as TEXT instead of the correct type
placeholders := make([]string, 4)
placeholders[0] = builder.AppendArg(md.Key)
placeholders[1] = builder.AppendArg(md.Value) + "::BYTEA"
var createdAt, updatedAt any = database.NowInstruction, database.NullInstruction
if !md.CreatedAt.IsZero() {
createdAt = md.CreatedAt
}
if !md.UpdatedAt.IsZero() {
updatedAt = md.UpdatedAt
}
placeholders[2] = builder.AppendArg(createdAt) + "::TIMESTAMPTZ"
placeholders[3] = builder.AppendArg(updatedAt) + "::TIMESTAMPTZ"
builder.WriteString(strings.Join(placeholders, ", "))
builder.WriteRune(')')
}
builder.WriteString(") AS md(key, value, created_at, updated_at) ON CONFLICT (")
database.Columns{
u.instanceIDColumn(),
u.userIDColumn(),
u.keyColumn(),
}.WriteUnqualified(builder)
builder.WriteString(") DO UPDATE SET value = EXCLUDED.value, updated_at = EXCLUDED.updated_at WHERE ")
u.valueColumn().WriteQualified(builder)
builder.WriteString(" IS DISTINCT FROM EXCLUDED.value")
},
nil,
)
}
// RemoveMetadata implements [domain.UserRepository].
func (u userMetadata) RemoveMetadata(condition database.Condition) database.Change {
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("DELETE FROM zitadel.user_metadata USING ")
builder.WriteString(existingUser.unqualifiedTableName())
writeCondition(builder, database.And(
database.NewColumnCondition(existingUser.InstanceIDColumn(), u.instanceIDColumn()),
database.NewColumnCondition(existingUser.IDColumn(), u.userIDColumn()),
condition,
))
},
nil,
)
}
// -------------------------------------------------------------
// conditions
// -------------------------------------------------------------
func (u userMetadata) MetadataConditions() domain.UserMetadataConditions {
return u
}
// MetadataKeyCondition implements [domain.UserMetadataConditions].
func (u userMetadata) MetadataKeyCondition(op database.TextOperation, key string) database.Condition {
return database.NewTextCondition(u.keyColumn(), op, key)
}
// MetadataValueCondition implements [domain.UserMetadataConditions].
func (u userMetadata) MetadataValueCondition(op database.BytesOperation, value []byte) database.Condition {
return database.NewBytesCondition[[]byte](database.SHA256Column(u.valueColumn()), op, database.SHA256Value(value))
}
var _ domain.UserMetadataConditions = (*userMetadata)(nil)
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
func (u userMetadata) instanceIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "instance_id")
}
func (u userMetadata) userIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "user_id")
}
func (u userMetadata) keyColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "key")
}
func (u userMetadata) valueColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "value")
}
@@ -0,0 +1,264 @@
package repository
import (
"time"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/instrumentation/logging"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
type userPasskey struct{}
func (u userPasskey) unqualifiedTableName() string {
return "user_passkeys"
}
func (u userPasskey) qualifiedTableName() string {
return "zitadel.user_passkeys"
}
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
// AddPasskey implements [domain.HumanUserRepository].
func (u userPasskey) AddPasskey(passkey *domain.Passkey) database.Change {
var (
createdAt any = database.NowInstruction
updatedAt any = database.NowInstruction
verifiedAt any = database.NowInstruction
)
if !passkey.CreatedAt.IsZero() {
createdAt = passkey.CreatedAt
}
if !passkey.UpdatedAt.IsZero() {
updatedAt = passkey.UpdatedAt
}
if !passkey.VerifiedAt.IsZero() {
verifiedAt = passkey.VerifiedAt
}
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("INSERT INTO ")
builder.WriteString(u.qualifiedTableName())
builder.WriteString(" (")
database.Columns{
u.instanceIDColumn(),
u.userIDColumn(),
u.tokenIDColumn(),
u.keyIDColumn(),
u.createdAtColumn(),
u.updatedAtColumn(),
u.verifiedAtColumn(),
u.typeColumn(),
u.nameColumn(),
u.signCountColumn(),
u.challengeColumn(),
u.publicKeyColumn(),
u.attestationTypeColumn(),
u.authenticatorAttestationGUIDColumn(),
u.relyingPartyIDColumn(),
}.WriteUnqualified(builder)
builder.WriteString(") SELECT ")
database.Columns{
existingHumanUser.InstanceIDColumn(),
existingHumanUser.IDColumn(),
}.WriteQualified(builder)
builder.WriteString(", ")
builder.WriteArgs(
passkey.ID,
passkey.KeyID,
createdAt,
updatedAt,
verifiedAt,
passkey.Type,
passkey.Name,
passkey.SignCount,
passkey.Challenge,
passkey.PublicKey,
passkey.AttestationType,
passkey.AuthenticatorAttestationGUID,
passkey.RelyingPartyID,
)
builder.WriteString(" FROM ")
builder.WriteString(existingHumanUser.unqualifiedTableName())
}, nil,
)
}
// RemovePasskey implements [domain.HumanUserRepository].
func (u userPasskey) RemovePasskey(condition database.Condition) database.Change {
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("DELETE FROM ")
builder.WriteString(u.qualifiedTableName())
builder.WriteString(" USING ")
builder.WriteString(existingHumanUser.unqualifiedTableName())
writeCondition(builder, database.And(
database.NewColumnCondition(existingHumanUser.InstanceIDColumn(), u.instanceIDColumn()),
database.NewColumnCondition(existingHumanUser.IDColumn(), u.userIDColumn()),
condition,
))
},
nil,
)
}
// UpdatePasskey implements [domain.HumanUserRepository].
func (u userPasskey) UpdatePasskey(condition database.Condition, changes ...database.Change) database.Change {
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("UPDATE ")
builder.WriteString(u.qualifiedTableName())
builder.WriteString(" SET ")
err := database.Changes(changes).Write(builder)
logging.New(logging.StreamRuntime).Debug("write changes in cte failed", "error", err)
builder.WriteString(" FROM ")
builder.WriteString(existingHumanUser.unqualifiedTableName())
writeCondition(builder, database.And(
database.NewColumnCondition(existingHumanUser.InstanceIDColumn(), u.instanceIDColumn()),
database.NewColumnCondition(existingHumanUser.IDColumn(), u.userIDColumn()),
condition,
))
},
nil,
)
}
// SetPasskeyAttestationType implements [domain.HumanUserRepository].
func (u userPasskey) SetPasskeyAttestationType(attestationType string) database.Change {
return database.NewChange(u.attestationTypeColumn(), attestationType)
}
// SetPasskeyAuthenticatorAttestationGUID implements [domain.HumanUserRepository].
func (u userPasskey) SetPasskeyAuthenticatorAttestationGUID(aaguid []byte) database.Change {
return database.NewChange(u.authenticatorAttestationGUIDColumn(), aaguid)
}
// SetPasskeyKeyID implements [domain.HumanUserRepository].
func (u userPasskey) SetPasskeyKeyID(keyID []byte) database.Change {
return database.NewChange(u.keyIDColumn(), keyID)
}
// SetPasskeyName implements [domain.HumanUserRepository].
func (u userPasskey) SetPasskeyName(name string) database.Change {
return database.NewChange(u.nameColumn(), name)
}
// SetPasskeyPublicKey implements [domain.HumanUserRepository].
func (u userPasskey) SetPasskeyPublicKey(publicKey []byte) database.Change {
return database.NewChange(u.publicKeyColumn(), publicKey)
}
// SetPasskeySignCount implements [domain.HumanUserRepository].
func (u userPasskey) SetPasskeySignCount(signCount uint32) database.Change {
return database.NewChange(u.signCountColumn(), signCount)
}
// SetPasskeyUpdatedAt implements [domain.HumanUserRepository].
func (u userPasskey) SetPasskeyUpdatedAt(updatedAt time.Time) database.Change {
return database.NewChange(u.updatedAtColumn(), updatedAt)
}
// SetPasskeyVerifiedAt implements [domain.HumanUserRepository].
func (u userPasskey) SetPasskeyVerifiedAt(verifiedAt time.Time) database.Change {
verifiedAtChange := database.NewChange(u.verifiedAtColumn(), database.NowInstruction)
if !verifiedAt.IsZero() {
verifiedAtChange = database.NewChange(u.verifiedAtColumn(), verifiedAt)
}
return verifiedAtChange
}
// -------------------------------------------------------------
// conditions
// -------------------------------------------------------------
// PasskeyConditions implements [domain.HumanUserRepository].
func (u userPasskey) PasskeyConditions() domain.HumanPasskeyConditions {
return u
}
// ChallengeCondition implements [domain.HumanPasskeyConditions].
func (u userPasskey) ChallengeCondition(challenge []byte) database.Condition {
return database.NewBytesCondition[[]byte](database.SHA256Column(u.challengeColumn()), database.BytesOperationEqual, database.SHA256Value(challenge))
}
// IDCondition implements [domain.HumanPasskeyConditions].
func (u userPasskey) IDCondition(passkeyID string) database.Condition {
return database.NewTextCondition(u.tokenIDColumn(), database.TextOperationEqual, passkeyID)
}
// KeyIDCondition implements [domain.HumanPasskeyConditions].
func (u userPasskey) KeyIDCondition(keyID string) database.Condition {
return database.NewTextCondition(u.keyIDColumn(), database.TextOperationEqual, keyID)
}
// TypeCondition implements [domain.HumanPasskeyConditions].
func (u userPasskey) TypeCondition(passkeyType domain.PasskeyType) database.Condition {
return database.NewTextCondition(u.typeColumn(), database.TextOperationEqual, passkeyType.String())
}
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
func (u userPasskey) tokenIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "token_id")
}
func (u userPasskey) keyIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "key_id")
}
func (u userPasskey) instanceIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "instance_id")
}
func (u userPasskey) userIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "user_id")
}
func (u userPasskey) relyingPartyIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "relying_party_id")
}
func (u userPasskey) authenticatorAttestationGUIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "authenticator_attestation_guid")
}
func (u userPasskey) attestationTypeColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "attestation_type")
}
func (u userPasskey) publicKeyColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "public_key")
}
func (u userPasskey) challengeColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "challenge")
}
func (u userPasskey) signCountColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "sign_count")
}
func (u userPasskey) nameColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "name")
}
func (u userPasskey) typeColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "type")
}
func (u userPasskey) verifiedAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "verified_at")
}
func (u userPasskey) updatedAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "updated_at")
}
func (u userPasskey) createdAtColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "created_at")
}
@@ -0,0 +1,60 @@
package repository
import (
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
type userPersonalAccessToken struct{}
// AddPersonalAccessToken implements [domain.MachineUserRepository].
func (userPersonalAccessToken) AddPersonalAccessToken(pat *domain.PersonalAccessToken) database.Change {
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("INSERT INTO zitadel.user_personal_access_tokens (" +
"instance_id, user_id, id, created_at, expires_at, scopes" +
") SELECT instance_id, id, ",
)
var createdAt any = database.NowInstruction
if !pat.CreatedAt.IsZero() {
createdAt = pat.CreatedAt
}
var expiresAt any = database.NullInstruction
if !pat.ExpiresAt.IsZero() {
expiresAt = pat.ExpiresAt
}
builder.WriteArgs(pat.ID, createdAt, expiresAt, pat.Scopes)
builder.WriteString(" FROM existing_user")
},
nil,
)
}
// RemovePersonalAccessToken implements [domain.MachineUserRepository].
func (userPersonalAccessToken) RemovePersonalAccessToken(id string) database.Change {
return database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("DELETE FROM zitadel.user_personal_access_tokens WHERE " +
"(instance_id, user_id, id) = (SELECT instance_id, id, ")
builder.WriteArg(id)
builder.WriteString(" FROM existing_user)")
},
nil,
)
}
func (userPersonalAccessToken) qualifiedTableName() string {
return "zitadel.user_personal_access_tokens"
}
func (userPersonalAccessToken) unqualifiedTableName() string {
return "user_personal_access_tokens"
}
func (u userPersonalAccessToken) instanceIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "instance_id")
}
func (u userPersonalAccessToken) userIDColumn() database.Column {
return database.NewColumn(u.unqualifiedTableName(), "user_id")
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,171 @@
package repository
import (
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/instrumentation/logging"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
type verification struct{}
func (v verification) unqualifiedTableName() string {
return "verifications"
}
func (v verification) qualifiedTableName() string {
return "zitadel." + v.unqualifiedTableName()
}
// init creates a new verification
func (v verification) init(init *domain.VerificationTypeInit, existingTableName string, verificationID database.Column) database.CTEChange {
return database.NewCTEChange(func(builder *database.StatementBuilder) {
var (
createdAt any = database.NowInstruction
expiry any = database.NullInstruction
id any = database.GenRandomUUIDInstruction
)
if !init.CreatedAt.IsZero() {
createdAt = init.CreatedAt
}
if init.Expiry != nil {
expiry = *init.Expiry
}
if init.ID != nil {
id = *init.ID
}
builder.WriteString("INSERT INTO zitadel.verifications(instance_id, user_id, id, code, created_at, updated_at, expiry) SELECT instance_id, id, ")
builder.WriteArgs(id, init.Code, createdAt, createdAt, expiry)
builder.WriteString(" FROM ")
builder.WriteString(existingTableName)
builder.WriteString(" RETURNING id")
}, func(name string) database.Change {
return database.NewChangeToStatement(verificationID, func(builder *database.StatementBuilder) {
builder.WriteString("SELECT id FROM ")
builder.WriteString(name)
})
})
}
// updates the given fields of the verification with the given ID. Only non-nil fields get updated.
func (v verification) update(update *domain.VerificationTypeUpdate, existingTableName string, instanceID, verificationID database.Column) database.CTEChange {
changes := make(database.Changes, 0, 3)
if update.Code != nil {
changes = append(changes, database.NewChange(v.codeColumn(), update.Code))
}
if update.Expiry != nil {
changes = append(changes, database.NewChange(v.expiryColumn(), *update.Expiry))
}
if update.UpdatedAt.IsZero() {
changes = append(changes, database.NewChange(v.updatedAtColumn(), database.NowInstruction))
} else {
changes = append(changes, database.NewChange(v.updatedAtColumn(), update.UpdatedAt))
}
return database.NewCTEChange(func(builder *database.StatementBuilder) {
builder.WriteString("UPDATE ")
builder.WriteString(v.qualifiedTableName())
builder.WriteString(" SET ")
err := changes.Write(builder)
logging.New(logging.StreamRuntime).Debug("write changes in cte failed", "error", err)
builder.WriteString(" FROM ")
builder.WriteString(existingTableName)
writeCondition(builder, database.And(
database.NewColumnCondition(v.instanceIDColumn(), instanceID),
database.NewColumnCondition(v.idColumn(), verificationID),
))
}, nil)
}
// verified constructs the following changes:
// - sets the verifiedAt column to the current time or the provided time
// - clears the pending verification ID
// - deletes the verification
// - resets the failed attempts counter
func (v verification) verified(verified *domain.VerificationTypeSucceeded, existingTableName string, instanceID, pendingVerificationID, verifiedAt, failedAttempts database.Column) database.Changes {
verifiedAtChange := database.NewChange(verifiedAt, database.NowInstruction)
if !verified.VerifiedAt.IsZero() {
verifiedAtChange = database.NewChange(verifiedAt, verified.VerifiedAt)
}
return database.NewChanges(
verifiedAtChange,
database.NewChangeToNull(pendingVerificationID),
database.NewChange(failedAttempts, 0),
database.NewCTEChange(
func(builder *database.StatementBuilder) {
builder.WriteString("DELETE FROM ")
builder.WriteString(v.qualifiedTableName())
builder.WriteString(" USING ")
builder.WriteString(existingTableName)
writeCondition(builder, database.And(
database.NewColumnCondition(v.instanceIDColumn(), instanceID),
database.NewColumnCondition(v.idColumn(), pendingVerificationID),
))
}, nil,
),
)
}
// skipped constructs the following changes:
// - sets the verifiedAt column to the current time or the provided time
// - clears the pending verification ID
// - resets the failed attempts counter
func (v verification) skipped(skipped *domain.VerificationTypeSkipped, verifiedAt, pendingVerificationID, failedAttempts database.Column) database.Changes {
verifiedAtChange := database.NewChange(verifiedAt, database.NowInstruction)
if !skipped.SkippedAt.IsZero() {
verifiedAtChange = database.NewChange(verifiedAt, skipped.SkippedAt)
}
return database.NewChanges(
verifiedAtChange,
database.NewChange(failedAttempts, 0),
database.NewChangeToNull(pendingVerificationID),
)
}
// failed increments the failed attempts counter.
func (v verification) failed(existingTableName string, instanceID, verificationID database.Column) database.CTEChange {
return database.NewCTEChange(func(builder *database.StatementBuilder) {
builder.WriteString("UPDATE ")
builder.WriteString(v.qualifiedTableName())
builder.WriteString(" SET ")
err := database.NewIncrementColumnChange(v.failedAttemptsColumn(), database.Coalesce(v.failedAttemptsColumn(), 0)).Write(builder)
logging.New(logging.StreamRuntime).Debug("write cte failed", "error", err)
builder.WriteString(" FROM ")
builder.WriteString(existingTableName)
writeCondition(builder, database.And(
database.NewColumnCondition(v.instanceIDColumn(), instanceID),
database.NewColumnCondition(v.idColumn(), verificationID),
))
}, nil)
}
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
func (v verification) instanceIDColumn() database.Column {
return database.NewColumn(v.unqualifiedTableName(), "instance_id")
}
func (v verification) idColumn() database.Column {
return database.NewColumn(v.unqualifiedTableName(), "id")
}
func (v verification) codeColumn() database.Column {
return database.NewColumn(v.unqualifiedTableName(), "code")
}
func (v verification) expiryColumn() database.Column {
return database.NewColumn(v.unqualifiedTableName(), "expiry")
}
func (v verification) failedAttemptsColumn() database.Column {
return database.NewColumn(v.unqualifiedTableName(), "failed_attempts")
}
func (v verification) userIDColumn() database.Column {
return database.NewColumn(v.unqualifiedTableName(), "user_id")
}
func (v verification) updatedAtColumn() database.Column {
return database.NewColumn(v.unqualifiedTableName(), "updated_at")
}
+4 -3
View File
@@ -8,9 +8,10 @@ import (
type Instruction string type Instruction string
const ( const (
DefaultInstruction Instruction = "DEFAULT" DefaultInstruction Instruction = "DEFAULT"
NowInstruction Instruction = "NOW()" NowInstruction Instruction = "NOW()"
NullInstruction Instruction = "NULL" NullInstruction Instruction = "NULL"
GenRandomUUIDInstruction Instruction = "gen_random_uuid()"
) )
// StatementBuilder is a helper to build SQL statement. // StatementBuilder is a helper to build SQL statement.
+7 -1
View File
@@ -30,12 +30,13 @@ require (
github.com/drone/envsubst v1.0.3 github.com/drone/envsubst v1.0.3
github.com/envoyproxy/protoc-gen-validate v1.2.1 github.com/envoyproxy/protoc-gen-validate v1.2.1
github.com/fatih/color v1.18.0 github.com/fatih/color v1.18.0
github.com/fergusstrange/embedded-postgres v1.30.0 github.com/fergusstrange/embedded-postgres v1.33.0
github.com/gabriel-vasile/mimetype v1.4.11 github.com/gabriel-vasile/mimetype v1.4.11
github.com/georgysavva/scany/v2 v2.1.4 github.com/georgysavva/scany/v2 v2.1.4
github.com/go-chi/chi/v5 v5.2.3 github.com/go-chi/chi/v5 v5.2.3
github.com/go-jose/go-jose/v4 v4.1.3 github.com/go-jose/go-jose/v4 v4.1.3
github.com/go-ldap/ldap/v3 v3.4.12 github.com/go-ldap/ldap/v3 v3.4.12
github.com/go-resty/resty/v2 v2.16.5
github.com/go-webauthn/webauthn v0.10.2 github.com/go-webauthn/webauthn v0.10.2
github.com/goccy/go-json v0.10.5 github.com/goccy/go-json v0.10.5
github.com/golang/protobuf v1.5.4 github.com/golang/protobuf v1.5.4
@@ -134,6 +135,7 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217
google.golang.org/grpc v1.77.0 google.golang.org/grpc v1.77.0
google.golang.org/protobuf v1.36.10 google.golang.org/protobuf v1.36.10
gopkg.in/headzoo/surf.v1 v1.0.1
sigs.k8s.io/yaml v1.6.0 sigs.k8s.io/yaml v1.6.0
) )
@@ -152,7 +154,9 @@ require (
github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/PuerkitoBio/goquery v1.5.1 // indirect
github.com/amdonov/xmlsig v0.1.0 // indirect github.com/amdonov/xmlsig v0.1.0 // indirect
github.com/andybalholm/cascadia v1.1.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect
@@ -199,6 +203,8 @@ require (
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect
github.com/h2non/filetype v1.1.3 // indirect github.com/h2non/filetype v1.1.3 // indirect
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
github.com/headzoo/surf v1.0.1 // indirect
github.com/headzoo/ut v0.0.0-20181013193318-a13b5a7a02ca // indirect
github.com/huandu/xstrings v1.5.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
+12 -2
View File
@@ -60,6 +60,7 @@ github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
@@ -86,6 +87,7 @@ github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21j
github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
github.com/amdonov/xmlsig v0.1.0 h1:i0iQ3neKLmUhcfIRgiiR3eRPKgXZj+n5lAfqnfKoeXI= github.com/amdonov/xmlsig v0.1.0 h1:i0iQ3neKLmUhcfIRgiiR3eRPKgXZj+n5lAfqnfKoeXI=
github.com/amdonov/xmlsig v0.1.0/go.mod h1:jTR/jO0E8fSl/cLvMesP+RjxyV4Ux4WL1Ip64ZnQpA0= github.com/amdonov/xmlsig v0.1.0/go.mod h1:jTR/jO0E8fSl/cLvMesP+RjxyV4Ux4WL1Ip64ZnQpA0=
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
@@ -224,8 +226,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fergusstrange/embedded-postgres v1.30.0 h1:ewv1e6bBlqOIYtgGgRcEnNDpfGlmfPxB8T3PO9tV68Q= github.com/fergusstrange/embedded-postgres v1.33.0 h1:ka8vmRpm4IDsES7NPXQ/NThAp1fc/f+crcXYjCW7wK0=
github.com/fergusstrange/embedded-postgres v1.30.0/go.mod h1:w0YvnCgf19o6tskInrOOACtnqfVlOvluz3hlNLY7tRk= github.com/fergusstrange/embedded-postgres v1.33.0/go.mod h1:w0YvnCgf19o6tskInrOOACtnqfVlOvluz3hlNLY7tRk=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
@@ -274,6 +276,8 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q= github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q=
github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@@ -429,6 +433,10 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/headzoo/surf v1.0.1 h1:wk3+LT8gjnCxEwfBJl6MhaNg154En5KjgmgzAG9uMS0=
github.com/headzoo/surf v1.0.1/go.mod h1:/bct0m/iMNEqpn520y01yoaWxsAEigGFPnvyR1ewR5M=
github.com/headzoo/ut v0.0.0-20181013193318-a13b5a7a02ca h1:utFgFwgxaqx5OthzE3DSGrtOq7rox5r2sxZ2wbfTuK0=
github.com/headzoo/ut v0.0.0-20181013193318-a13b5a7a02ca/go.mod h1:8926sG02TCOX4RFRzIMFIzRw4xuc/TwO2gtN7teMJZ4=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@@ -1128,6 +1136,8 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/headzoo/surf.v1 v1.0.1 h1:oDBy9b5NlTb2Hvl3hF8NN+Qy7ypC9/g5YDP85pPh13k=
gopkg.in/headzoo/surf.v1 v1.0.1/go.mod h1:T0BH8276y+OPL0E4tisxCFjBVIAKGbwdYU7AS7/EpQQ=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+1 -1
View File
@@ -14,7 +14,7 @@ func StartEmbedded() (embeddedpostgres.Config, func()) {
port, close := getPort() port, close := getPort()
config := embeddedpostgres.DefaultConfig().Version(embeddedpostgres.V16).Port(uint32(port)).RuntimePath(path) config := embeddedpostgres.DefaultConfig().Version(embeddedpostgres.V17).Port(uint32(port)).RuntimePath(path)
embedded := embeddedpostgres.NewDatabase(config) embedded := embeddedpostgres.NewDatabase(config)
close() close()
+230 -232
View File
@@ -1,257 +1,255 @@
package projection package projection
// TODO(adlerhurst): Uncomment once users table is created and FK can be enforced import (
"context"
"database/sql"
"encoding/json"
// import ( "github.com/zitadel/zitadel/backend/v3/domain"
// "context" "github.com/zitadel/zitadel/backend/v3/storage/database"
// "database/sql" v3_sql "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/sql"
// "encoding/json" "github.com/zitadel/zitadel/backend/v3/storage/database/repository"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
"github.com/zitadel/zitadel/internal/repository/idpintent"
"github.com/zitadel/zitadel/internal/zerrors"
)
// "github.com/zitadel/zitadel/backend/v3/domain" const (
// "github.com/zitadel/zitadel/backend/v3/storage/database" IDPIntentRelationalProjectionTable = "zitadel.identity_provider_intents"
// v3_sql "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/sql" )
// "github.com/zitadel/zitadel/backend/v3/storage/database/repository"
// "github.com/zitadel/zitadel/internal/eventstore"
// "github.com/zitadel/zitadel/internal/eventstore/handler/v2"
// "github.com/zitadel/zitadel/internal/repository/idpintent"
// "github.com/zitadel/zitadel/internal/zerrors"
// )
// const ( type idpIntentRelationalProjection struct{}
// IDPIntentRelationalProjectionTable = "zitadel.identity_provider_intents"
// )
// type idpIntentRelationalProjection struct{} func (*idpIntentRelationalProjection) Name() string {
return IDPIntentRelationalProjectionTable
}
// func (*idpIntentRelationalProjection) Name() string { func newIDPIntentRelationalProjection(ctx context.Context, config handler.Config) *handler.Handler {
// return IDPIntentRelationalProjectionTable return handler.NewHandler(ctx, &config, new(idpIntentRelationalProjection))
// } }
// func newIDPIntentRelationalProjection(ctx context.Context, config handler.Config) *handler.Handler { // Reducers implements [handler.Projection].
// return handler.NewHandler(ctx, &config, new(idpIntentRelationalProjection)) func (i *idpIntentRelationalProjection) Reducers() []handler.AggregateReducer {
// } return []handler.AggregateReducer{
{
Aggregate: idpintent.AggregateType,
EventReducers: []handler.EventReducer{
{Event: idpintent.StartedEventType, Reduce: i.reduceStartedEvent},
{Event: idpintent.SucceededEventType, Reduce: i.reduceSucceededEvent},
{Event: idpintent.SAMLSucceededEventType, Reduce: i.reduceSAMLSucceededEvent},
{Event: idpintent.SAMLRequestEventType, Reduce: i.reduceSAMLRequestEvent},
{Event: idpintent.LDAPSucceededEventType, Reduce: i.reduceLDAPSucceededEvent},
{Event: idpintent.FailedEventType, Reduce: i.reduceFailedEvent},
{Event: idpintent.ConsumedEventType, Reduce: i.reduceConsumedEvent},
},
},
}
// // Reducers implements [handler.Projection]. }
// func (i *idpIntentRelationalProjection) Reducers() []handler.AggregateReducer {
// return []handler.AggregateReducer{
// {
// Aggregate: idpintent.AggregateType,
// EventReducers: []handler.EventReducer{
// {Event: idpintent.StartedEventType, Reduce: i.reduceStartedEvent},
// {Event: idpintent.SucceededEventType, Reduce: i.reduceSucceededEvent},
// {Event: idpintent.SAMLSucceededEventType, Reduce: i.reduceSAMLSucceededEvent},
// {Event: idpintent.SAMLRequestEventType, Reduce: i.reduceSAMLRequestEvent},
// {Event: idpintent.LDAPSucceededEventType, Reduce: i.reduceLDAPSucceededEvent},
// {Event: idpintent.FailedEventType, Reduce: i.reduceFailedEvent},
// {Event: idpintent.ConsumedEventType, Reduce: i.reduceConsumedEvent},
// },
// },
// }
// } func (i *idpIntentRelationalProjection) reduceStartedEvent(evt eventstore.Event) (*handler.Statement, error) {
e, ok := evt.(*idpintent.StartedEvent)
if !ok {
return nil, zerrors.ThrowInternalf(nil, "HANDL-Lqj3HB", "reduce.wrong.event.type %s", idpintent.StartedEventType)
}
return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error {
tx, ok := ex.(*sql.Tx)
if !ok {
return zerrors.ThrowInvalidArgumentf(nil, "HANDL-rirFQm", "reduce.wrong.db.pool %T", ex)
}
// func (i *idpIntentRelationalProjection) reduceStartedEvent(evt eventstore.Event) (*handler.Statement, error) { repo := repository.IDPIntentRepository()
// e, ok := evt.(*idpintent.StartedEvent) return repo.Create(ctx, v3_sql.SQLTx(tx), &domain.IDPIntent{
// if !ok { ID: e.Aggregate().ID,
// return nil, zerrors.ThrowInternalf(nil, "HANDL-Lqj3HB", "reduce.wrong.event.type %s", idpintent.StartedEventType) InstanceID: e.Aggregate().InstanceID,
// } State: domain.IDPIntentStateStarted,
// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { SuccessURL: e.SuccessURL,
// tx, ok := ex.(*sql.Tx) FailureURL: e.FailureURL,
// if !ok { CreatedAt: e.CreationDate(),
// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-rirFQm", "reduce.wrong.db.pool %T", ex) UpdatedAt: e.CreationDate(),
// } IDPID: e.IDPID,
IDPArguments: e.IDPArguments,
})
}), nil
}
// repo := repository.IDPIntentRepository() func (i *idpIntentRelationalProjection) reduceSucceededEvent(evt eventstore.Event) (*handler.Statement, error) {
// return repo.Create(ctx, v3_sql.SQLTx(tx), &domain.IDPIntent{ e, ok := evt.(*idpintent.SucceededEvent)
// ID: e.Aggregate().ID, if !ok {
// InstanceID: e.Aggregate().InstanceID, return nil, zerrors.ThrowInternalf(nil, "HANDL-hQSxj0", "reduce.wrong.event.type %s", idpintent.SucceededEventType)
// State: domain.IDPIntentStateStarted, }
// SuccessURL: e.SuccessURL, return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error {
// FailureURL: e.FailureURL, tx, ok := ex.(*sql.Tx)
// CreatedAt: e.CreationDate(), if !ok {
// UpdatedAt: e.CreationDate(), return zerrors.ThrowInvalidArgumentf(nil, "HANDL-ry4tFH", "reduce.wrong.db.pool %T", ex)
// IDPID: e.IDPID, }
// IDPArguments: e.IDPArguments, idpAccessToken, err := e.IDPAccessToken.Value()
// }) if err != nil {
// }), nil return err
// } }
jsonIDPAccessToken, ok := idpAccessToken.([]byte)
if !ok {
return zerrors.ThrowInternal(nil, "HANDL-32XE1L", "reduce.convertion.json.failed")
}
repo := repository.IDPIntentRepository()
// func (i *idpIntentRelationalProjection) reduceSucceededEvent(evt eventstore.Event) (*handler.Statement, error) { changes := []database.Change{
// e, ok := evt.(*idpintent.SucceededEvent) repo.SetState(domain.IDPIntentStateSucceeded),
// if !ok { repo.SetIDPUser(e.IDPUser),
// return nil, zerrors.ThrowInternalf(nil, "HANDL-hQSxj0", "reduce.wrong.event.type %s", idpintent.SucceededEventType) repo.SetIDPUserID(e.IDPUserID),
// } repo.SetIDPUsername(e.IDPUserName),
// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { repo.SetUserID(e.UserID),
// tx, ok := ex.(*sql.Tx) repo.SetIDPAccessToken(jsonIDPAccessToken),
// if !ok { repo.SetIDPIDToken(e.IDPIDToken),
// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-ry4tFH", "reduce.wrong.db.pool %T", ex) repo.SetSucceededAt(e.CreationDate()),
// } repo.SetExpiresAt(e.ExpiresAt),
// idpAccessToken, err := e.IDPAccessToken.Value() }
// if err != nil {
// return err
// }
// jsonIDPAccessToken, ok := idpAccessToken.([]byte)
// if !ok {
// return zerrors.ThrowInternal(nil, "HANDL-32XE1L", "reduce.convertion.json.failed")
// }
// repo := repository.IDPIntentRepository()
// changes := []database.Change{ _, err = repo.Update(
// repo.SetState(domain.IDPIntentStateSucceeded), ctx,
// repo.SetIDPUser(e.IDPUser), v3_sql.SQLTx(tx),
// repo.SetIDPUserID(e.IDPUserID), repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID),
// repo.SetIDPUsername(e.IDPUserName), changes...,
// repo.SetUserID(e.UserID), )
// repo.SetIDPAccessToken(jsonIDPAccessToken), return err
// repo.SetIDPIDToken(e.IDPIDToken), }), nil
// repo.SetSucceededAt(e.CreationDate()), }
// repo.SetExpiresAt(e.ExpiresAt),
// }
// _, err = repo.Update( func (i *idpIntentRelationalProjection) reduceSAMLSucceededEvent(evt eventstore.Event) (*handler.Statement, error) {
// ctx, e, ok := evt.(*idpintent.SAMLSucceededEvent)
// v3_sql.SQLTx(tx), if !ok {
// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID), return nil, zerrors.ThrowInternalf(nil, "HANDL-t2uaiv", "reduce.wrong.event.type %s", idpintent.SAMLSucceededEventType)
// changes..., }
// ) return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error {
// return err tx, ok := ex.(*sql.Tx)
// }), nil if !ok {
// } return zerrors.ThrowInvalidArgumentf(nil, "HANDL-0QGPXm", "reduce.wrong.db.pool %T", ex)
}
assertion, err := e.Assertion.Value()
if err != nil {
return err
}
jsonAssertion, ok := assertion.([]byte)
if !ok {
return zerrors.ThrowInternal(nil, "HANDL-1TFjTi", "reduce.convertion.json.failed")
}
// func (i *idpIntentRelationalProjection) reduceSAMLSucceededEvent(evt eventstore.Event) (*handler.Statement, error) { repo := repository.IDPIntentRepository()
// e, ok := evt.(*idpintent.SAMLSucceededEvent) _, err = repo.Update(
// if !ok { ctx,
// return nil, zerrors.ThrowInternalf(nil, "HANDL-t2uaiv", "reduce.wrong.event.type %s", idpintent.SAMLSucceededEventType) v3_sql.SQLTx(tx),
// } repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID),
// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { repo.SetState(domain.IDPIntentStateSucceeded),
// tx, ok := ex.(*sql.Tx) repo.SetIDPUser(e.IDPUser),
// if !ok { repo.SetIDPUserID(e.IDPUserID),
// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-0QGPXm", "reduce.wrong.db.pool %T", ex) repo.SetIDPUsername(e.IDPUserName),
// } repo.SetUserID(e.UserID),
// assertion, err := e.Assertion.Value() repo.SetAssertion(jsonAssertion),
// if err != nil { repo.SetSucceededAt(e.CreationDate()),
// return err repo.SetExpiresAt(e.ExpiresAt),
// } )
// jsonAssertion, ok := assertion.([]byte) return err
// if !ok { }), nil
// return zerrors.ThrowInternal(nil, "HANDL-1TFjTi", "reduce.convertion.json.failed") }
// }
// repo := repository.IDPIntentRepository() func (i *idpIntentRelationalProjection) reduceSAMLRequestEvent(evt eventstore.Event) (*handler.Statement, error) {
// _, err = repo.Update( e, ok := evt.(*idpintent.SAMLRequestEvent)
// ctx, if !ok {
// v3_sql.SQLTx(tx), return nil, zerrors.ThrowInternalf(nil, "HANDL-f7O6K2", "reduce.wrong.event.type %s", idpintent.SAMLRequestEventType)
// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID), }
// repo.SetState(domain.IDPIntentStateSucceeded), return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error {
// repo.SetIDPUser(e.IDPUser), tx, ok := ex.(*sql.Tx)
// repo.SetIDPUserID(e.IDPUserID), if !ok {
// repo.SetIDPUsername(e.IDPUserName), return zerrors.ThrowInvalidArgumentf(nil, "HANDL-ijgAPJ", "reduce.wrong.db.pool %T", ex)
// repo.SetUserID(e.UserID), }
// repo.SetAssertion(jsonAssertion),
// repo.SetSucceededAt(e.CreationDate()),
// repo.SetExpiresAt(e.ExpiresAt),
// )
// return err
// }), nil
// }
// func (i *idpIntentRelationalProjection) reduceSAMLRequestEvent(evt eventstore.Event) (*handler.Statement, error) { repo := repository.IDPIntentRepository()
// e, ok := evt.(*idpintent.SAMLRequestEvent) _, err := repo.Update(
// if !ok { ctx,
// return nil, zerrors.ThrowInternalf(nil, "HANDL-f7O6K2", "reduce.wrong.event.type %s", idpintent.SAMLRequestEventType) v3_sql.SQLTx(tx),
// } repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID),
// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { repo.SetRequestID(e.RequestID),
// tx, ok := ex.(*sql.Tx) )
// if !ok { return err
// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-ijgAPJ", "reduce.wrong.db.pool %T", ex) }), nil
// } }
// repo := repository.IDPIntentRepository() func (i *idpIntentRelationalProjection) reduceLDAPSucceededEvent(evt eventstore.Event) (*handler.Statement, error) {
// _, err := repo.Update( e, ok := evt.(*idpintent.LDAPSucceededEvent)
// ctx, if !ok {
// v3_sql.SQLTx(tx), return nil, zerrors.ThrowInternalf(nil, "HANDL-Gw8ddW", "reduce.wrong.event.type %s", idpintent.LDAPSucceededEventType)
// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID), }
// repo.SetRequestID(e.RequestID), return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error {
// ) tx, ok := ex.(*sql.Tx)
// return err if !ok {
// }), nil return zerrors.ThrowInvalidArgumentf(nil, "HANDL-tNp8aa", "reduce.wrong.db.pool %T", ex)
// } }
// func (i *idpIntentRelationalProjection) reduceLDAPSucceededEvent(evt eventstore.Event) (*handler.Statement, error) { jsonAttributes, err := json.Marshal(e.EntryAttributes)
// e, ok := evt.(*idpintent.LDAPSucceededEvent) if err != nil {
// if !ok { return zerrors.ThrowInternal(nil, "HANDL-LuvCvD", "reduce.convertion.json.failed")
// return nil, zerrors.ThrowInternalf(nil, "HANDL-Gw8ddW", "reduce.wrong.event.type %s", idpintent.LDAPSucceededEventType) }
// }
// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error {
// tx, ok := ex.(*sql.Tx)
// if !ok {
// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-tNp8aa", "reduce.wrong.db.pool %T", ex)
// }
// jsonAttributes, err := json.Marshal(e.EntryAttributes) repo := repository.IDPIntentRepository()
// if err != nil { _, err = repo.Update(
// return zerrors.ThrowInternal(nil, "HANDL-LuvCvD", "reduce.convertion.json.failed") ctx,
// } v3_sql.SQLTx(tx),
repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID),
repo.SetState(domain.IDPIntentStateSucceeded),
repo.SetIDPUser(e.IDPUser),
repo.SetIDPUserID(e.IDPUserID),
repo.SetIDPUsername(e.IDPUserName),
repo.SetUserID(e.UserID),
repo.SetIDPEntryAttributes(jsonAttributes),
repo.SetSucceededAt(e.CreationDate()),
repo.SetExpiresAt(e.ExpiresAt),
)
return err
}), nil
}
// repo := repository.IDPIntentRepository() func (i *idpIntentRelationalProjection) reduceFailedEvent(evt eventstore.Event) (*handler.Statement, error) {
// _, err = repo.Update( e, ok := evt.(*idpintent.FailedEvent)
// ctx, if !ok {
// v3_sql.SQLTx(tx), return nil, zerrors.ThrowInternalf(nil, "HANDL-x3o9LZ", "reduce.wrong.event.type %s", idpintent.FailedEventType)
// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID), }
// repo.SetState(domain.IDPIntentStateSucceeded), return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error {
// repo.SetIDPUser(e.IDPUser), tx, ok := ex.(*sql.Tx)
// repo.SetIDPUserID(e.IDPUserID), if !ok {
// repo.SetIDPUsername(e.IDPUserName), return zerrors.ThrowInvalidArgumentf(nil, "HANDL-iqmR8O", "reduce.wrong.db.pool %T", ex)
// repo.SetUserID(e.UserID), }
// repo.SetIDPEntryAttributes(jsonAttributes),
// repo.SetSucceededAt(e.CreationDate()),
// repo.SetExpiresAt(e.ExpiresAt),
// )
// return err
// }), nil
// }
// func (i *idpIntentRelationalProjection) reduceFailedEvent(evt eventstore.Event) (*handler.Statement, error) { repo := repository.IDPIntentRepository()
// e, ok := evt.(*idpintent.FailedEvent) _, err := repo.Update(
// if !ok { ctx,
// return nil, zerrors.ThrowInternalf(nil, "HANDL-x3o9LZ", "reduce.wrong.event.type %s", idpintent.FailedEventType) v3_sql.SQLTx(tx),
// } repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID),
// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { repo.SetState(domain.IDPIntentStateFailed),
// tx, ok := ex.(*sql.Tx) repo.SetFailReason(e.Reason),
// if !ok { repo.SetFailedAt(e.CreatedAt()),
// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-iqmR8O", "reduce.wrong.db.pool %T", ex) )
// } return err
}), nil
}
// repo := repository.IDPIntentRepository() func (i *idpIntentRelationalProjection) reduceConsumedEvent(evt eventstore.Event) (*handler.Statement, error) {
// _, err := repo.Update( e, ok := evt.(*idpintent.ConsumedEvent)
// ctx, if !ok {
// v3_sql.SQLTx(tx), return nil, zerrors.ThrowInternalf(nil, "HANDL-jHZs6T", "reduce.wrong.event.type %s", idpintent.ConsumedEventType)
// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID), }
// repo.SetState(domain.IDPIntentStateFailed), return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error {
// repo.SetFailReason(e.Reason), tx, ok := ex.(*sql.Tx)
// repo.SetFailedAt(e.CreatedAt()), if !ok {
// ) return zerrors.ThrowInvalidArgumentf(nil, "HANDL-8X9U9w", "reduce.wrong.db.pool %T", ex)
// return err }
// }), nil
// }
// func (i *idpIntentRelationalProjection) reduceConsumedEvent(evt eventstore.Event) (*handler.Statement, error) { repo := repository.IDPIntentRepository()
// e, ok := evt.(*idpintent.ConsumedEvent) _, err := repo.Delete(
// if !ok { ctx,
// return nil, zerrors.ThrowInternalf(nil, "HANDL-jHZs6T", "reduce.wrong.event.type %s", idpintent.ConsumedEventType) v3_sql.SQLTx(tx),
// } repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID),
// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { )
// tx, ok := ex.(*sql.Tx) return err
// if !ok { }), nil
// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-8X9U9w", "reduce.wrong.db.pool %T", ex) }
// }
// repo := repository.IDPIntentRepository()
// _, err := repo.Delete(
// ctx,
// v3_sql.SQLTx(tx),
// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID),
// )
// return err
// }), nil
// }
+6 -6
View File
@@ -101,8 +101,8 @@ var (
ProjectGrantRelationalProjection *handler.Handler ProjectGrantRelationalProjection *handler.Handler
SessionRelationalProjection *handler.Handler SessionRelationalProjection *handler.Handler
SettingsRelationalProjection *handler.Handler SettingsRelationalProjection *handler.Handler
// TODO(adlerhurst): Uncomment once users table is created and FK can be enforced UserRelationalProjection *handler.Handler
// IDPIntentRelationalProjection *handler.Handler IDPIntentRelationalProjection *handler.Handler
ProjectGrantFields *handler.FieldHandler ProjectGrantFields *handler.FieldHandler
OrgDomainVerifiedFields *handler.FieldHandler OrgDomainVerifiedFields *handler.FieldHandler
@@ -232,8 +232,8 @@ func Create(ctx context.Context, sqlClient *database.DB, es handler.EventStore,
AuthorizationRelationalProjection = newAuthorizationRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["authorizations_relational"])) AuthorizationRelationalProjection = newAuthorizationRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["authorizations_relational"]))
ProjectGrantRelationalProjection = newProjectGrantRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["project_grant_relational"])) ProjectGrantRelationalProjection = newProjectGrantRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["project_grant_relational"]))
SessionRelationalProjection = newSessionRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["session_relational"])) SessionRelationalProjection = newSessionRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["session_relational"]))
// TODO(adlerhurst): Uncomment once users table is created and FK can be enforced UserRelationalProjection = newUserRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["user_relational"]))
// IDPIntentRelationalProjection = newIDPIntentRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_intent_relational"])) IDPIntentRelationalProjection = newIDPIntentRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_intent_relational"]))
newProjectionsList() newProjectionsList()
newFieldsList() newFieldsList()
@@ -428,10 +428,10 @@ func newProjectionsList() {
ProjectRelationalProjection, ProjectRelationalProjection,
ProjectRoleRelationalProjection, ProjectRoleRelationalProjection,
OrganizationMetadataRelationalProjection, OrganizationMetadataRelationalProjection,
UserRelationalProjection,
AuthorizationRelationalProjection, AuthorizationRelationalProjection,
ProjectGrantRelationalProjection, ProjectGrantRelationalProjection,
SessionRelationalProjection, SessionRelationalProjection,
// TODO(adlerhurst): Uncomment once users table is created and FK can be enforced IDPIntentRelationalProjection,
// IDPIntentRelationalProjection,
} }
} }
File diff suppressed because it is too large Load Diff
-1
View File
@@ -18,7 +18,6 @@ const (
HumanEmailVerificationFailedType = emailEventPrefix + "verification.failed" HumanEmailVerificationFailedType = emailEventPrefix + "verification.failed"
HumanEmailCodeAddedType = emailEventPrefix + "code.added" HumanEmailCodeAddedType = emailEventPrefix + "code.added"
HumanEmailCodeSentType = emailEventPrefix + "code.sent" HumanEmailCodeSentType = emailEventPrefix + "code.sent"
HumanEmailConfirmURLAddedType = emailEventPrefix + "confirm_url.added"
) )
type HumanEmailChangedEvent struct { type HumanEmailChangedEvent struct {