mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:17:32 +00:00
feat: restrict languages (#6931)
* feat: return 404 or 409 if org reg disallowed * fix: system limit permissions * feat: add iam limits api * feat: disallow public org registrations on default instance * add integration test * test: integration * fix test * docs: describe public org registrations * avoid updating docs deps * fix system limits integration test * silence integration tests * fix linting * ignore strange linter complaints * review * improve reset properties naming * redefine the api * use restrictions aggregate * test query * simplify and test projection * test commands * fix unit tests * move integration test * support restrictions on default instance * also test GetRestrictions * self review * lint * abstract away resource owner * fix tests * configure supported languages * fix allowed languages * fix tests * default lang must not be restricted * preferred language must be allowed * change preferred languages * check languages everywhere * lint * test command side * lint * add integration test * add integration test * restrict supported ui locales * lint * lint * cleanup * lint * allow undefined preferred language * fix integration tests * update main * fix env var * ignore linter * ignore linter * improve integration test config * reduce cognitive complexity * compile * check for duplicates * remove useless restriction checks * review * revert restriction renaming * fix language restrictions * lint * generate * allow custom texts for supported langs for now * fix tests * cleanup * cleanup * cleanup * lint * unsupported preferred lang is allowed * fix integration test * finish reverting to old property name * finish reverting to old property name * load languages * refactor(i18n): centralize translators and fs * lint * amplify no validations on preferred languages * fix integration test * lint * fix resetting allowed languages * test unchanged restrictions
This commit is contained in:
22
internal/command/command_test.go
Normal file
22
internal/command/command_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/i18n"
|
||||
)
|
||||
|
||||
var (
|
||||
SupportedLanguages = []language.Tag{language.English, language.German}
|
||||
OnlyAllowedLanguages = []language.Tag{language.English}
|
||||
AllowedLanguage = language.English
|
||||
DisallowedLanguage = language.German
|
||||
UnsupportedLanguage = language.Spanish
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
i18n.SupportLanguages(SupportedLanguages...)
|
||||
m.Run()
|
||||
}
|
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/i18n"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
"github.com/zitadel/zitadel/internal/notification/channels/smtp"
|
||||
"github.com/zitadel/zitadel/internal/repository/feature"
|
||||
@@ -107,18 +108,22 @@ type InstanceSetup struct {
|
||||
EmailTemplate []byte
|
||||
MessageTexts []*domain.CustomMessageText
|
||||
SMTPConfiguration *smtp.Config
|
||||
OIDCSettings *struct {
|
||||
AccessTokenLifetime time.Duration
|
||||
IdTokenLifetime time.Duration
|
||||
RefreshTokenIdleExpiration time.Duration
|
||||
RefreshTokenExpiration time.Duration
|
||||
}
|
||||
Quotas *struct {
|
||||
Items []*SetQuota
|
||||
}
|
||||
Features map[domain.Feature]any
|
||||
Limits *SetLimits
|
||||
Restrictions *SetRestrictions
|
||||
OIDCSettings *OIDCSettings
|
||||
Quotas *SetQuotas
|
||||
Features map[domain.Feature]any
|
||||
Limits *SetLimits
|
||||
Restrictions *SetRestrictions
|
||||
}
|
||||
|
||||
type OIDCSettings struct {
|
||||
AccessTokenLifetime time.Duration
|
||||
IdTokenLifetime time.Duration
|
||||
RefreshTokenIdleExpiration time.Duration
|
||||
RefreshTokenExpiration time.Duration
|
||||
}
|
||||
|
||||
type SetQuotas struct {
|
||||
Items []*SetQuota
|
||||
}
|
||||
|
||||
type SecretGenerators struct {
|
||||
@@ -289,183 +294,32 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
|
||||
|
||||
prepareAddDefaultEmailTemplate(instanceAgg, setup.EmailTemplate),
|
||||
}
|
||||
|
||||
if setup.Quotas != nil {
|
||||
for _, q := range setup.Quotas.Items {
|
||||
quotaId, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", "", nil, nil, err
|
||||
}
|
||||
validations = append(validations, c.SetQuotaCommand(quota.NewAggregate(quotaId, instanceID), nil, true, q))
|
||||
}
|
||||
if err := setupQuotas(c, &validations, setup.Quotas, instanceID); err != nil {
|
||||
return "", "", nil, nil, err
|
||||
}
|
||||
|
||||
for _, msg := range setup.MessageTexts {
|
||||
validations = append(validations, prepareSetInstanceCustomMessageTexts(instanceAgg, msg))
|
||||
}
|
||||
|
||||
console := &addOIDCApp{
|
||||
AddApp: AddApp{
|
||||
Aggregate: *projectAgg,
|
||||
ID: setup.zitadel.consoleAppID,
|
||||
Name: consoleAppName,
|
||||
},
|
||||
Version: domain.OIDCVersionV1,
|
||||
RedirectUris: []string{},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeUserAgent,
|
||||
AuthMethodType: domain.OIDCAuthMethodTypeNone,
|
||||
PostLogoutRedirectUris: []string{},
|
||||
DevMode: !c.externalSecure,
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
AccessTokenRoleAssertion: false,
|
||||
IDTokenRoleAssertion: false,
|
||||
IDTokenUserinfoAssertion: false,
|
||||
ClockSkew: 0,
|
||||
}
|
||||
|
||||
setupMessageTexts(&validations, setup.MessageTexts, instanceAgg)
|
||||
validations = append(validations,
|
||||
AddOrgCommand(ctx, orgAgg, setup.Org.Name),
|
||||
c.prepareSetDefaultOrg(instanceAgg, orgAgg.ID),
|
||||
)
|
||||
|
||||
var pat *PersonalAccessToken
|
||||
var machineKey *MachineKey
|
||||
// only a human or a machine user should be created as owner
|
||||
if setup.Org.Machine != nil && setup.Org.Machine.Machine != nil && !setup.Org.Machine.Machine.IsZero() {
|
||||
validations = append(validations,
|
||||
AddMachineCommand(userAgg, setup.Org.Machine.Machine),
|
||||
)
|
||||
if setup.Org.Machine.Pat != nil {
|
||||
pat = NewPersonalAccessToken(orgID, userID, setup.Org.Machine.Pat.ExpirationDate, setup.Org.Machine.Pat.Scopes, domain.UserTypeMachine)
|
||||
pat.TokenID, err = c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", "", nil, nil, err
|
||||
}
|
||||
validations = append(validations, prepareAddPersonalAccessToken(pat, c.keyAlgorithm))
|
||||
}
|
||||
if setup.Org.Machine.MachineKey != nil {
|
||||
machineKey = NewMachineKey(orgID, userID, setup.Org.Machine.MachineKey.ExpirationDate, setup.Org.Machine.MachineKey.Type)
|
||||
machineKey.KeyID, err = c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", "", nil, nil, err
|
||||
}
|
||||
validations = append(validations, prepareAddUserMachineKey(machineKey, c.machineKeySize))
|
||||
}
|
||||
} else if setup.Org.Human != nil {
|
||||
setup.Org.Human.ID = userID
|
||||
validations = append(validations,
|
||||
c.AddHumanCommand(setup.Org.Human, orgID, c.userPasswordHasher, c.userEncryption, true),
|
||||
)
|
||||
}
|
||||
|
||||
validations = append(validations,
|
||||
c.AddOrgMemberCommand(orgAgg, userID, domain.RoleOrgOwner),
|
||||
c.AddInstanceMemberCommand(instanceAgg, userID, domain.RoleIAMOwner),
|
||||
AddProjectCommand(projectAgg, zitadelProjectName, userID, false, false, false, domain.PrivateLabelingSettingUnspecified),
|
||||
SetIAMProject(instanceAgg, projectAgg.ID),
|
||||
|
||||
c.AddAPIAppCommand(
|
||||
&addAPIApp{
|
||||
AddApp: AddApp{
|
||||
Aggregate: *projectAgg,
|
||||
ID: setup.zitadel.mgmtAppID,
|
||||
Name: mgmtAppName,
|
||||
},
|
||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||
},
|
||||
nil,
|
||||
),
|
||||
|
||||
c.AddAPIAppCommand(
|
||||
&addAPIApp{
|
||||
AddApp: AddApp{
|
||||
Aggregate: *projectAgg,
|
||||
ID: setup.zitadel.adminAppID,
|
||||
Name: adminAppName,
|
||||
},
|
||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||
},
|
||||
nil,
|
||||
),
|
||||
|
||||
c.AddAPIAppCommand(
|
||||
&addAPIApp{
|
||||
AddApp: AddApp{
|
||||
Aggregate: *projectAgg,
|
||||
ID: setup.zitadel.authAppID,
|
||||
Name: authAppName,
|
||||
},
|
||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||
},
|
||||
nil,
|
||||
),
|
||||
|
||||
c.AddOIDCAppCommand(console, nil),
|
||||
SetIAMConsoleID(instanceAgg, &console.ClientID, &setup.zitadel.consoleAppID),
|
||||
)
|
||||
|
||||
addGeneratedDomain, err := c.addGeneratedInstanceDomain(ctx, instanceAgg, setup.InstanceName)
|
||||
pat, machineKey, err := setupAdmin(c, &validations, setup.Org.Machine, setup.Org.Human, orgID, userID, userAgg)
|
||||
if err != nil {
|
||||
return "", "", nil, nil, err
|
||||
}
|
||||
validations = append(validations, addGeneratedDomain...)
|
||||
if setup.CustomDomain != "" {
|
||||
validations = append(validations,
|
||||
c.addInstanceDomain(instanceAgg, setup.CustomDomain, false),
|
||||
setPrimaryInstanceDomain(instanceAgg, setup.CustomDomain),
|
||||
)
|
||||
setupMinimalInterfaces(c, &validations, instanceAgg, projectAgg, orgAgg, userID, setup.zitadel)
|
||||
if err := setupGeneratedDomain(ctx, c, &validations, instanceAgg, setup.InstanceName); err != nil {
|
||||
return "", "", nil, nil, err
|
||||
}
|
||||
|
||||
if setup.SMTPConfiguration != nil {
|
||||
validations = append(validations,
|
||||
c.prepareAddSMTPConfig(
|
||||
instanceAgg,
|
||||
setup.SMTPConfiguration.From,
|
||||
setup.SMTPConfiguration.FromName,
|
||||
setup.SMTPConfiguration.ReplyToAddress,
|
||||
setup.SMTPConfiguration.SMTP.Host,
|
||||
setup.SMTPConfiguration.SMTP.User,
|
||||
[]byte(setup.SMTPConfiguration.SMTP.Password),
|
||||
setup.SMTPConfiguration.Tls,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if setup.OIDCSettings != nil {
|
||||
validations = append(validations,
|
||||
c.prepareAddOIDCSettings(
|
||||
instanceAgg,
|
||||
setup.OIDCSettings.AccessTokenLifetime,
|
||||
setup.OIDCSettings.IdTokenLifetime,
|
||||
setup.OIDCSettings.RefreshTokenIdleExpiration,
|
||||
setup.OIDCSettings.RefreshTokenExpiration,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
for f, value := range setup.Features {
|
||||
switch v := value.(type) {
|
||||
case bool:
|
||||
wm, err := NewInstanceFeatureWriteModel[feature.Boolean](instanceID, f)
|
||||
if err != nil {
|
||||
return "", "", nil, nil, err
|
||||
}
|
||||
validations = append(validations, prepareSetFeature(wm, feature.Boolean{Boolean: v}, c.idGenerator))
|
||||
default:
|
||||
return "", "", nil, nil, errors.ThrowInvalidArgument(nil, "INST-GE4tg", "Errors.Feature.TypeNotSupported")
|
||||
}
|
||||
}
|
||||
|
||||
if setup.Limits != nil {
|
||||
validations = append(validations, c.SetLimitsCommand(limitsAgg, &limitsWriteModel{}, setup.Limits))
|
||||
}
|
||||
|
||||
if setup.Restrictions != nil {
|
||||
validations = append(validations, c.SetRestrictionsCommand(restrictionsAgg, &restrictionsWriteModel{}, setup.Restrictions))
|
||||
setupCustomDomain(c, &validations, instanceAgg, setup.CustomDomain)
|
||||
setupSMTPSettings(c, &validations, setup.SMTPConfiguration, instanceAgg)
|
||||
setupOIDCSettings(c, &validations, setup.OIDCSettings, instanceAgg)
|
||||
if err := setupFeatures(c, &validations, setup.Features, instanceID); err != nil {
|
||||
return "", "", nil, nil, err
|
||||
}
|
||||
setupLimits(c, &validations, limitsAgg, setup.Limits)
|
||||
setupRestrictions(c, &validations, restrictionsAgg, setup.Restrictions)
|
||||
|
||||
//nolint:staticcheck
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validations...)
|
||||
if err != nil {
|
||||
return "", "", nil, nil, err
|
||||
@@ -488,6 +342,205 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
|
||||
}, nil
|
||||
}
|
||||
|
||||
func setupLimits(commands *Commands, validations *[]preparation.Validation, limitsAgg *limits.Aggregate, setLimits *SetLimits) {
|
||||
if setLimits != nil {
|
||||
*validations = append(*validations, commands.SetLimitsCommand(limitsAgg, &limitsWriteModel{}, setLimits))
|
||||
}
|
||||
}
|
||||
|
||||
func setupRestrictions(commands *Commands, validations *[]preparation.Validation, restrictionsAgg *restrictions.Aggregate, setRestrictions *SetRestrictions) {
|
||||
if setRestrictions != nil {
|
||||
*validations = append(*validations, commands.SetRestrictionsCommand(restrictionsAgg, &restrictionsWriteModel{}, setRestrictions))
|
||||
}
|
||||
}
|
||||
|
||||
func setupQuotas(commands *Commands, validations *[]preparation.Validation, setQuotas *SetQuotas, instanceID string) error {
|
||||
if setQuotas == nil {
|
||||
return nil
|
||||
}
|
||||
for _, q := range setQuotas.Items {
|
||||
quotaId, err := commands.idGenerator.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*validations = append(*validations, commands.SetQuotaCommand(quota.NewAggregate(quotaId, instanceID), nil, true, q))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupFeatures(commands *Commands, validations *[]preparation.Validation, enableFeatures map[domain.Feature]any, instanceID string) error {
|
||||
for f, value := range enableFeatures {
|
||||
switch v := value.(type) {
|
||||
case bool:
|
||||
wm, err := NewInstanceFeatureWriteModel[feature.Boolean](instanceID, f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*validations = append(*validations, prepareSetFeature(wm, feature.Boolean{Boolean: v}, commands.idGenerator))
|
||||
default:
|
||||
return errors.ThrowInvalidArgument(nil, "INST-GE4tg", "Errors.Feature.TypeNotSupported")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupOIDCSettings(commands *Commands, validations *[]preparation.Validation, oidcSettings *OIDCSettings, instanceAgg *instance.Aggregate) {
|
||||
if oidcSettings == nil {
|
||||
return
|
||||
}
|
||||
*validations = append(*validations,
|
||||
commands.prepareAddOIDCSettings(
|
||||
instanceAgg,
|
||||
oidcSettings.AccessTokenLifetime,
|
||||
oidcSettings.IdTokenLifetime,
|
||||
oidcSettings.RefreshTokenIdleExpiration,
|
||||
oidcSettings.RefreshTokenExpiration,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func setupSMTPSettings(commands *Commands, validations *[]preparation.Validation, smtpConfig *smtp.Config, instanceAgg *instance.Aggregate) {
|
||||
if smtpConfig == nil {
|
||||
return
|
||||
}
|
||||
*validations = append(*validations,
|
||||
commands.prepareAddSMTPConfig(
|
||||
instanceAgg,
|
||||
smtpConfig.From,
|
||||
smtpConfig.FromName,
|
||||
smtpConfig.ReplyToAddress,
|
||||
smtpConfig.SMTP.Host,
|
||||
smtpConfig.SMTP.User,
|
||||
[]byte(smtpConfig.SMTP.Password),
|
||||
smtpConfig.Tls,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func setupCustomDomain(commands *Commands, validations *[]preparation.Validation, instanceAgg *instance.Aggregate, customDomain string) {
|
||||
if customDomain == "" {
|
||||
return
|
||||
}
|
||||
*validations = append(*validations,
|
||||
commands.addInstanceDomain(instanceAgg, customDomain, false),
|
||||
setPrimaryInstanceDomain(instanceAgg, customDomain),
|
||||
)
|
||||
}
|
||||
|
||||
func setupGeneratedDomain(ctx context.Context, commands *Commands, validations *[]preparation.Validation, instanceAgg *instance.Aggregate, instanceName string) error {
|
||||
addGeneratedDomain, err := commands.addGeneratedInstanceDomain(ctx, instanceAgg, instanceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*validations = append(*validations, addGeneratedDomain...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupMinimalInterfaces(commands *Commands, validations *[]preparation.Validation, instanceAgg *instance.Aggregate, projectAgg *project.Aggregate, orgAgg *org.Aggregate, userID string, ids ZitadelConfig) {
|
||||
cnsl := &addOIDCApp{
|
||||
AddApp: AddApp{
|
||||
Aggregate: *projectAgg,
|
||||
ID: ids.consoleAppID,
|
||||
Name: consoleAppName,
|
||||
},
|
||||
Version: domain.OIDCVersionV1,
|
||||
RedirectUris: []string{},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeUserAgent,
|
||||
AuthMethodType: domain.OIDCAuthMethodTypeNone,
|
||||
PostLogoutRedirectUris: []string{},
|
||||
DevMode: !commands.externalSecure,
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
AccessTokenRoleAssertion: false,
|
||||
IDTokenRoleAssertion: false,
|
||||
IDTokenUserinfoAssertion: false,
|
||||
ClockSkew: 0,
|
||||
}
|
||||
*validations = append(*validations,
|
||||
commands.AddOrgMemberCommand(orgAgg, userID, domain.RoleOrgOwner),
|
||||
commands.AddInstanceMemberCommand(instanceAgg, userID, domain.RoleIAMOwner),
|
||||
AddProjectCommand(projectAgg, zitadelProjectName, userID, false, false, false, domain.PrivateLabelingSettingUnspecified),
|
||||
SetIAMProject(instanceAgg, projectAgg.ID),
|
||||
|
||||
commands.AddAPIAppCommand(
|
||||
&addAPIApp{
|
||||
AddApp: AddApp{
|
||||
Aggregate: *projectAgg,
|
||||
ID: ids.mgmtAppID,
|
||||
Name: mgmtAppName,
|
||||
},
|
||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||
},
|
||||
nil,
|
||||
),
|
||||
|
||||
commands.AddAPIAppCommand(
|
||||
&addAPIApp{
|
||||
AddApp: AddApp{
|
||||
Aggregate: *projectAgg,
|
||||
ID: ids.adminAppID,
|
||||
Name: adminAppName,
|
||||
},
|
||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||
},
|
||||
nil,
|
||||
),
|
||||
|
||||
commands.AddAPIAppCommand(
|
||||
&addAPIApp{
|
||||
AddApp: AddApp{
|
||||
Aggregate: *projectAgg,
|
||||
ID: ids.authAppID,
|
||||
Name: authAppName,
|
||||
},
|
||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||
},
|
||||
nil,
|
||||
),
|
||||
|
||||
commands.AddOIDCAppCommand(cnsl, nil),
|
||||
SetIAMConsoleID(instanceAgg, &cnsl.ClientID, &ids.consoleAppID),
|
||||
)
|
||||
}
|
||||
|
||||
func setupAdmin(commands *Commands, validations *[]preparation.Validation, machine *AddMachine, human *AddHuman, orgID, userID string, userAgg *user.Aggregate) (pat *PersonalAccessToken, machineKey *MachineKey, err error) {
|
||||
// only a human or a machine user should be created as owner
|
||||
if machine != nil && machine.Machine != nil && !machine.Machine.IsZero() {
|
||||
*validations = append(*validations,
|
||||
AddMachineCommand(userAgg, machine.Machine),
|
||||
)
|
||||
if machine.Pat != nil {
|
||||
pat = NewPersonalAccessToken(orgID, userID, machine.Pat.ExpirationDate, machine.Pat.Scopes, domain.UserTypeMachine)
|
||||
pat.TokenID, err = commands.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
*validations = append(*validations, prepareAddPersonalAccessToken(pat, commands.keyAlgorithm))
|
||||
}
|
||||
if machine.MachineKey != nil {
|
||||
machineKey = NewMachineKey(orgID, userID, machine.MachineKey.ExpirationDate, machine.MachineKey.Type)
|
||||
machineKey.KeyID, err = commands.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
*validations = append(*validations, prepareAddUserMachineKey(machineKey, commands.machineKeySize))
|
||||
}
|
||||
} else if human != nil {
|
||||
human.ID = userID
|
||||
*validations = append(*validations,
|
||||
commands.AddHumanCommand(human, orgID, commands.userPasswordHasher, commands.userEncryption, true),
|
||||
)
|
||||
}
|
||||
return pat, machineKey, nil
|
||||
}
|
||||
|
||||
func setupMessageTexts(validations *[]preparation.Validation, setupMessageTexts []*domain.CustomMessageText, instanceAgg *instance.Aggregate) {
|
||||
for _, msg := range setupMessageTexts {
|
||||
*validations = append(*validations, prepareSetInstanceCustomMessageTexts(instanceAgg, msg))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) UpdateInstance(ctx context.Context, name string) (*domain.ObjectDetails, error) {
|
||||
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
|
||||
validation := c.prepareUpdateInstance(instanceAgg, name)
|
||||
@@ -656,16 +709,27 @@ func (c *Commands) prepareUpdateInstance(a *instance.Aggregate, name string) pre
|
||||
|
||||
func (c *Commands) prepareSetDefaultLanguage(a *instance.Aggregate, defaultLanguage language.Tag) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if defaultLanguage == language.Und {
|
||||
return nil, errors.ThrowInvalidArgument(nil, "INST-28nlD", "Errors.Invalid.Argument")
|
||||
if err := domain.LanguageIsDefined(defaultLanguage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := domain.LanguagesAreSupported(i18n.SupportedLanguages(), defaultLanguage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel, err := getInstanceWriteModel(ctx, filter)
|
||||
if writeModel.DefaultLanguage == defaultLanguage {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "INST-DS3rq", "Errors.Instance.NotChanged")
|
||||
}
|
||||
instanceID := authz.GetInstance(ctx).InstanceID()
|
||||
restrictionsWM, err := c.getRestrictionsWriteModel(ctx, instanceID, instanceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if writeModel.DefaultLanguage == defaultLanguage {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "INST-DS3rq", "Errors.Instance.NotChanged")
|
||||
if err := domain.LanguageIsAllowed(false, restrictionsWM.allowedLanguages, defaultLanguage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []eventstore.Command{instance.NewDefaultLanguageSetEvent(ctx, &a.Aggregate, defaultLanguage)}, nil
|
||||
}, nil
|
||||
|
@@ -2,16 +2,18 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/i18n"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
// SetCustomInstanceLoginText only validates if the language is supported, not if it is allowed.
|
||||
// This enables setting texts before allowing a language
|
||||
func (c *Commands) SetCustomInstanceLoginText(ctx context.Context, loginText *domain.CustomLoginText) (*domain.ObjectDetails, error) {
|
||||
iamAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
|
||||
events, existingMailText, err := c.setCustomInstanceLoginText(ctx, &iamAgg.Aggregate, loginText)
|
||||
@@ -53,8 +55,8 @@ func (c *Commands) RemoveCustomInstanceLoginTexts(ctx context.Context, lang lang
|
||||
}
|
||||
|
||||
func (c *Commands) setCustomInstanceLoginText(ctx context.Context, instanceAgg *eventstore.Aggregate, text *domain.CustomLoginText) ([]eventstore.Command, *InstanceCustomLoginTextReadModel, error) {
|
||||
if !text.IsValid() {
|
||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "Instance-kd9fs", "Errors.CustomText.Invalid")
|
||||
if err := text.IsValid(i18n.SupportedLanguages()); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
existingLoginText, err := c.defaultLoginTextWriteModelByID(ctx, text.Language)
|
||||
if err != nil {
|
||||
|
@@ -33,20 +33,54 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "invalid custom login text, error",
|
||||
name: "empty custom login text, success",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
expectPush(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
|
||||
config: &domain.CustomLoginText{
|
||||
Language: AllowedLanguage,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "INSTANCE",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "undefined language, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
|
||||
config: &domain.CustomLoginText{},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unsupported language, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
|
||||
config: &domain.CustomLoginText{
|
||||
Language: UnsupportedLanguage,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom login text set all fields, ok",
|
||||
fields: fields{
|
||||
|
@@ -9,9 +9,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/i18n"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
// SetDefaultMessageText only validates if the language is supported, not if it is allowed.
|
||||
// This enables setting texts before allowing a language
|
||||
func (c *Commands) SetDefaultMessageText(ctx context.Context, instanceID string, messageText *domain.CustomMessageText) (*domain.ObjectDetails, error) {
|
||||
instanceAgg := instance.NewAggregate(instanceID)
|
||||
events, existingMessageText, err := c.setDefaultMessageText(ctx, &instanceAgg.Aggregate, messageText)
|
||||
@@ -30,8 +33,8 @@ func (c *Commands) SetDefaultMessageText(ctx context.Context, instanceID string,
|
||||
}
|
||||
|
||||
func (c *Commands) setDefaultMessageText(ctx context.Context, instanceAgg *eventstore.Aggregate, msg *domain.CustomMessageText) ([]eventstore.Command, *InstanceCustomMessageTextWriteModel, error) {
|
||||
if !msg.IsValid() {
|
||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-kd9fs", "Errors.CustomMessageText.Invalid")
|
||||
if err := msg.IsValid(i18n.SupportedLanguages()); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
existingMessageText, err := c.defaultCustomMessageTextWriteModelByID(ctx, msg.MessageTextType, msg.Language)
|
||||
@@ -129,8 +132,8 @@ func prepareSetInstanceCustomMessageTexts(
|
||||
msg *domain.CustomMessageText,
|
||||
) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if !msg.IsValid() {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-kd9fs", "Errors.CustomMessageText.Invalid")
|
||||
if err := msg.IsValid(i18n.SupportedLanguages()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
existing, err := existingInstanceCustomMessageText(ctx, filter, msg.MessageTextType, msg.Language)
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
zitadel_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
@@ -34,19 +34,68 @@ func TestCommandSide_SetDefaultMessageText(t *testing.T) {
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "invalid custom text, error",
|
||||
name: "empty message type, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
|
||||
config: &domain.CustomMessageText{
|
||||
Language: AllowedLanguage,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty custom message text, success",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
expectPush(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
instanceID: "INSTANCE",
|
||||
config: &domain.CustomMessageText{},
|
||||
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
|
||||
config: &domain.CustomMessageText{
|
||||
MessageTextType: "Some type", // TODO: check the type!
|
||||
Language: AllowedLanguage,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "INSTANCE",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "undefined language, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
|
||||
config: &domain.CustomMessageText{},
|
||||
},
|
||||
res: res{
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unsupported language, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
|
||||
config: &domain.CustomMessageText{
|
||||
Language: UnsupportedLanguage,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@@ -212,7 +212,7 @@ func (m *mockInstance) ConsoleApplicationID() string {
|
||||
}
|
||||
|
||||
func (m *mockInstance) DefaultLanguage() language.Tag {
|
||||
return language.English
|
||||
return AllowedLanguage
|
||||
}
|
||||
|
||||
func (m *mockInstance) DefaultOrganisationID() string {
|
||||
|
@@ -8,9 +8,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/i18n"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
// SetOrgLoginText only validates if the language is supported, not if it is allowed.
|
||||
// This enables setting texts before allowing a language
|
||||
func (c *Commands) SetOrgLoginText(ctx context.Context, resourceOwner string, loginText *domain.CustomLoginText) (*domain.ObjectDetails, error) {
|
||||
if resourceOwner == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-m29rF", "Errors.ResourceOwnerMissing")
|
||||
@@ -32,10 +35,9 @@ func (c *Commands) SetOrgLoginText(ctx context.Context, resourceOwner string, lo
|
||||
}
|
||||
|
||||
func (c *Commands) setOrgLoginText(ctx context.Context, orgAgg *eventstore.Aggregate, loginText *domain.CustomLoginText) ([]eventstore.Command, *OrgCustomLoginTextReadModel, error) {
|
||||
if !loginText.IsValid() {
|
||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "ORG-PPo2w", "Errors.CustomText.Invalid")
|
||||
if err := loginText.IsValid(i18n.SupportedLanguages()); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
existingLoginText, err := c.orgCustomLoginTextWriteModelByID(ctx, orgAgg.ID, loginText.Language)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@@ -40,22 +41,44 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
config: &domain.CustomLoginText{},
|
||||
ctx: authz.WithInstanceID(context.Background(), "org1"),
|
||||
config: &domain.CustomLoginText{
|
||||
Language: AllowedLanguage,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid custom login text, error",
|
||||
name: "empty custom login text, success",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
expectPush(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
ctx: authz.WithInstanceID(context.Background(), "org1"),
|
||||
resourceOwner: "org1",
|
||||
config: &domain.CustomLoginText{
|
||||
Language: AllowedLanguage,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "undefined language, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "org1"),
|
||||
resourceOwner: "org1",
|
||||
config: &domain.CustomLoginText{},
|
||||
},
|
||||
@@ -63,6 +86,22 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unsupported language, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "org1"),
|
||||
resourceOwner: "org1",
|
||||
config: &domain.CustomLoginText{
|
||||
Language: UnsupportedLanguage,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom login text set all fields, ok",
|
||||
fields: fields{
|
||||
|
@@ -8,9 +8,12 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/i18n"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
// SetOrgMessageText only validates if the language is supported, not if it is allowed.
|
||||
// This enables setting texts before allowing a language
|
||||
func (c *Commands) SetOrgMessageText(ctx context.Context, resourceOwner string, messageText *domain.CustomMessageText) (*domain.ObjectDetails, error) {
|
||||
if resourceOwner == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-2biiR", "Errors.ResourceOwnerMissing")
|
||||
@@ -32,10 +35,9 @@ func (c *Commands) SetOrgMessageText(ctx context.Context, resourceOwner string,
|
||||
}
|
||||
|
||||
func (c *Commands) setOrgMessageText(ctx context.Context, orgAgg *eventstore.Aggregate, message *domain.CustomMessageText) ([]eventstore.Command, *OrgCustomMessageTextReadModel, error) {
|
||||
if !message.IsValid() {
|
||||
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "ORG-2jfsf", "Errors.CustomText.Invalid")
|
||||
if err := message.IsValid(i18n.SupportedLanguages()); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
existingMessageText, err := c.orgCustomMessageTextWriteModelByID(ctx, orgAgg.ID, message.MessageTextType, message.Language)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
zitadel_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
@@ -35,32 +35,83 @@ func TestCommandSide_SetCustomMessageText(t *testing.T) {
|
||||
{
|
||||
name: "no resource owner, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
config: &domain.CustomMessageText{},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid custom text, error",
|
||||
name: "empty message type, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
config: &domain.CustomMessageText{
|
||||
Language: AllowedLanguage,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty custom message text, success",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
expectPush(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
config: &domain.CustomMessageText{
|
||||
MessageTextType: "Some type", // TODO: check the type!
|
||||
Language: AllowedLanguage,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "undefined language, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
config: &domain.CustomMessageText{},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unsupported language, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
config: &domain.CustomMessageText{
|
||||
Language: UnsupportedLanguage,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -345,7 +396,7 @@ func TestCommandSide_RemoveCustomMessageText(t *testing.T) {
|
||||
lang: language.English,
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -361,7 +412,7 @@ func TestCommandSide_RemoveCustomMessageText(t *testing.T) {
|
||||
lang: language.English,
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -377,7 +428,7 @@ func TestCommandSide_RemoveCustomMessageText(t *testing.T) {
|
||||
mailTextType: "Template",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -471,6 +522,43 @@ func TestCommandSide_RemoveCustomMessageText(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove unsupported language ok, especially because we never validated whether a language is supported in previous ZITADEL versions",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewCustomTextSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1").Aggregate,
|
||||
"Template",
|
||||
domain.MessageGreeting,
|
||||
"Greeting",
|
||||
UnsupportedLanguage,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
org.NewCustomTextTemplateRemovedEvent(context.Background(),
|
||||
&org.NewAggregate("org1").Aggregate,
|
||||
"Template",
|
||||
UnsupportedLanguage,
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
mailTextType: "Template",
|
||||
lang: UnsupportedLanguage,
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@@ -141,7 +141,7 @@ func TestCommandSide_AddOrg(t *testing.T) {
|
||||
"lastname1",
|
||||
"nickname1",
|
||||
"displayname1",
|
||||
language.German,
|
||||
language.English,
|
||||
domain.GenderMale,
|
||||
"email1",
|
||||
true,
|
||||
@@ -185,7 +185,7 @@ func TestCommandSide_AddOrg(t *testing.T) {
|
||||
"lastname1",
|
||||
"nickname1",
|
||||
"displayname1",
|
||||
language.German,
|
||||
language.English,
|
||||
domain.GenderMale,
|
||||
"email1",
|
||||
true,
|
||||
@@ -253,7 +253,7 @@ func TestCommandSide_AddOrg(t *testing.T) {
|
||||
"lastname1",
|
||||
"nickname1",
|
||||
"displayname1",
|
||||
language.German,
|
||||
language.English,
|
||||
domain.GenderMale,
|
||||
"email1",
|
||||
true,
|
||||
@@ -321,7 +321,7 @@ func TestCommandSide_AddOrg(t *testing.T) {
|
||||
"lastname1",
|
||||
"nickname1",
|
||||
"displayname1",
|
||||
language.German,
|
||||
language.English,
|
||||
domain.GenderMale,
|
||||
"email1",
|
||||
true,
|
||||
@@ -392,7 +392,7 @@ func TestCommandSide_AddOrg(t *testing.T) {
|
||||
"lastname1",
|
||||
"nickname1",
|
||||
"displayname1",
|
||||
language.German,
|
||||
language.English,
|
||||
domain.GenderMale,
|
||||
"email1",
|
||||
true,
|
||||
@@ -1181,7 +1181,7 @@ func TestCommandSide_RemoveOrg(t *testing.T) {
|
||||
"lastname1",
|
||||
"nickname1",
|
||||
"displayname1",
|
||||
language.German,
|
||||
language.English,
|
||||
domain.GenderMale,
|
||||
"email1",
|
||||
false,
|
||||
|
@@ -3,16 +3,38 @@ package command
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
zitadel_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/i18n"
|
||||
"github.com/zitadel/zitadel/internal/repository/restrictions"
|
||||
)
|
||||
|
||||
type SetRestrictions struct {
|
||||
DisallowPublicOrgRegistration *bool
|
||||
AllowedLanguages []language.Tag
|
||||
}
|
||||
|
||||
func (s *SetRestrictions) Validate(defaultLanguage language.Tag) error {
|
||||
if s == nil || (s.DisallowPublicOrgRegistration == nil && s.AllowedLanguages == nil) {
|
||||
return zitadel_errors.ThrowInvalidArgument(nil, "COMMAND-oASwj", "Errors.Restrictions.NoneSpecified")
|
||||
}
|
||||
if s.AllowedLanguages != nil {
|
||||
if err := domain.LanguagesHaveDuplicates(s.AllowedLanguages); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := domain.LanguagesAreSupported(i18n.SupportedLanguages(), s.AllowedLanguages...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := domain.LanguageIsAllowed(false, s.AllowedLanguages, defaultLanguage); err != nil {
|
||||
return zitadel_errors.ThrowPreconditionFailedf(err, "COMMAND-L0m2u", "Errors.Restrictions.DefaultLanguageMustBeAllowed")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetRestrictions creates new restrictions or updates existing restrictions.
|
||||
@@ -60,10 +82,10 @@ func (c *Commands) getRestrictionsWriteModel(ctx context.Context, instanceId, re
|
||||
|
||||
func (c *Commands) SetRestrictionsCommand(a *restrictions.Aggregate, wm *restrictionsWriteModel, setRestrictions *SetRestrictions) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if setRestrictions == nil || setRestrictions.DisallowPublicOrgRegistration == nil {
|
||||
return nil, errors.ThrowInvalidArgument(nil, "COMMAND-oASwj", "Errors.Restrictions.NoneSpecified")
|
||||
}
|
||||
return func(ctx context.Context, _ preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
if err := setRestrictions.Validate(authz.GetInstance(ctx).DefaultLanguage()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes := wm.NewChanges(setRestrictions)
|
||||
if len(changes) == 0 {
|
||||
return nil, nil
|
||||
|
@@ -1,13 +1,17 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/restrictions"
|
||||
)
|
||||
|
||||
type restrictionsWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
disallowPublicOrgRegistrations bool
|
||||
disallowPublicOrgRegistration bool
|
||||
allowedLanguages []language.Tag
|
||||
}
|
||||
|
||||
// newRestrictionsWriteModel aggregateId is filled by reducing unit matching events
|
||||
@@ -34,8 +38,15 @@ func (wm *restrictionsWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
func (wm *restrictionsWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
wm.ChangeDate = event.CreatedAt()
|
||||
if e, ok := event.(*restrictions.SetEvent); ok && e.DisallowPublicOrgRegistrations != nil {
|
||||
wm.disallowPublicOrgRegistrations = *e.DisallowPublicOrgRegistrations
|
||||
e, ok := event.(*restrictions.SetEvent)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if e.DisallowPublicOrgRegistration != nil {
|
||||
wm.disallowPublicOrgRegistration = *e.DisallowPublicOrgRegistration
|
||||
}
|
||||
if e.AllowedLanguages != nil {
|
||||
wm.allowedLanguages = *e.AllowedLanguages
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
@@ -48,8 +59,11 @@ func (wm *restrictionsWriteModel) NewChanges(setRestrictions *SetRestrictions) (
|
||||
return nil
|
||||
}
|
||||
changes = make([]restrictions.RestrictionsChange, 0, 1)
|
||||
if setRestrictions.DisallowPublicOrgRegistration != nil && (wm.disallowPublicOrgRegistrations != *setRestrictions.DisallowPublicOrgRegistration) {
|
||||
changes = append(changes, restrictions.ChangePublicOrgRegistrations(*setRestrictions.DisallowPublicOrgRegistration))
|
||||
if setRestrictions.DisallowPublicOrgRegistration != nil && (wm.disallowPublicOrgRegistration != *setRestrictions.DisallowPublicOrgRegistration) {
|
||||
changes = append(changes, restrictions.ChangeDisallowPublicOrgRegistration(*setRestrictions.DisallowPublicOrgRegistration))
|
||||
}
|
||||
if setRestrictions.AllowedLanguages != nil && domain.LanguagesDiffer(wm.allowedLanguages, setRestrictions.AllowedLanguages) {
|
||||
changes = append(changes, restrictions.ChangeAllowedLanguages(setRestrictions.AllowedLanguages))
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -19,7 +20,6 @@ import (
|
||||
func TestSetRestrictions(t *testing.T) {
|
||||
type fields func(*testing.T) (*eventstore.Eventstore, id.Generator)
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
setRestrictions *SetRestrictions
|
||||
}
|
||||
type res struct {
|
||||
@@ -40,14 +40,14 @@ func TestSetRestrictions(t *testing.T) {
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
"INSTANCE",
|
||||
restrictions.NewSetEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
context.Background(),
|
||||
&restrictions.NewAggregate("restrictions1", "instance1", "instance1").Aggregate,
|
||||
&restrictions.NewAggregate("restrictions1", "INSTANCE", "INSTANCE").Aggregate,
|
||||
restrictions.SetEventType,
|
||||
),
|
||||
restrictions.ChangePublicOrgRegistrations(true),
|
||||
restrictions.ChangeDisallowPublicOrgRegistration(true),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -55,14 +55,13 @@ func TestSetRestrictions(t *testing.T) {
|
||||
id_mock.NewIDGeneratorExpectIDs(t, "restrictions1")
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
setRestrictions: &SetRestrictions{
|
||||
DisallowPublicOrgRegistration: gu.Ptr(true),
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "instance1",
|
||||
ResourceOwner: "INSTANCE",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -76,23 +75,23 @@ func TestSetRestrictions(t *testing.T) {
|
||||
restrictions.NewSetEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
context.Background(),
|
||||
&restrictions.NewAggregate("restrictions1", "instance1", "instance1").Aggregate,
|
||||
&restrictions.NewAggregate("restrictions1", "INSTANCE", "INSTANCE").Aggregate,
|
||||
restrictions.SetEventType,
|
||||
),
|
||||
restrictions.ChangePublicOrgRegistrations(true),
|
||||
restrictions.ChangeDisallowPublicOrgRegistration(true),
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
"INSTANCE",
|
||||
restrictions.NewSetEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
context.Background(),
|
||||
&restrictions.NewAggregate("restrictions1", "instance1", "instance1").Aggregate,
|
||||
&restrictions.NewAggregate("restrictions1", "INSTANCE", "INSTANCE").Aggregate,
|
||||
restrictions.SetEventType,
|
||||
),
|
||||
restrictions.ChangePublicOrgRegistrations(false),
|
||||
restrictions.ChangeDisallowPublicOrgRegistration(false),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -100,14 +99,13 @@ func TestSetRestrictions(t *testing.T) {
|
||||
nil
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
setRestrictions: &SetRestrictions{
|
||||
DisallowPublicOrgRegistration: gu.Ptr(false),
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "instance1",
|
||||
ResourceOwner: "INSTANCE",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -121,10 +119,10 @@ func TestSetRestrictions(t *testing.T) {
|
||||
restrictions.NewSetEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
context.Background(),
|
||||
&restrictions.NewAggregate("restrictions1", "instance1", "instance1").Aggregate,
|
||||
&restrictions.NewAggregate("restrictions1", "INSTANCE", "INSTANCE").Aggregate,
|
||||
restrictions.SetEventType,
|
||||
),
|
||||
restrictions.ChangePublicOrgRegistrations(true),
|
||||
restrictions.ChangeDisallowPublicOrgRegistration(true),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -132,14 +130,13 @@ func TestSetRestrictions(t *testing.T) {
|
||||
nil
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
setRestrictions: &SetRestrictions{
|
||||
DisallowPublicOrgRegistration: gu.Ptr(true),
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "instance1",
|
||||
ResourceOwner: "INSTANCE",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -152,29 +149,82 @@ func TestSetRestrictions(t *testing.T) {
|
||||
restrictions.NewSetEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
context.Background(),
|
||||
&restrictions.NewAggregate("restrictions1", "instance1", "instance1").Aggregate,
|
||||
&restrictions.NewAggregate("restrictions1", "INSTANCE", "INSTANCE").Aggregate,
|
||||
restrictions.SetEventType,
|
||||
),
|
||||
restrictions.ChangePublicOrgRegistrations(true),
|
||||
restrictions.ChangeDisallowPublicOrgRegistration(true),
|
||||
),
|
||||
),
|
||||
),
|
||||
), nil
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
setRestrictions: &SetRestrictions{},
|
||||
},
|
||||
res: res{
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unsupported language restricted",
|
||||
fields: func(*testing.T) (*eventstore.Eventstore, id.Generator) {
|
||||
return eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
restrictions.NewSetEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
context.Background(),
|
||||
&restrictions.NewAggregate("restrictions1", "INSTANCE", "INSTANCE").Aggregate,
|
||||
restrictions.SetEventType,
|
||||
),
|
||||
restrictions.ChangeAllowedLanguages(SupportedLanguages),
|
||||
),
|
||||
),
|
||||
),
|
||||
), nil
|
||||
},
|
||||
args: args{
|
||||
setRestrictions: &SetRestrictions{
|
||||
AllowedLanguages: []language.Tag{AllowedLanguage, UnsupportedLanguage},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: zitadel_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default language not allowed",
|
||||
fields: func(*testing.T) (*eventstore.Eventstore, id.Generator) {
|
||||
return eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
restrictions.NewSetEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
context.Background(),
|
||||
&restrictions.NewAggregate("restrictions1", "INSTANCE", "INSTANCE").Aggregate,
|
||||
restrictions.SetEventType,
|
||||
),
|
||||
restrictions.ChangeAllowedLanguages(OnlyAllowedLanguages),
|
||||
),
|
||||
),
|
||||
),
|
||||
), nil
|
||||
},
|
||||
args: args{
|
||||
setRestrictions: &SetRestrictions{
|
||||
AllowedLanguages: []language.Tag{DisallowedLanguage},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: zitadel_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := new(Commands)
|
||||
r.eventstore, r.idGenerator = tt.fields(t)
|
||||
got, err := r.SetInstanceRestrictions(tt.args.ctx, tt.args.setRestrictions)
|
||||
got, err := r.SetInstanceRestrictions(authz.WithInstance(context.Background(), &mockInstance{}), tt.args.setRestrictions)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
zitadel_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/repository/user"
|
||||
@@ -36,8 +36,7 @@ func TestCommandSide_ChangeHumanProfile(t *testing.T) {
|
||||
{
|
||||
name: "user not existing, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
@@ -51,13 +50,13 @@ func TestCommandSide_ChangeHumanProfile(t *testing.T) {
|
||||
LastName: "lastname",
|
||||
NickName: "nickname",
|
||||
DisplayName: "displayname",
|
||||
PreferredLanguage: language.German,
|
||||
PreferredLanguage: AllowedLanguage,
|
||||
Gender: domain.GenderFemale,
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsPreconditionFailed,
|
||||
err: zitadel_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -74,7 +73,7 @@ func TestCommandSide_ChangeHumanProfile(t *testing.T) {
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
AllowedLanguage,
|
||||
domain.GenderFemale,
|
||||
"email",
|
||||
true,
|
||||
@@ -93,13 +92,13 @@ func TestCommandSide_ChangeHumanProfile(t *testing.T) {
|
||||
LastName: "lastname",
|
||||
NickName: "nickname",
|
||||
DisplayName: "displayname",
|
||||
PreferredLanguage: language.German,
|
||||
PreferredLanguage: AllowedLanguage,
|
||||
Gender: domain.GenderFemale,
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsPreconditionFailed,
|
||||
err: zitadel_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -116,7 +115,7 @@ func TestCommandSide_ChangeHumanProfile(t *testing.T) {
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
DisallowedLanguage,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
true,
|
||||
@@ -130,7 +129,7 @@ func TestCommandSide_ChangeHumanProfile(t *testing.T) {
|
||||
"lastname2",
|
||||
"nickname2",
|
||||
"displayname2",
|
||||
language.English,
|
||||
AllowedLanguage,
|
||||
domain.GenderMale,
|
||||
),
|
||||
),
|
||||
@@ -146,7 +145,7 @@ func TestCommandSide_ChangeHumanProfile(t *testing.T) {
|
||||
LastName: "lastname2",
|
||||
NickName: "nickname2",
|
||||
DisplayName: "displayname2",
|
||||
PreferredLanguage: language.English,
|
||||
PreferredLanguage: AllowedLanguage,
|
||||
Gender: domain.GenderMale,
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
@@ -161,7 +160,133 @@ func TestCommandSide_ChangeHumanProfile(t *testing.T) {
|
||||
LastName: "lastname2",
|
||||
NickName: "nickname2",
|
||||
DisplayName: "displayname2",
|
||||
PreferredLanguage: language.English,
|
||||
PreferredLanguage: AllowedLanguage,
|
||||
Gender: domain.GenderMale,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "undefined preferred language, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
DisallowedLanguage,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
newProfileChangedEvent(context.Background(),
|
||||
"user1", "org1",
|
||||
"firstname2",
|
||||
"lastname2",
|
||||
"nickname2",
|
||||
"displayname2",
|
||||
language.Und,
|
||||
domain.GenderMale,
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
address: &domain.Profile{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "user1",
|
||||
},
|
||||
FirstName: "firstname2",
|
||||
LastName: "lastname2",
|
||||
NickName: "nickname2",
|
||||
DisplayName: "displayname2",
|
||||
Gender: domain.GenderMale,
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
want: &domain.Profile{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "user1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
FirstName: "firstname2",
|
||||
LastName: "lastname2",
|
||||
NickName: "nickname2",
|
||||
DisplayName: "displayname2",
|
||||
PreferredLanguage: language.Und,
|
||||
Gender: domain.GenderMale,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "unsupported preferred language, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
DisallowedLanguage,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
true,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
newProfileChangedEvent(context.Background(),
|
||||
"user1", "org1",
|
||||
"firstname2",
|
||||
"lastname2",
|
||||
"nickname2",
|
||||
"displayname2",
|
||||
UnsupportedLanguage,
|
||||
domain.GenderMale,
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
address: &domain.Profile{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "user1",
|
||||
},
|
||||
FirstName: "firstname2",
|
||||
LastName: "lastname2",
|
||||
NickName: "nickname2",
|
||||
DisplayName: "displayname2",
|
||||
PreferredLanguage: UnsupportedLanguage,
|
||||
Gender: domain.GenderMale,
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
want: &domain.Profile{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "user1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
FirstName: "firstname2",
|
||||
LastName: "lastname2",
|
||||
NickName: "nickname2",
|
||||
DisplayName: "displayname2",
|
||||
PreferredLanguage: UnsupportedLanguage,
|
||||
Gender: domain.GenderMale,
|
||||
},
|
||||
},
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -5,11 +5,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
|
Reference in New Issue
Block a user