mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
feat(settings_relational): adding settings table for relational db (#10769)
# Which Problems Are Solved As part of https://github.com/zitadel/zitadel/issues/9599 to push to move to a relational db table model, this is the migration of the settings # Additional Changes I had to add 2 non source code files `backend/v3/storage/database/events_testing/font.otf` and `backend/v3/storage/database/events_testing/picture.png`, these are used as part of the reduce tests, hence why they're sourced inside `backend/v3/storage/database/events_testing/settings_instance_test.go` - Closes https://github.com/zitadel/zitadel/issues/10207 --------- Co-authored-by: adlerhurst <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Tim Möhlmann <[email protected]> Co-authored-by: Stefan Benz <[email protected]>
This commit is contained in:
co-authored by
adlerhurst
Copilot
Tim Möhlmann
Stefan Benz
parent
6c8619e2f0
commit
911967c865
@@ -1,12 +1,9 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrNoAdminSpecified = errors.New("at least one admin must be specified")
|
|
||||||
|
|
||||||
type wrongIDPTypeError struct {
|
type wrongIDPTypeError struct {
|
||||||
expected IDPType
|
expected IDPType
|
||||||
got string
|
got string
|
||||||
|
|||||||
@@ -0,0 +1,430 @@
|
|||||||
|
package domain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||||
|
db_json "github.com/zitadel/zitadel/backend/v3/storage/database/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate enumer -type SettingType -transform snake -trimprefix SettingType -sql
|
||||||
|
type SettingType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
SettingTypeLogin SettingType = iota
|
||||||
|
SettingTypeBranding
|
||||||
|
SettingTypePasswordComplexity
|
||||||
|
SettingTypePasswordExpiry
|
||||||
|
SettingTypeDomain
|
||||||
|
SettingTypeLockout
|
||||||
|
SettingTypeSecurity
|
||||||
|
SettingTypeOrganization
|
||||||
|
SettingTypeNotification
|
||||||
|
SettingTypeLegalAndSupport
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate enumer -type SettingState -transform snake -trimprefix SettingState -sql
|
||||||
|
type SettingState int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
SettingStateActive SettingState = iota
|
||||||
|
SettingStatePreview
|
||||||
|
)
|
||||||
|
|
||||||
|
type Settings struct {
|
||||||
|
ID string `json:"id,omitempty" db:"id"`
|
||||||
|
InstanceID string `json:"instanceId,omitempty" db:"instance_id"`
|
||||||
|
OrganizationID *string `json:"organizationId,omitempty" db:"organization_id"`
|
||||||
|
Type SettingType `json:"type,omitempty" db:"type"`
|
||||||
|
State SettingState `json:"state,omitempty" db:"state"`
|
||||||
|
Settings []byte `json:"settings,omitempty" db:"settings"`
|
||||||
|
CreatedAt time.Time `json:"createdAt,omitzero" db:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt,omitzero" db:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type settingsColumns interface {
|
||||||
|
IDColumn() database.Column
|
||||||
|
InstanceIDColumn() database.Column
|
||||||
|
OrganizationIDColumn() database.Column
|
||||||
|
TypeColumn() database.Column
|
||||||
|
StateColumn() database.Column
|
||||||
|
SettingsColumn() database.Column
|
||||||
|
CreatedAtColumn() database.Column
|
||||||
|
UpdatedAtColumn() database.Column
|
||||||
|
PrimaryKeyColumns() []database.Column
|
||||||
|
UniqueColumns() []database.Column
|
||||||
|
}
|
||||||
|
|
||||||
|
type settingsConditions interface {
|
||||||
|
InstanceIDCondition(id string) database.Condition
|
||||||
|
OrganizationIDCondition(id *string) database.Condition
|
||||||
|
IDCondition(id string) database.Condition
|
||||||
|
PrimaryKeyCondition(instanceID, id string) database.Condition
|
||||||
|
UniqueCondition(instanceID string, orgID *string, typ SettingType, state SettingState) database.Condition
|
||||||
|
}
|
||||||
|
|
||||||
|
type settingsChanges interface {
|
||||||
|
// SetSettings(settings string) database.Change
|
||||||
|
SetUpdatedAt(updatedAt *time.Time) database.Change
|
||||||
|
}
|
||||||
|
|
||||||
|
type settingsRepository[T any] interface {
|
||||||
|
settingsColumns
|
||||||
|
settingsConditions
|
||||||
|
settingsChanges
|
||||||
|
|
||||||
|
Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*T, error)
|
||||||
|
List(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) ([]*T, error)
|
||||||
|
|
||||||
|
Set(ctx context.Context, client database.QueryExecutor, settings *T) error
|
||||||
|
Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordlessType int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
PasswordlessTypeNotAllowed PasswordlessType = iota
|
||||||
|
PasswordlessTypeAllowed
|
||||||
|
)
|
||||||
|
|
||||||
|
type MultiFactorType int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
MultiFactorTypeUnspecified MultiFactorType = iota
|
||||||
|
MultiFactorTypeU2FWithPIN
|
||||||
|
)
|
||||||
|
|
||||||
|
type SecondFactorType int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
SecondFactorTypeUnspecified SecondFactorType = iota
|
||||||
|
SecondFactorTypeTOTP
|
||||||
|
SecondFactorTypeU2F
|
||||||
|
SecondFactorTypeOTPEmail
|
||||||
|
SecondFactorTypeOTPSMS
|
||||||
|
)
|
||||||
|
|
||||||
|
type loginSettingsJSONChanges interface {
|
||||||
|
SetSettingFields(value LoginSettingsAttributes) database.Change
|
||||||
|
|
||||||
|
SetAllowUserNamePassword(value bool) db_json.JsonUpdate
|
||||||
|
SetAllowRegister(value bool) db_json.JsonUpdate
|
||||||
|
SetAllowExternalIDP(value bool) db_json.JsonUpdate
|
||||||
|
SetForceMFA(value bool) db_json.JsonUpdate
|
||||||
|
SetForceMFALocalOnly(value bool) db_json.JsonUpdate
|
||||||
|
SetHidePasswordReset(value bool) db_json.JsonUpdate
|
||||||
|
SetIgnoreUnknownUsernames(value bool) db_json.JsonUpdate
|
||||||
|
SetAllowDomainDiscovery(value bool) db_json.JsonUpdate
|
||||||
|
SetDisableLoginWithEmail(value bool) db_json.JsonUpdate
|
||||||
|
SetDisableLoginWithPhone(value bool) db_json.JsonUpdate
|
||||||
|
SetPasswordlessType(value PasswordlessType) db_json.JsonUpdate
|
||||||
|
SetDefaultRedirectURI(value string) db_json.JsonUpdate
|
||||||
|
SetPasswordCheckLifetime(value time.Duration) db_json.JsonUpdate
|
||||||
|
SetExternalLoginCheckLifetime(value time.Duration) db_json.JsonUpdate
|
||||||
|
SetMFAInitSkipLifetime(value time.Duration) db_json.JsonUpdate
|
||||||
|
SetSecondFactorCheckLifetime(value time.Duration) db_json.JsonUpdate
|
||||||
|
SetMultiFactorCheckLifetime(value time.Duration) db_json.JsonUpdate
|
||||||
|
|
||||||
|
AddMFAType(value MultiFactorType) database.Change
|
||||||
|
RemoveMFAType(value MultiFactorType) database.Change
|
||||||
|
AddSecondFactorTypes(value SecondFactorType) database.Change
|
||||||
|
RemoveSecondFactorTypes(value SecondFactorType) database.Change
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginSettings struct {
|
||||||
|
Settings
|
||||||
|
LoginSettingsAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginSettingsAttributes struct {
|
||||||
|
AllowUserNamePassword *bool `json:"allowUsernamePassword,omitempty"`
|
||||||
|
AllowRegister *bool `json:"allowRegister,omitempty"`
|
||||||
|
AllowExternalIDP *bool `json:"allowExternalIdp,omitempty"`
|
||||||
|
ForceMFA *bool `json:"forceMfa,omitempty"`
|
||||||
|
ForceMFALocalOnly *bool `json:"forceMfaLocalOnly,omitempty"`
|
||||||
|
HidePasswordReset *bool `json:"hidePasswordReset,omitempty"`
|
||||||
|
IgnoreUnknownUsernames *bool `json:"ignoreUnknownUsernames,omitempty"`
|
||||||
|
AllowDomainDiscovery *bool `json:"allowDomainDiscovery,omitempty"`
|
||||||
|
DisableLoginWithEmail *bool `json:"disableLoginWithEmail,omitempty"`
|
||||||
|
DisableLoginWithPhone *bool `json:"disableLoginWithPhone,omitempty"`
|
||||||
|
PasswordlessType *PasswordlessType `json:"passwordlessType,omitempty"`
|
||||||
|
DefaultRedirectURI *string `json:"defaultRedirectUri,omitempty"`
|
||||||
|
PasswordCheckLifetime *time.Duration `json:"passwordCheckLifetime,omitempty"`
|
||||||
|
ExternalLoginCheckLifetime *time.Duration `json:"externalLoginCheckLifetime,omitempty"`
|
||||||
|
MFAInitSkipLifetime *time.Duration `json:"mfaInitSkipLifetime,omitempty"`
|
||||||
|
SecondFactorCheckLifetime *time.Duration `json:"secondFactorCheckLifetime,omitempty"`
|
||||||
|
MultiFactorCheckLifetime *time.Duration `json:"multiFactorCheckLifetime,omitempty"`
|
||||||
|
|
||||||
|
MFAType []MultiFactorType `json:"mfaType,omitempty"`
|
||||||
|
SecondFactorTypes []SecondFactorType `json:"secondFactors,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginSettingsRepository interface {
|
||||||
|
settingsRepository[LoginSettings]
|
||||||
|
loginSettingsJSONChanges
|
||||||
|
|
||||||
|
SetColumns(ctx context.Context, client database.QueryExecutor, settings *Settings, changes ...database.Change) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type BrandingPolicyThemeMode int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
BrandingPolicyThemeAuto BrandingPolicyThemeMode = iota
|
||||||
|
BrandingPolicyThemeLight
|
||||||
|
BrandingPolicyThemeDark
|
||||||
|
)
|
||||||
|
|
||||||
|
type brandingSettingsJSONChanges interface {
|
||||||
|
SetSettingFields(value BrandingSettingsAttributes) database.Change
|
||||||
|
|
||||||
|
SetPrimaryColorLight(value string) db_json.JsonUpdate
|
||||||
|
SetBackgroundColorLight(value string) db_json.JsonUpdate
|
||||||
|
SetWarnColorLight(value string) db_json.JsonUpdate
|
||||||
|
SetFontColorLight(value string) db_json.JsonUpdate
|
||||||
|
SetLogoURLLight(value url.URL) db_json.JsonUpdate
|
||||||
|
SetIconURLLight(value url.URL) db_json.JsonUpdate
|
||||||
|
|
||||||
|
SetPrimaryColorDark(value string) db_json.JsonUpdate
|
||||||
|
SetBackgroundColorDark(value string) db_json.JsonUpdate
|
||||||
|
SetWarnColorDark(value string) db_json.JsonUpdate
|
||||||
|
SetFontColorDark(value string) db_json.JsonUpdate
|
||||||
|
SetLogoURLDark(value url.URL) db_json.JsonUpdate
|
||||||
|
SetIconURLDark(value url.URL) db_json.JsonUpdate
|
||||||
|
|
||||||
|
SetHideLoginNameSuffix(value bool) db_json.JsonUpdate
|
||||||
|
SetErrorMsgPopup(value bool) db_json.JsonUpdate
|
||||||
|
SetDisableWatermark(value bool) db_json.JsonUpdate
|
||||||
|
SetThemeMode(value BrandingPolicyThemeMode) db_json.JsonUpdate
|
||||||
|
SetFontURL(value url.URL) db_json.JsonUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
type BrandingSettings struct {
|
||||||
|
Settings
|
||||||
|
BrandingSettingsAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
type BrandingSettingsAttributes struct {
|
||||||
|
PrimaryColorLight *string `json:"primaryColorLight,omitempty"`
|
||||||
|
BackgroundColorLight *string `json:"backgroundColorLight,omitempty"`
|
||||||
|
WarnColorLight *string `json:"warnColorLight,omitempty"`
|
||||||
|
FontColorLight *string `json:"fontColorLight,omitempty"`
|
||||||
|
LogoURLLight *url.URL `json:"logoUrlLight,omitempty"`
|
||||||
|
IconURLLight *url.URL `json:"iconUrlLight,omitempty"`
|
||||||
|
|
||||||
|
PrimaryColorDark *string `json:"primaryColorDark,omitempty"`
|
||||||
|
BackgroundColorDark *string `json:"backgroundColorDark,omitempty"`
|
||||||
|
WarnColorDark *string `json:"warnColorDark,omitempty"`
|
||||||
|
FontColorDark *string `json:"fontColorDark,omitempty"`
|
||||||
|
LogoURLDark *url.URL `json:"logoUrlDark,omitempty"`
|
||||||
|
IconURLDark *url.URL `json:"iconUrlDark,omitempty"`
|
||||||
|
|
||||||
|
HideLoginNameSuffix *bool `json:"hideLoginNameSuffix,omitempty"`
|
||||||
|
ErrorMsgPopup *bool `json:"errorMsgPopup,omitempty"`
|
||||||
|
DisableWatermark *bool `json:"disableMsgPopup,omitempty"`
|
||||||
|
ThemeMode *BrandingPolicyThemeMode `json:"themeMode,omitempty"`
|
||||||
|
FontURL *url.URL `json:"fontUrl,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BrandingSettingsRepository interface {
|
||||||
|
settingsRepository[BrandingSettings]
|
||||||
|
brandingSettingsJSONChanges
|
||||||
|
|
||||||
|
StateCondition(typ SettingState) database.Condition
|
||||||
|
Activate(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error)
|
||||||
|
ActivateAt(ctx context.Context, client database.QueryExecutor, condition database.Condition, updatedAt time.Time) (int64, error)
|
||||||
|
SetColumns(ctx context.Context, client database.QueryExecutor, settings *Settings, changes ...database.Change) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type passwordComplexitySettingsJSONChanges interface {
|
||||||
|
SetSettingFields(value PasswordComplexitySettingsAttributes) database.Change
|
||||||
|
|
||||||
|
SetMinLength(value uint64) db_json.JsonUpdate
|
||||||
|
SetHasLowercase(value bool) db_json.JsonUpdate
|
||||||
|
SetHasUppercase(value bool) db_json.JsonUpdate
|
||||||
|
SetHasNumber(value bool) db_json.JsonUpdate
|
||||||
|
SetHasSymbol(value bool) db_json.JsonUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordComplexitySettings struct {
|
||||||
|
Settings
|
||||||
|
PasswordComplexitySettingsAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordComplexitySettingsAttributes struct {
|
||||||
|
MinLength *uint64 `json:"minLength,omitempty"`
|
||||||
|
HasLowercase *bool `json:"hasLowercase,omitempty"`
|
||||||
|
HasUppercase *bool `json:"hasUppercase,omitempty"`
|
||||||
|
HasNumber *bool `json:"hasNumber,omitempty"`
|
||||||
|
HasSymbol *bool `json:"hasSymbol,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordComplexitySettingsRepository interface {
|
||||||
|
settingsRepository[PasswordComplexitySettings]
|
||||||
|
passwordComplexitySettingsJSONChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
type passwordExpirySettingsJSONChanges interface {
|
||||||
|
SetSettingFields(value PasswordExpirySettingsAttributes) database.Change
|
||||||
|
|
||||||
|
SetExpireWarnDays(value uint64) db_json.JsonUpdate
|
||||||
|
SetMaxAgeDays(value uint64) db_json.JsonUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordExpirySettings struct {
|
||||||
|
Settings
|
||||||
|
PasswordExpirySettingsAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordExpirySettingsAttributes struct {
|
||||||
|
ExpireWarnDays *uint64 `json:"expireWarnDays,omitempty"`
|
||||||
|
MaxAgeDays *uint64 `json:"maxAgeDays,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordExpirySettingsRepository interface {
|
||||||
|
settingsRepository[PasswordExpirySettings]
|
||||||
|
passwordExpirySettingsJSONChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
type lockoutSettingsJSONChanges interface {
|
||||||
|
SetSettingFields(value LockoutSettingsAttributes) database.Change
|
||||||
|
|
||||||
|
SetMaxPasswordAttempts(value uint64) db_json.JsonUpdate
|
||||||
|
SetMaxOTPAttempts(value uint64) db_json.JsonUpdate
|
||||||
|
SetShowLockOutFailures(value bool) db_json.JsonUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
type LockoutSettings struct {
|
||||||
|
Settings
|
||||||
|
LockoutSettingsAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
type LockoutSettingsAttributes struct {
|
||||||
|
MaxPasswordAttempts *uint64 `json:"maxPasswordAttempts,omitempty"`
|
||||||
|
MaxOTPAttempts *uint64 `json:"maxOtpAttempts,omitempty"`
|
||||||
|
ShowLockOutFailures *bool `json:"showLockOutFailures,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LockoutSettingsRepository interface {
|
||||||
|
settingsRepository[LockoutSettings]
|
||||||
|
lockoutSettingsJSONChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
type securitySettingsJSONChanges interface {
|
||||||
|
SetSettingFields(value SecuritySettingsAttributes) database.Change
|
||||||
|
|
||||||
|
SetEnableIframeEmbedding(value bool) db_json.JsonUpdate
|
||||||
|
SetAllowedOrigins(values []string) db_json.JsonUpdate
|
||||||
|
SetEnableImpersonation(value bool) db_json.JsonUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecuritySettings struct {
|
||||||
|
Settings
|
||||||
|
SecuritySettingsAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecuritySettingsAttributes struct {
|
||||||
|
EnableIframeEmbedding *bool `json:"enableIframeEmbedding,omitempty"`
|
||||||
|
AllowedOrigins []string `json:"allowedOrigins,omitempty"`
|
||||||
|
EnableImpersonation *bool `json:"enableImpersonation,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecuritySettingsRepository interface {
|
||||||
|
settingsRepository[SecuritySettings]
|
||||||
|
securitySettingsJSONChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
type domainSettingsJSONChanges interface {
|
||||||
|
SetSettingFields(value DomainSettingsAttributes) database.Change
|
||||||
|
|
||||||
|
SetLoginNameIncludesDomain(value bool) db_json.JsonUpdate
|
||||||
|
SetRequireOrgDomainVerification(value bool) db_json.JsonUpdate
|
||||||
|
SetSMTPSenderAddressMatchesInstanceDomain(value bool) db_json.JsonUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
type DomainSettings struct {
|
||||||
|
Settings
|
||||||
|
DomainSettingsAttributes
|
||||||
|
}
|
||||||
|
type DomainSettingsAttributes struct {
|
||||||
|
LoginNameIncludesDomain *bool `json:"loginNameIncludesDomain,omitempty"`
|
||||||
|
RequireOrgDomainVerification *bool `json:"requireOrgDomainVerification,omitempty"`
|
||||||
|
SMTPSenderAddressMatchesInstanceDomain *bool `json:"smtpSenderAddressMatchesInstanceDomain,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DomainSettingsRepository interface {
|
||||||
|
settingsRepository[DomainSettings]
|
||||||
|
domainSettingsJSONChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
type organizationSettingsJSONChanges interface {
|
||||||
|
SetSettingFields(value OrganizationSettingsAttributes) database.Change
|
||||||
|
|
||||||
|
SetOrganizationScopedUsernames(value bool) db_json.JsonUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrganizationSettings struct {
|
||||||
|
Settings
|
||||||
|
OrganizationSettingsAttributes
|
||||||
|
}
|
||||||
|
type OrganizationSettingsAttributes struct {
|
||||||
|
OrganizationScopedUsernames *bool `json:"organizationScopedUsernames,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrganizationSettingsRepository interface {
|
||||||
|
settingsRepository[OrganizationSettings]
|
||||||
|
organizationSettingsJSONChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
type notificationSettingsJSONChanges interface {
|
||||||
|
SetSettingFields(value NotificationSettingsAttributes) database.Change
|
||||||
|
|
||||||
|
SetPasswordChange(value bool) db_json.JsonUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotificationSettings struct {
|
||||||
|
Settings
|
||||||
|
NotificationSettingsAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotificationSettingsAttributes struct {
|
||||||
|
PasswordChange *bool `json:"passwordChange,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotificationSettingsRepository interface {
|
||||||
|
settingsRepository[NotificationSettings]
|
||||||
|
notificationSettingsJSONChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
type legalAndSupportSettingsJSONChanges interface {
|
||||||
|
SetSettingFields(value LegalAndSupportSettingsAttributes) database.Change
|
||||||
|
|
||||||
|
SetTOSLink(value string) db_json.JsonUpdate
|
||||||
|
SetPrivacyPolicyLink(value string) db_json.JsonUpdate
|
||||||
|
SetHelpLink(value string) db_json.JsonUpdate
|
||||||
|
SetSupportEmail(value string) db_json.JsonUpdate
|
||||||
|
SetDocsLink(value string) db_json.JsonUpdate
|
||||||
|
SetCustomLink(value string) db_json.JsonUpdate
|
||||||
|
SetCustomLinkText(value string) db_json.JsonUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
type LegalAndSupportSettings struct {
|
||||||
|
Settings
|
||||||
|
LegalAndSupportSettingsAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
type LegalAndSupportSettingsAttributes struct {
|
||||||
|
TOSLink *string `json:"tosLink,omitempty"`
|
||||||
|
PrivacyPolicyLink *string `json:"privacyPolicyLink,omitempty"`
|
||||||
|
HelpLink *string `json:"helpLink,omitempty"`
|
||||||
|
SupportEmail *string `json:"supportEmail,omitempty"`
|
||||||
|
DocsLink *string `json:"docsLink,omitempty"`
|
||||||
|
CustomLink *string `json:"customLink,omitempty"`
|
||||||
|
CustomLinkText *string `json:"customLinkText,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LegalAndSupportSettingsRepository interface {
|
||||||
|
settingsRepository[LegalAndSupportSettings]
|
||||||
|
legalAndSupportSettingsJSONChanges
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
// Code generated by "enumer -type SettingState -transform snake -trimprefix SettingState -sql"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const _SettingStateName = "activepreview"
|
||||||
|
|
||||||
|
var _SettingStateIndex = [...]uint8{0, 6, 13}
|
||||||
|
|
||||||
|
const _SettingStateLowerName = "activepreview"
|
||||||
|
|
||||||
|
func (i SettingState) String() string {
|
||||||
|
if i < 0 || i >= SettingState(len(_SettingStateIndex)-1) {
|
||||||
|
return fmt.Sprintf("SettingState(%d)", i)
|
||||||
|
}
|
||||||
|
return _SettingStateName[_SettingStateIndex[i]:_SettingStateIndex[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 _SettingStateNoOp() {
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[SettingStateActive-(0)]
|
||||||
|
_ = x[SettingStatePreview-(1)]
|
||||||
|
}
|
||||||
|
|
||||||
|
var _SettingStateValues = []SettingState{SettingStateActive, SettingStatePreview}
|
||||||
|
|
||||||
|
var _SettingStateNameToValueMap = map[string]SettingState{
|
||||||
|
_SettingStateName[0:6]: SettingStateActive,
|
||||||
|
_SettingStateLowerName[0:6]: SettingStateActive,
|
||||||
|
_SettingStateName[6:13]: SettingStatePreview,
|
||||||
|
_SettingStateLowerName[6:13]: SettingStatePreview,
|
||||||
|
}
|
||||||
|
|
||||||
|
var _SettingStateNames = []string{
|
||||||
|
_SettingStateName[0:6],
|
||||||
|
_SettingStateName[6:13],
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingStateString retrieves an enum value from the enum constants string name.
|
||||||
|
// Throws an error if the param is not part of the enum.
|
||||||
|
func SettingStateString(s string) (SettingState, error) {
|
||||||
|
if val, ok := _SettingStateNameToValueMap[s]; ok {
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := _SettingStateNameToValueMap[strings.ToLower(s)]; ok {
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("%s does not belong to SettingState values", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingStateValues returns all values of the enum
|
||||||
|
func SettingStateValues() []SettingState {
|
||||||
|
return _SettingStateValues
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingStateStrings returns a slice of all String values of the enum
|
||||||
|
func SettingStateStrings() []string {
|
||||||
|
strs := make([]string, len(_SettingStateNames))
|
||||||
|
copy(strs, _SettingStateNames)
|
||||||
|
return strs
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsASettingState returns "true" if the value is listed in the enum definition. "false" otherwise
|
||||||
|
func (i SettingState) IsASettingState() bool {
|
||||||
|
for _, v := range _SettingStateValues {
|
||||||
|
if i == v {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i SettingState) Value() (driver.Value, error) {
|
||||||
|
return i.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *SettingState) 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 SettingState: %[1]T(%[1]v)", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := SettingStateString(str)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*i = val
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
// Code generated by "enumer -type SettingType -transform snake -trimprefix SettingType -sql"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const _SettingTypeName = "loginbrandingpassword_complexitypassword_expirydomainlockoutsecurityorganizationnotificationlegal_and_support"
|
||||||
|
|
||||||
|
var _SettingTypeIndex = [...]uint8{0, 5, 13, 32, 47, 53, 60, 68, 80, 92, 109}
|
||||||
|
|
||||||
|
const _SettingTypeLowerName = "loginbrandingpassword_complexitypassword_expirydomainlockoutsecurityorganizationnotificationlegal_and_support"
|
||||||
|
|
||||||
|
func (i SettingType) String() string {
|
||||||
|
if i >= SettingType(len(_SettingTypeIndex)-1) {
|
||||||
|
return fmt.Sprintf("SettingType(%d)", i)
|
||||||
|
}
|
||||||
|
return _SettingTypeName[_SettingTypeIndex[i]:_SettingTypeIndex[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 _SettingTypeNoOp() {
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[SettingTypeLogin-(0)]
|
||||||
|
_ = x[SettingTypeBranding-(1)]
|
||||||
|
_ = x[SettingTypePasswordComplexity-(2)]
|
||||||
|
_ = x[SettingTypePasswordExpiry-(3)]
|
||||||
|
_ = x[SettingTypeDomain-(4)]
|
||||||
|
_ = x[SettingTypeLockout-(5)]
|
||||||
|
_ = x[SettingTypeSecurity-(6)]
|
||||||
|
_ = x[SettingTypeOrganization-(7)]
|
||||||
|
_ = x[SettingTypeNotification-(8)]
|
||||||
|
_ = x[SettingTypeLegalAndSupport-(9)]
|
||||||
|
}
|
||||||
|
|
||||||
|
var _SettingTypeValues = []SettingType{SettingTypeLogin, SettingTypeBranding, SettingTypePasswordComplexity, SettingTypePasswordExpiry, SettingTypeDomain, SettingTypeLockout, SettingTypeSecurity, SettingTypeOrganization, SettingTypeNotification, SettingTypeLegalAndSupport}
|
||||||
|
|
||||||
|
var _SettingTypeNameToValueMap = map[string]SettingType{
|
||||||
|
_SettingTypeName[0:5]: SettingTypeLogin,
|
||||||
|
_SettingTypeLowerName[0:5]: SettingTypeLogin,
|
||||||
|
_SettingTypeName[5:13]: SettingTypeBranding,
|
||||||
|
_SettingTypeLowerName[5:13]: SettingTypeBranding,
|
||||||
|
_SettingTypeName[13:32]: SettingTypePasswordComplexity,
|
||||||
|
_SettingTypeLowerName[13:32]: SettingTypePasswordComplexity,
|
||||||
|
_SettingTypeName[32:47]: SettingTypePasswordExpiry,
|
||||||
|
_SettingTypeLowerName[32:47]: SettingTypePasswordExpiry,
|
||||||
|
_SettingTypeName[47:53]: SettingTypeDomain,
|
||||||
|
_SettingTypeLowerName[47:53]: SettingTypeDomain,
|
||||||
|
_SettingTypeName[53:60]: SettingTypeLockout,
|
||||||
|
_SettingTypeLowerName[53:60]: SettingTypeLockout,
|
||||||
|
_SettingTypeName[60:68]: SettingTypeSecurity,
|
||||||
|
_SettingTypeLowerName[60:68]: SettingTypeSecurity,
|
||||||
|
_SettingTypeName[68:80]: SettingTypeOrganization,
|
||||||
|
_SettingTypeLowerName[68:80]: SettingTypeOrganization,
|
||||||
|
_SettingTypeName[80:92]: SettingTypeNotification,
|
||||||
|
_SettingTypeLowerName[80:92]: SettingTypeNotification,
|
||||||
|
_SettingTypeName[92:109]: SettingTypeLegalAndSupport,
|
||||||
|
_SettingTypeLowerName[92:109]: SettingTypeLegalAndSupport,
|
||||||
|
}
|
||||||
|
|
||||||
|
var _SettingTypeNames = []string{
|
||||||
|
_SettingTypeName[0:5],
|
||||||
|
_SettingTypeName[5:13],
|
||||||
|
_SettingTypeName[13:32],
|
||||||
|
_SettingTypeName[32:47],
|
||||||
|
_SettingTypeName[47:53],
|
||||||
|
_SettingTypeName[53:60],
|
||||||
|
_SettingTypeName[60:68],
|
||||||
|
_SettingTypeName[68:80],
|
||||||
|
_SettingTypeName[80:92],
|
||||||
|
_SettingTypeName[92:109],
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingTypeString retrieves an enum value from the enum constants string name.
|
||||||
|
// Throws an error if the param is not part of the enum.
|
||||||
|
func SettingTypeString(s string) (SettingType, error) {
|
||||||
|
if val, ok := _SettingTypeNameToValueMap[s]; ok {
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok := _SettingTypeNameToValueMap[strings.ToLower(s)]; ok {
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("%s does not belong to SettingType values", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingTypeValues returns all values of the enum
|
||||||
|
func SettingTypeValues() []SettingType {
|
||||||
|
return _SettingTypeValues
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingTypeStrings returns a slice of all String values of the enum
|
||||||
|
func SettingTypeStrings() []string {
|
||||||
|
strs := make([]string, len(_SettingTypeNames))
|
||||||
|
copy(strs, _SettingTypeNames)
|
||||||
|
return strs
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsASettingType returns "true" if the value is listed in the enum definition. "false" otherwise
|
||||||
|
func (i SettingType) IsASettingType() bool {
|
||||||
|
for _, v := range _SettingTypeValues {
|
||||||
|
if i == v {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i SettingType) Value() (driver.Value, error) {
|
||||||
|
return i.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *SettingType) 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 SettingType: %[1]T(%[1]v)", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := SettingTypeString(str)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*i = val
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
type Change interface {
|
type Change interface {
|
||||||
gomock.Matcher
|
gomock.Matcher
|
||||||
// Write writes the change to the given statement builder.
|
// Write writes the change to the given statement builder.
|
||||||
Write(builder *StatementBuilder)
|
Write(builder *StatementBuilder) error
|
||||||
// IsOnColumn checks if the change is on the given column.
|
// IsOnColumn checks if the change is on the given column.
|
||||||
IsOnColumn(col Column) bool
|
IsOnColumn(col Column) bool
|
||||||
}
|
}
|
||||||
@@ -62,10 +62,11 @@ func NewChangePtr[V Value](col Column, value *V) Change {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write implements [Change].
|
// Write implements [Change].
|
||||||
func (c change[V]) Write(builder *StatementBuilder) {
|
func (c change[V]) Write(builder *StatementBuilder) error {
|
||||||
c.column.WriteUnqualified(builder)
|
c.column.WriteUnqualified(builder)
|
||||||
builder.WriteString(" = ")
|
builder.WriteString(" = ")
|
||||||
builder.WriteArg(c.value)
|
builder.WriteArg(c.value)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsOnColumn implements [Change].
|
// IsOnColumn implements [Change].
|
||||||
@@ -87,13 +88,17 @@ func (c Changes) IsOnColumn(col Column) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write implements [Change].
|
// Write implements [Change].
|
||||||
func (m Changes) Write(builder *StatementBuilder) {
|
func (m Changes) Write(builder *StatementBuilder) error {
|
||||||
for i, change := range m {
|
for i, change := range m {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
builder.WriteString(", ")
|
builder.WriteString(", ")
|
||||||
}
|
}
|
||||||
change.Write(builder)
|
err := change.Write(builder)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matches implements [gomock.Matcher].
|
// Matches implements [gomock.Matcher].
|
||||||
@@ -153,10 +158,11 @@ func (c *changeToColumn) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write implements [Change].
|
// Write implements [Change].
|
||||||
func (c *changeToColumn) Write(builder *StatementBuilder) {
|
func (c *changeToColumn) Write(builder *StatementBuilder) error {
|
||||||
c.to.WriteUnqualified(builder)
|
c.to.WriteUnqualified(builder)
|
||||||
builder.WriteString(" = ")
|
builder.WriteString(" = ")
|
||||||
c.from.WriteQualified(builder)
|
c.from.WriteQualified(builder)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Change = (*changeToColumn)(nil)
|
var _ Change = (*changeToColumn)(nil)
|
||||||
@@ -191,11 +197,12 @@ func (i *incrementColumnChange) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write implements [Change].
|
// Write implements [Change].
|
||||||
func (i *incrementColumnChange) Write(builder *StatementBuilder) {
|
func (i *incrementColumnChange) Write(builder *StatementBuilder) error {
|
||||||
i.column.WriteUnqualified(builder)
|
i.column.WriteUnqualified(builder)
|
||||||
builder.WriteString(" = ")
|
builder.WriteString(" = ")
|
||||||
i.column.WriteUnqualified(builder)
|
i.column.WriteUnqualified(builder)
|
||||||
builder.WriteString(" + 1")
|
builder.WriteString(" + 1")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Change = (*incrementColumnChange)(nil)
|
var _ Change = (*incrementColumnChange)(nil)
|
||||||
@@ -242,7 +249,7 @@ func (c *changeToStatement) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write implements [Change].
|
// Write implements [Change].
|
||||||
func (c *changeToStatement) Write(builder *StatementBuilder) {
|
func (c *changeToStatement) Write(builder *StatementBuilder) error {
|
||||||
_, ok := c.column.(Columns)
|
_, ok := c.column.(Columns)
|
||||||
if ok {
|
if ok {
|
||||||
builder.WriteRune('(')
|
builder.WriteRune('(')
|
||||||
@@ -254,6 +261,7 @@ func (c *changeToStatement) Write(builder *StatementBuilder) {
|
|||||||
builder.WriteString(" = (")
|
builder.WriteString(" = (")
|
||||||
c.stmt(builder)
|
c.stmt(builder)
|
||||||
builder.WriteString(")")
|
builder.WriteString(")")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Change = (*changeToStatement)(nil)
|
var _ Change = (*changeToStatement)(nil)
|
||||||
@@ -322,11 +330,12 @@ func (c *cteChange) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write implements [CTEChange].
|
// Write implements [CTEChange].
|
||||||
func (c *cteChange) Write(builder *StatementBuilder) {
|
func (c *cteChange) Write(builder *StatementBuilder) error {
|
||||||
if c.change == nil {
|
if c.change == nil {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
c.change(c.name).Write(builder)
|
c.change(c.name).Write(builder)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteCTE implements [CTEChange].
|
// WriteCTE implements [CTEChange].
|
||||||
|
|||||||
@@ -64,7 +64,8 @@ func TestChangeWrite(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
var builder StatementBuilder
|
var builder StatementBuilder
|
||||||
test.change.Write(&builder)
|
err := test.change.Write(&builder)
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, test.want.stmt, builder.String())
|
assert.Equal(t, test.want.stmt, builder.String())
|
||||||
require.Len(t, builder.Args(), len(test.want.args))
|
require.Len(t, builder.Args(), len(test.want.args))
|
||||||
for i, arg := range test.want.args {
|
for i, arg := range test.want.args {
|
||||||
|
|||||||
@@ -157,9 +157,8 @@ func IsNull(column Column) *isNull {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsRestrictingColumn implements [Condition].
|
// IsRestrictingColumn implements [Condition].
|
||||||
// It returns false because it cannot be used for restricting a column.
|
|
||||||
func (i isNull) IsRestrictingColumn(col Column) bool {
|
func (i isNull) IsRestrictingColumn(col Column) bool {
|
||||||
return false
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Condition = (*isNull)(nil)
|
var _ Condition = (*isNull)(nil)
|
||||||
@@ -194,9 +193,8 @@ func IsNotNull(column Column) *isNotNull {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsRestrictingColumn implements [Condition].
|
// IsRestrictingColumn implements [Condition].
|
||||||
// It returns false because it cannot be used for restricting a column.
|
|
||||||
func (i isNotNull) IsRestrictingColumn(col Column) bool {
|
func (i isNotNull) IsRestrictingColumn(col Column) bool {
|
||||||
return false
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Condition = (*isNotNull)(nil)
|
var _ Condition = (*isNotNull)(nil)
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ func wrapPgError(err *pgconn.PgError) error {
|
|||||||
// 23502: not_null_violation - A value violates a NOT NULL constraint.
|
// 23502: not_null_violation - A value violates a NOT NULL constraint.
|
||||||
case "23502":
|
case "23502":
|
||||||
return database.NewNotNullError(err.TableName, err.ConstraintName, err)
|
return database.NewNotNullError(err.TableName, err.ConstraintName, err)
|
||||||
|
// 22P02: integrity violation - A value is being inserted into a enum that is not valid
|
||||||
|
case "22P02":
|
||||||
|
return database.NewCheckError(err.TableName, err.ConstraintName, err)
|
||||||
default:
|
default:
|
||||||
return database.NewUnknownError(err)
|
return database.NewUnknownError(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package migration
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed 009_settings_table/up.sql
|
||||||
|
up009SettingsTable string
|
||||||
|
//go:embed 009_settings_table/down.sql
|
||||||
|
down009SettingsTable string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registerSQLMigration(9, up009SettingsTable, down009SettingsTable)
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
DROP TABLE IF EXISTS zitadel.settings;
|
||||||
|
DROP TYPE IF EXISTS zitadel.settings_type;
|
||||||
|
DROP TYPE IF EXISTS zitadel.settings_state;
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
CREATE TYPE zitadel.settings_type AS ENUM (
|
||||||
|
'login',
|
||||||
|
'branding',
|
||||||
|
'password_complexity',
|
||||||
|
'password_expiry',
|
||||||
|
'domain',
|
||||||
|
'lockout',
|
||||||
|
'security',
|
||||||
|
'organization',
|
||||||
|
'notification',
|
||||||
|
'legal_and_support'
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TYPE zitadel.settings_state AS ENUM (
|
||||||
|
'active',
|
||||||
|
'preview'
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE zitadel.settings (
|
||||||
|
instance_id TEXT NOT NULL
|
||||||
|
, organization_id TEXT
|
||||||
|
, id TEXT NOT NULL DEFAULT gen_random_uuid()
|
||||||
|
, type zitadel.settings_type NOT NULL
|
||||||
|
, state zitadel.settings_state NOT NULL
|
||||||
|
, settings JSONB -- the storage does not really care about what is configured so we store it as json
|
||||||
|
|
||||||
|
, created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
, updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
|
||||||
|
, PRIMARY KEY (instance_id, id, type, state)
|
||||||
|
, FOREIGN KEY (instance_id) REFERENCES zitadel.instances(id) ON DELETE CASCADE
|
||||||
|
, FOREIGN KEY (instance_id, organization_id) REFERENCES zitadel.organizations(instance_id, id) ON DELETE CASCADE
|
||||||
|
|
||||||
|
, UNIQUE (instance_id, organization_id, type, state)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX idx_settings_unique_type ON zitadel.settings (instance_id, organization_id, type, state) NULLS NOT DISTINCT;
|
||||||
|
|
||||||
|
CREATE TRIGGER trigger_set_updated_at
|
||||||
|
BEFORE UPDATE ON zitadel.settings
|
||||||
|
FOR EACH ROW
|
||||||
|
WHEN (NEW.updated_at IS NULL)
|
||||||
|
EXECUTE FUNCTION zitadel.set_updated_at();
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION zitadel.jsonb_array_remove(
|
||||||
|
source JSONB
|
||||||
|
, path TEXT[]
|
||||||
|
, value anyelement
|
||||||
|
|
||||||
|
, outt out jsonb
|
||||||
|
)
|
||||||
|
language 'plpgsql'
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
outt = jsonb_set(source, path,
|
||||||
|
(CASE WHEN (SELECT source ?& path) then
|
||||||
|
coalesce(
|
||||||
|
(SELECT jsonb_agg(v)
|
||||||
|
FROM jsonb_array_elements(source #>path) AS elem(v)
|
||||||
|
WHERE v::text <> value::text),
|
||||||
|
jsonb_build_array())
|
||||||
|
ELSe
|
||||||
|
jsonb_build_array()
|
||||||
|
END)::jsonb, TRUE);
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION zitadel.jsonb_array_append(
|
||||||
|
source jsonb
|
||||||
|
, path text[]
|
||||||
|
, value anyelement
|
||||||
|
|
||||||
|
, outt out jsonb
|
||||||
|
)
|
||||||
|
language 'plpgsql'
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
outt := jsonb_insert(
|
||||||
|
source,
|
||||||
|
(CASE WHEN (SELECT source ?& path) then
|
||||||
|
array_append(path, '-1')
|
||||||
|
ELSE
|
||||||
|
path
|
||||||
|
END)::text[],
|
||||||
|
(CASE WHEN (select source ?& path) then
|
||||||
|
value::TEXT::jsonb
|
||||||
|
ELSE
|
||||||
|
jsonb_build_array(value)
|
||||||
|
END),
|
||||||
|
TRUE
|
||||||
|
);
|
||||||
|
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,97 @@
|
|||||||
|
<svg width="100%" height="100%" viewBox="0 0 295 80" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g id="zitadel-logo-light" transform="matrix(1,0,0,1,-20.9181,-89.5699)">
|
||||||
|
<rect x="20.918" y="89.57" width="294.943" height="79.632" style="fill:none;"></rect>
|
||||||
|
<g transform="matrix(2.73883,0,0,1.55076,-35267,23.6366)">
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,0.0429306,0.282967,12622.8,-105.843)">
|
||||||
|
<path d="M1493.5,1056.38L1493.5,1037L1496.5,1037L1496.5,1061.62L1426.02,1020.38L1496.5,979.392L1496.5,1004L1493.5,1004L1493.5,984.608L1431.98,1020.39L1493.5,1056.38Z" style="fill:white;"></path>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g transform="matrix(-0.0429306,-0.282967,0.160219,-0.0758207,12884.5,137.392)">
|
||||||
|
<path d="M212.517,110L200.392,110L190,92L179.608,110L167.483,110L190,71L212.517,110Z" style="fill:url(#_Linear1);"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,0.0758207,-0.0429306,0.282967,12878.9,10.8747)">
|
||||||
|
<path d="M212.517,110L200.392,110L190,92L179.608,110L167.483,110L190,71L212.517,110Z" style="fill:url(#_Linear2);"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(-0.117289,0.207146,-0.117289,-0.207146,12943.8,65.7)">
|
||||||
|
<path d="M212.517,110L200.392,110L190,92L179.608,110L167.483,110L190,71L212.517,110Z" style="fill:url(#_Linear3);"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(-0.160219,-0.0758207,0.0429306,-0.282967,12917.4,132.195)">
|
||||||
|
<path d="M139.622,117L149,142L130.244,142L139.622,117Z" style="fill:url(#_Linear4);"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(-0.117289,0.207146,0.117289,0.207146,12897.8,5.87512)">
|
||||||
|
<path d="M139.622,117L149,142L130.244,142L139.622,117Z" style="fill:url(#_Linear5);"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(-0.0429306,-0.282967,-0.160219,0.0758207,12936.8,97.6441)">
|
||||||
|
<path d="M139.622,117L149,142L130.244,142L139.622,117Z" style="fill:url(#_Linear6);"></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,0.0429306,0.282967,12622.6,-105.767)">
|
||||||
|
<circle cx="1496" cy="1004" r="7" style="fill:white;"></circle>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,0.0429306,0.282967,12624.1,-96.4295)">
|
||||||
|
<circle cx="1496" cy="1004" r="7" style="fill:white;"></circle>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,0.0429306,0.282967,12625,-90.2042)">
|
||||||
|
<circle cx="1496" cy="1004" r="7" style="fill:white;"></circle>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,0.0429306,0.282967,12612.8,-96.1272)">
|
||||||
|
<circle cx="1496" cy="1004" r="7" style="fill:white;"></circle>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,0.0429306,0.282967,12621.7,-111.993)">
|
||||||
|
<circle cx="1496" cy="1004" r="7" style="fill:white;"></circle>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,0.0375643,0.247596,12637.2,-10.9628)">
|
||||||
|
<path d="M1499.26,757.787C1499.26,757.787 1497.37,756.489 1497,755.2C1496.71,754.182 1496.57,750.662 1496.54,750C1496.41,747.303 1499.21,745.644 1499.21,745.644L1490.01,745.835C1490.01,745.835 1493.15,745.713 1493.46,750C1493.51,750.661 1493.23,753.476 1493,755.2C1492.91,756.447 1491.2,757.668 1491.2,757.668L1499.26,757.787Z" style="fill:white;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,0.0375643,0.247596,12639.5,4.60032)">
|
||||||
|
<path d="M1495,760L1495,744" style="fill:none;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,0.0375643,0.247596,12639.5,4.60032)">
|
||||||
|
<path d="M1498.27,757.077C1498.27,757.077 1496.71,756.46 1496.65,754.8C1496.65,753.658 1496.64,753.281 1496.65,752.016C1496.62,751.334 1496.59,750.608 1496.65,749.949C1496.78,746.836 1498.5,746.156 1498.5,746.156L1491.46,745.931C1491.46,745.931 1493.37,746.719 1493.65,749.83C1493.71,750.489 1493.69,751.528 1493.65,752.209C1493.64,753.331 1493.64,753.413 1493.65,754.518C1493.68,756.334 1492.58,756.827 1492.58,756.827L1498.27,757.077Z" style="fill:white;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,0.0375643,0.247596,12627.7,-0.733956)">
|
||||||
|
<path d="M1496.17,759.473L1555.54,720.014" style="fill:none;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,0.0375643,0.247596,12627.7,-0.733956)">
|
||||||
|
<path d="M1500.86,762.056C1500.86,762.056 1499.86,760.4 1503.09,757.456C1504.91,755.797 1507.33,754.151 1509.98,752.255C1514.82,748.79 1520.68,744.94 1526.52,741.049C1531.45,737.766 1536.38,734.479 1540.82,731.68C1544.52,729.349 1547.85,727.296 1550.54,725.8C1551.07,725.506 1551.6,725.329 1552.05,725.029C1554.73,723.257 1556.85,724.968 1556.85,724.968L1552.23,716.282C1552.23,716.282 1551.99,719.454 1550,720.997C1549.57,721.333 1549.15,721.741 1548.67,722.12C1546.2,724.053 1542.99,726.344 1539.39,728.867C1535.06,731.898 1530.13,735.166 1525.19,738.438C1519.35,742.314 1513.52,746.234 1508.49,749.329C1505.74,751.023 1503.28,752.577 1501.13,753.598C1497.99,755.086 1495.28,753.617 1495.28,753.617L1500.86,762.056Z" style="fill:white;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,-0.0375643,-0.247596,12684.9,376.33)">
|
||||||
|
<path d="M1496.17,759.473L1555.54,720.014" style="fill:none;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.160219,-0.0758207,-0.0375643,-0.247596,12684.9,376.33)">
|
||||||
|
<path d="M1496.1,754.362C1496.1,754.362 1497.2,755.607 1501.13,753.598C1503.25,752.509 1505.74,751.023 1508.49,749.329C1513.52,746.234 1519.35,742.314 1525.19,738.438C1530.13,735.166 1534.94,731.832 1539.27,728.802C1542.87,726.279 1549.36,722.059 1549.81,721.75C1552.75,719.73 1552.18,718.196 1552.18,718.196L1555.28,724.152C1555.28,724.152 1553.77,722.905 1551.37,724.681C1550.93,725.006 1544.52,729.349 1540.82,731.68C1536.38,734.479 1531.45,737.766 1526.52,741.049C1520.68,744.94 1514.82,748.79 1509.98,752.255C1507.33,754.151 1504.89,755.771 1503.09,757.456C1499.47,760.841 1501.26,763.283 1501.26,763.283L1496.1,754.362Z" style="fill:white;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.156811,0,0,0.230771,12477,-400.567)">
|
||||||
|
<g transform="matrix(94.7456,0,0,94.7456,2811.73,2063)">
|
||||||
|
<path d="M0.449,-0.7L0.177,-0.7C0.185,-0.682 0.197,-0.654 0.2,-0.648C0.205,-0.639 0.216,-0.628 0.239,-0.628L0.32,-0.628C0.332,-0.628 0.336,-0.62 0.334,-0.611L0.128,-0L0.389,-0C0.412,-0 0.422,-0.01 0.427,-0.02L0.45,-0.071L0.255,-0.071C0.245,-0.071 0.239,-0.078 0.242,-0.09L0.449,-0.7Z" style="fill:white;fill-rule:nonzero;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(94.7456,0,0,94.7456,2882.79,2063)">
|
||||||
|
<path d="M0.214,-0.7L0.214,-0.015C0.215,-0.01 0.218,-0 0.235,-0L0.286,-0L0.286,-0.672C0.286,-0.684 0.278,-0.7 0.257,-0.7L0.214,-0.7Z" style="fill:white;fill-rule:nonzero;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(94.7456,0,0,94.7456,2944.37,2063)">
|
||||||
|
<path d="M0.441,-0.7L0.155,-0.7C0.143,-0.7 0.133,-0.69 0.133,-0.678L0.133,-0.629L0.234,-0.629L0.234,-0.015C0.234,-0.01 0.237,-0 0.254,-0L0.305,-0L0.305,-0.612C0.306,-0.621 0.313,-0.629 0.323,-0.629L0.379,-0.629C0.402,-0.629 0.413,-0.639 0.417,-0.648L0.441,-0.7Z" style="fill:white;fill-rule:nonzero;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(94.7456,0,0,94.7456,3010.69,2063)">
|
||||||
|
<path d="M0.422,-0L0.343,-0L0.28,-0.482L0.217,-0L0.138,-0L0.244,-0.7L0.283,-0.7C0.313,-0.7 0.318,-0.681 0.321,-0.662L0.422,-0Z" style="fill:white;fill-rule:nonzero;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(94.7456,0,0,94.7456,3077.96,2063)">
|
||||||
|
<path d="M0.186,-0.7L0.186,-0L0.325,-0C0.374,-0 0.413,-0.039 0.414,-0.088L0.414,-0.612C0.413,-0.661 0.374,-0.7 0.325,-0.7L0.186,-0.7ZM0.343,-0.108C0.343,-0.081 0.325,-0.071 0.305,-0.071L0.258,-0.071L0.258,-0.628L0.305,-0.628C0.325,-0.628 0.343,-0.618 0.343,-0.592L0.343,-0.108Z" style="fill:white;fill-rule:nonzero;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(94.7456,0,0,94.7456,3149.02,2063)">
|
||||||
|
<path d="M0.291,-0.071L0.291,-0.314C0.291,-0.323 0.299,-0.331 0.308,-0.331L0.338,-0.331C0.361,-0.331 0.371,-0.341 0.376,-0.35C0.379,-0.356 0.391,-0.385 0.399,-0.403L0.291,-0.403L0.291,-0.611C0.291,-0.621 0.298,-0.628 0.308,-0.628L0.366,-0.628C0.389,-0.628 0.4,-0.639 0.404,-0.648L0.428,-0.7L0.241,-0.7C0.229,-0.7 0.22,-0.691 0.219,-0.68L0.219,-0L0.379,-0C0.402,-0 0.413,-0.01 0.418,-0.019C0.421,-0.025 0.433,-0.053 0.441,-0.071L0.291,-0.071Z" style="fill:white;fill-rule:nonzero;"></path>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(94.7456,0,0,94.7456,3220.08,2063)">
|
||||||
|
<path d="M0.283,-0.071L0.283,-0.678C0.283,-0.69 0.273,-0.699 0.261,-0.7L0.211,-0.7L0.211,-0L0.383,-0C0.406,-0 0.417,-0.01 0.422,-0.019C0.425,-0.025 0.437,-0.053 0.445,-0.071L0.283,-0.071Z" style="fill:white;fill-rule:nonzero;"></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-41.5984,155.247,-155.247,-41.5984,201.516,76.8392)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"></stop><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"></stop></linearGradient>
|
||||||
|
<linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(155.247,-41.5984,41.5984,155.247,110.08,195.509)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"></stop><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"></stop></linearGradient>
|
||||||
|
<linearGradient id="_Linear3" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-113.649,-113.649,113.649,-113.649,258.31,215.618)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"></stop><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"></stop></linearGradient>
|
||||||
|
<linearGradient id="_Linear4" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-155.247,41.5984,-41.5984,-155.247,220.914,144.546)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"></stop><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"></stop></linearGradient>
|
||||||
|
<linearGradient id="_Linear5" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-113.649,113.649,113.649,113.649,206.837,124.661)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"></stop><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"></stop></linearGradient>
|
||||||
|
<linearGradient id="_Linear6" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-41.5984,-155.247,-155.247,41.5984,152.054,262.8)"><stop offset="0" style="stop-color:rgb(255,143,0);stop-opacity:1"></stop><stop offset="1" style="stop-color:rgb(254,0,255);stop-opacity:1"></stop></linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 11 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,225 @@
|
|||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ database.Change = (*jsonChanges)(nil)
|
||||||
|
|
||||||
|
type JsonUpdate interface {
|
||||||
|
writeUpdate(builder *database.StatementBuilder, changes jsonChanges, i int) error
|
||||||
|
getPathValue() ([]string, string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FieldChange struct {
|
||||||
|
path []string
|
||||||
|
value any
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFieldChange(path []string, value any) JsonUpdate {
|
||||||
|
return &FieldChange{
|
||||||
|
path: path,
|
||||||
|
value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FieldChange) getPathValue() ([]string, string, error) {
|
||||||
|
path, v := c.path, c.value
|
||||||
|
|
||||||
|
value, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return path, string(value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FieldChange) writeUpdate(builder *database.StatementBuilder, changes jsonChanges, i int) error {
|
||||||
|
path, value, err := c.getPathValue()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("jsonb_set_lax(")
|
||||||
|
if i < 0 {
|
||||||
|
changes.column.WriteQualified(builder)
|
||||||
|
} else {
|
||||||
|
err := changes.changes[i].writeUpdate(builder, changes, i-1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteArg(path)
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteArg(value)
|
||||||
|
builder.WriteString(", true, 'delete_key')")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArrayChange struct {
|
||||||
|
path []string
|
||||||
|
value any
|
||||||
|
remove bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewArrayChange(path []string, value any, remove bool) JsonUpdate {
|
||||||
|
return &ArrayChange{
|
||||||
|
path: path,
|
||||||
|
value: value,
|
||||||
|
remove: remove,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ArrayChange) getPathValue() ([]string, string, error) {
|
||||||
|
path, v := c.path, c.value
|
||||||
|
|
||||||
|
value, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return path, string(value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ArrayChange) writeUpdate(builder *database.StatementBuilder, changes jsonChanges, i int) error {
|
||||||
|
if c.remove {
|
||||||
|
return c.removeFromArray(builder, changes, i)
|
||||||
|
}
|
||||||
|
return c.addToArray(builder, changes, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ArrayChange) addToArray(builder *database.StatementBuilder, changes jsonChanges, i int) error {
|
||||||
|
path, value, err := c.getPathValue()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("zitadel.jsonb_array_append(")
|
||||||
|
|
||||||
|
// to mitigate the possibility of having duplicate values in the array
|
||||||
|
builder.WriteString("zitadel.jsonb_array_remove(")
|
||||||
|
if i < 0 {
|
||||||
|
changes.column.WriteQualified(builder)
|
||||||
|
} else {
|
||||||
|
err := changes.changes[i].writeUpdate(builder, changes, i-1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// zitadel.jsonb_array_remove
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteArg(path)
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteArg(value)
|
||||||
|
builder.WriteString("::TEXT)")
|
||||||
|
|
||||||
|
// zitadel.jsonb_array_append
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteArg(path)
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteArg(value)
|
||||||
|
if len(value) > 2 && value[0] == '"' && value[len(value)-1] == '"' {
|
||||||
|
builder.WriteString("::TEXT")
|
||||||
|
} else {
|
||||||
|
builder.WriteString("::NUMERIC")
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(")")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ArrayChange) removeFromArray(builder *database.StatementBuilder, changes jsonChanges, i int) error {
|
||||||
|
path, value, err := c.getPathValue()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("zitadel.jsonb_array_remove(")
|
||||||
|
if i < 0 {
|
||||||
|
changes.column.WriteQualified(builder)
|
||||||
|
} else {
|
||||||
|
err := changes.changes[i].writeUpdate(builder, changes, i-1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteArg(path)
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteArg(value)
|
||||||
|
builder.WriteString("::TEXT")
|
||||||
|
builder.WriteString(")")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ JsonUpdate = (*ArrayChange)(nil)
|
||||||
|
|
||||||
|
type jsonChanges struct {
|
||||||
|
column database.Column
|
||||||
|
changes []JsonUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ database.Change = (*jsonChanges)(nil)
|
||||||
|
|
||||||
|
func NewJsonChanges(col database.Column, changes ...JsonUpdate) database.Change {
|
||||||
|
return &jsonChanges{
|
||||||
|
column: col,
|
||||||
|
changes: changes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *jsonChanges) Matches(x any) bool {
|
||||||
|
toMatch, ok := x.(*jsonChanges)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.column.Equals(toMatch.column) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.changes) != len(toMatch.changes) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c1 := range c.changes {
|
||||||
|
found := false
|
||||||
|
for _, c2 := range toMatch.changes {
|
||||||
|
if reflect.DeepEqual(c1, c2) {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *jsonChanges) String() string {
|
||||||
|
return "database.json.jsonChange"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c jsonChanges) Write(builder *database.StatementBuilder) error {
|
||||||
|
c.column.WriteUnqualified(builder)
|
||||||
|
builder.WriteString(" = ")
|
||||||
|
|
||||||
|
if c.changes == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.changes[len(c.changes)-1].writeUpdate(builder, c, len(c.changes)-2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c jsonChanges) IsOnColumn(col database.Column) bool {
|
||||||
|
return c.column.Equals(col)
|
||||||
|
}
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFieldChange(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
name string
|
||||||
|
change database.Change
|
||||||
|
output string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "single json update",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change := NewFieldChange([]string{"path"}, "value")
|
||||||
|
changes := NewJsonChanges(col, change)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = jsonb_set_lax(table.column, $1, $2, true, 'delete_key')`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "two json update",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change1 := NewFieldChange([]string{"path"}, "value")
|
||||||
|
change2 := NewFieldChange([]string{"path"}, "value")
|
||||||
|
changes := NewJsonChanges(col, change1, change2)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = jsonb_set_lax(jsonb_set_lax(table.column, $1, $2, true, 'delete_key'), $3, $4, true, 'delete_key')`,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
builder := database.StatementBuilder{}
|
||||||
|
err := test.change.Write(&builder)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, test.output, builder.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArrayChange(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
name string
|
||||||
|
change database.Change
|
||||||
|
output string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "one json array add",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change := NewArrayChange([]string{"path"}, "value", false)
|
||||||
|
changes := NewJsonChanges(col, change)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = zitadel.jsonb_array_append(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "two json array add",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change1 := NewArrayChange([]string{"path)"}, "value", false)
|
||||||
|
change2 := NewArrayChange([]string{"path"}, "value", false)
|
||||||
|
changes := NewJsonChanges(col, change1, change2)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = zitadel.jsonb_array_append(zitadel.jsonb_array_remove(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT), $7, $8::TEXT)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one json array remove",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change := NewArrayChange([]string{"path"}, "value", true)
|
||||||
|
changes := NewJsonChanges(col, change)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = zitadel.jsonb_array_remove(table.column, $1, $2::TEXT)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "two json array remove",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change1 := NewArrayChange([]string{"path)"}, "value", true)
|
||||||
|
change2 := NewArrayChange([]string{"path"}, "value", true)
|
||||||
|
changes := NewJsonChanges(col, change1, change2)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = zitadel.jsonb_array_remove(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT)`,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
builder := database.StatementBuilder{}
|
||||||
|
err := test.change.Write(&builder)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, test.output, builder.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArrayMixedChange(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
name string
|
||||||
|
change database.Change
|
||||||
|
output string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "one json array add, one json remove",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change1 := NewArrayChange([]string{"path)"}, "value", false)
|
||||||
|
change2 := NewArrayChange([]string{"path"}, "value", true)
|
||||||
|
changes := NewJsonChanges(col, change1, change2)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = zitadel.jsonb_array_remove(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one json array remove, one json array add",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change1 := NewArrayChange([]string{"path)"}, "value", true)
|
||||||
|
change2 := NewArrayChange([]string{"path"}, "value", false)
|
||||||
|
changes := NewJsonChanges(col, change1, change2)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = zitadel.jsonb_array_append(zitadel.jsonb_array_remove(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one json array add, one json array remove, one array add",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change1 := NewArrayChange([]string{"path)"}, "value", false)
|
||||||
|
change2 := NewArrayChange([]string{"path"}, "value", true)
|
||||||
|
change3 := NewArrayChange([]string{"path)"}, "value", false)
|
||||||
|
changes := NewJsonChanges(col, change1, change2, change3)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = zitadel.jsonb_array_append(zitadel.jsonb_array_remove(zitadel.jsonb_array_remove(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT), $7, $8::TEXT), $9, $10::TEXT)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one json array remove, one json array add, one array remove",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change1 := NewArrayChange([]string{"path)"}, "value", true)
|
||||||
|
change2 := NewArrayChange([]string{"path"}, "value", false)
|
||||||
|
change3 := NewArrayChange([]string{"path)"}, "value", true)
|
||||||
|
changes := NewJsonChanges(col, change1, change2, change3)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = zitadel.jsonb_array_remove(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT), $7, $8::TEXT)`,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
builder := database.StatementBuilder{}
|
||||||
|
err := test.change.Write(&builder)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, test.output, builder.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
func TestFieldArrayMixedChange(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
name string
|
||||||
|
change database.Change
|
||||||
|
output string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "one field change, one json array add, one json remove",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change1 := NewFieldChange([]string{"path"}, "value")
|
||||||
|
change2 := NewArrayChange([]string{"path)"}, "value", false)
|
||||||
|
change3 := NewArrayChange([]string{"path"}, "value", true)
|
||||||
|
changes := NewJsonChanges(col, change1, change2, change3)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = zitadel.jsonb_array_remove(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(jsonb_set_lax(table.column, $1, $2, true, 'delete_key'), $3, $4::TEXT), $5, $6::TEXT), $7, $8::TEXT)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one json array add, one field change, one json remove",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change1 := NewArrayChange([]string{"path)"}, "value", false)
|
||||||
|
change2 := NewFieldChange([]string{"path"}, "value")
|
||||||
|
change3 := NewArrayChange([]string{"path"}, "value", true)
|
||||||
|
changes := NewJsonChanges(col, change1, change2, change3)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = zitadel.jsonb_array_remove(jsonb_set_lax(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6, true, 'delete_key'), $7, $8::TEXT)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one json remove, one json array, add one field change",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change1 := NewArrayChange([]string{"path"}, "value", true)
|
||||||
|
change2 := NewArrayChange([]string{"path)"}, "value", false)
|
||||||
|
change3 := NewFieldChange([]string{"path"}, "value")
|
||||||
|
changes := NewJsonChanges(col, change1, change2, change3)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = jsonb_set_lax(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT), $7, $8, true, 'delete_key')`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one json remove, one field change, one json array add",
|
||||||
|
change: func() database.Change {
|
||||||
|
col := database.NewColumn("table", "column")
|
||||||
|
change1 := NewArrayChange([]string{"path"}, "value", true)
|
||||||
|
change2 := NewFieldChange([]string{"path"}, "value")
|
||||||
|
change3 := NewArrayChange([]string{"path)"}, "value", false)
|
||||||
|
changes := NewJsonChanges(col, change1, change2, change3)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
}(),
|
||||||
|
output: `column = zitadel.jsonb_array_append(zitadel.jsonb_array_remove(jsonb_set_lax(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4, true, 'delete_key'), $5, $6::TEXT), $7, $8::TEXT)`,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
builder := database.StatementBuilder{}
|
||||||
|
err := test.change.Write(&builder)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, test.output, builder.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -92,7 +92,10 @@ func (i *idProvider) Update(ctx context.Context, client database.QueryExecutor,
|
|||||||
i.InstanceIDCondition(instanceID),
|
i.InstanceIDCondition(instanceID),
|
||||||
i.OrgIDCondition(orgID),
|
i.OrgIDCondition(orgID),
|
||||||
}
|
}
|
||||||
database.Changes(changes).Write(&builder)
|
err := database.Changes(changes).Write(&builder)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
writeCondition(&builder, database.And(conditions...))
|
writeCondition(&builder, database.And(conditions...))
|
||||||
|
|
||||||
stmt := builder.String()
|
stmt := builder.String()
|
||||||
|
|||||||
@@ -110,7 +110,10 @@ func (i instance) Update(ctx context.Context, client database.QueryExecutor, id
|
|||||||
|
|
||||||
var builder database.StatementBuilder
|
var builder database.StatementBuilder
|
||||||
builder.WriteString(`UPDATE zitadel.instances SET `)
|
builder.WriteString(`UPDATE zitadel.instances SET `)
|
||||||
database.Changes(changes).Write(&builder)
|
err := database.Changes(changes).Write(&builder)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
idCondition := i.IDCondition(id)
|
idCondition := i.IDCondition(id)
|
||||||
writeCondition(&builder, idCondition)
|
writeCondition(&builder, idCondition)
|
||||||
|
|
||||||
@@ -149,15 +152,19 @@ func (i instance) SetUpdatedAt(time time.Time) database.Change {
|
|||||||
func (i instance) SetIAMProject(id string) database.Change {
|
func (i instance) SetIAMProject(id string) database.Change {
|
||||||
return database.NewChange(i.IAMProjectIDColumn(), id)
|
return database.NewChange(i.IAMProjectIDColumn(), id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i instance) SetDefaultOrg(id string) database.Change {
|
func (i instance) SetDefaultOrg(id string) database.Change {
|
||||||
return database.NewChange(i.DefaultOrgIDColumn(), id)
|
return database.NewChange(i.DefaultOrgIDColumn(), id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i instance) SetDefaultLanguage(lang language.Tag) database.Change {
|
func (i instance) SetDefaultLanguage(lang language.Tag) database.Change {
|
||||||
return database.NewChange(i.DefaultLanguageColumn(), lang.String())
|
return database.NewChange(i.DefaultLanguageColumn(), lang.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i instance) SetConsoleClientID(id string) database.Change {
|
func (i instance) SetConsoleClientID(id string) database.Change {
|
||||||
return database.NewChange(i.ConsoleClientIDColumn(), id)
|
return database.NewChange(i.ConsoleClientIDColumn(), id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i instance) SetConsoleAppID(id string) database.Change {
|
func (i instance) SetConsoleAppID(id string) database.Change {
|
||||||
return database.NewChange(i.ConsoleAppIDColumn(), id)
|
return database.NewChange(i.ConsoleAppIDColumn(), id)
|
||||||
}
|
}
|
||||||
@@ -182,7 +189,6 @@ func (i instance) NameCondition(op database.TextOperation, name string) database
|
|||||||
|
|
||||||
// ExistsDomain creates a correlated [database.Exists] condition on instance_domains.
|
// ExistsDomain creates a correlated [database.Exists] condition on instance_domains.
|
||||||
// Use this filter to make sure the Instance returned contains a specific domain.
|
// Use this filter to make sure the Instance returned contains a specific domain.
|
||||||
// of the instance in the aggregated result.
|
|
||||||
// Example usage:
|
// Example usage:
|
||||||
//
|
//
|
||||||
// domainRepo := instanceRepo.Domains(true) // ensure domains are loaded/aggregated
|
// domainRepo := instanceRepo.Domains(true) // ensure domains are loaded/aggregated
|
||||||
|
|||||||
@@ -93,7 +93,10 @@ func (i instanceDomain) Update(ctx context.Context, client database.QueryExecuto
|
|||||||
|
|
||||||
var builder database.StatementBuilder
|
var builder database.StatementBuilder
|
||||||
builder.WriteString(`UPDATE zitadel.instance_domains SET `)
|
builder.WriteString(`UPDATE zitadel.instance_domains SET `)
|
||||||
database.Changes(changes).Write(&builder)
|
err := database.Changes(changes).Write(&builder)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
writeCondition(&builder, condition)
|
writeCondition(&builder, condition)
|
||||||
|
|
||||||
|
|||||||
@@ -721,7 +721,8 @@ func TestInstanceDomainChanges(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
var builder database.StatementBuilder
|
var builder database.StatementBuilder
|
||||||
test.change.Write(&builder)
|
err := test.change.Write(&builder)
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, test.expected, builder.String())
|
assert.Equal(t, test.expected, builder.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,10 @@ func (o org) Update(ctx context.Context, client database.QueryExecutor, conditio
|
|||||||
|
|
||||||
var builder database.StatementBuilder
|
var builder database.StatementBuilder
|
||||||
builder.WriteString(`UPDATE zitadel.organizations SET `)
|
builder.WriteString(`UPDATE zitadel.organizations SET `)
|
||||||
database.Changes(changes).Write(&builder)
|
err := database.Changes(changes).Write(&builder)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
writeCondition(&builder, condition)
|
writeCondition(&builder, condition)
|
||||||
|
|
||||||
stmt := builder.String()
|
stmt := builder.String()
|
||||||
|
|||||||
@@ -107,7 +107,10 @@ func (o orgDomain) Update(ctx context.Context, client database.QueryExecutor, co
|
|||||||
|
|
||||||
var builder database.StatementBuilder
|
var builder database.StatementBuilder
|
||||||
builder.WriteString(`UPDATE zitadel.org_domains SET `)
|
builder.WriteString(`UPDATE zitadel.org_domains SET `)
|
||||||
database.Changes(changes).Write(&builder)
|
err := database.Changes(changes).Write(&builder)
|
||||||
|
if 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()...)
|
||||||
|
|||||||
@@ -928,7 +928,8 @@ func TestOrganizationDomainChanges(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
var builder database.StatementBuilder
|
var builder database.StatementBuilder
|
||||||
test.change.Write(&builder)
|
err := test.change.Write(&builder)
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, test.expected, builder.String())
|
assert.Equal(t, test.expected, builder.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,10 @@ func (p projectRole) Update(ctx context.Context, client database.QueryExecutor,
|
|||||||
changes = append(changes, database.NewChange(p.UpdatedAtColumn(), database.NullInstruction))
|
changes = append(changes, database.NewChange(p.UpdatedAtColumn(), database.NullInstruction))
|
||||||
}
|
}
|
||||||
builder := database.NewStatementBuilder(`UPDATE zitadel.project_roles SET `)
|
builder := database.NewStatementBuilder(`UPDATE zitadel.project_roles SET `)
|
||||||
database.Changes(changes).Write(builder)
|
err := database.Changes(changes).Write(builder)
|
||||||
|
if 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()...)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ package systemdefaults
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ var (
|
|||||||
ProjectRoleRelationalProjection *handler.Handler
|
ProjectRoleRelationalProjection *handler.Handler
|
||||||
OrganizationMetadataRelationalProjection *handler.Handler
|
OrganizationMetadataRelationalProjection *handler.Handler
|
||||||
ProjectGrantRelationalProjection *handler.Handler
|
ProjectGrantRelationalProjection *handler.Handler
|
||||||
|
SettingsRelationalProjection *handler.Handler
|
||||||
|
|
||||||
ProjectGrantFields *handler.FieldHandler
|
ProjectGrantFields *handler.FieldHandler
|
||||||
OrgDomainVerifiedFields *handler.FieldHandler
|
OrgDomainVerifiedFields *handler.FieldHandler
|
||||||
@@ -219,6 +220,7 @@ func Create(ctx context.Context, sqlClient *database.DB, es handler.EventStore,
|
|||||||
OrganizationRelationalProjection = newOrgRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["organizations_relational"]))
|
OrganizationRelationalProjection = newOrgRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["organizations_relational"]))
|
||||||
InstanceDomainRelationalProjection = newInstanceDomainRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["instance_domains_relational"]))
|
InstanceDomainRelationalProjection = newInstanceDomainRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["instance_domains_relational"]))
|
||||||
OrganizationDomainRelationalProjection = newOrgDomainRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["organization_domains_relational"]))
|
OrganizationDomainRelationalProjection = newOrgDomainRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["organization_domains_relational"]))
|
||||||
|
SettingsRelationalProjection = newSettingsRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["settings_relational"]))
|
||||||
IDPTemplateRelationalProjection = newIDPTemplateRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_templates_relational"]))
|
IDPTemplateRelationalProjection = newIDPTemplateRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_templates_relational"]))
|
||||||
ProjectRelationalProjection = newProjectRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["projects_relational"]))
|
ProjectRelationalProjection = newProjectRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["projects_relational"]))
|
||||||
ProjectRoleRelationalProjection = newProjectRoleRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["project_roles_relational"]))
|
ProjectRoleRelationalProjection = newProjectRoleRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["project_roles_relational"]))
|
||||||
@@ -413,6 +415,7 @@ func newProjectionsList() {
|
|||||||
OrganizationRelationalProjection,
|
OrganizationRelationalProjection,
|
||||||
InstanceDomainRelationalProjection,
|
InstanceDomainRelationalProjection,
|
||||||
OrganizationDomainRelationalProjection,
|
OrganizationDomainRelationalProjection,
|
||||||
|
SettingsRelationalProjection,
|
||||||
IDPTemplateRelationalProjection,
|
IDPTemplateRelationalProjection,
|
||||||
ProjectRelationalProjection,
|
ProjectRelationalProjection,
|
||||||
ProjectRoleRelationalProjection,
|
ProjectRoleRelationalProjection,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user