feat: set default language on instance (#3594)

This commit is contained in:
Livio Amstutz 2022-05-03 15:58:38 +02:00 committed by GitHub
parent 462fe10dab
commit 79db247801
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 83 additions and 35 deletions

View File

@ -6,6 +6,8 @@ import (
"fmt"
"strings"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/config/systemdefaults"
@ -15,9 +17,10 @@ import (
)
type DefaultInstance struct {
InstanceName string
CustomDomain string
Org command.OrgSetup
InstanceName string
CustomDomain string
DefaultLanguage language.Tag
Org command.OrgSetup
instanceSetup command.InstanceSetup
userEncryptionKey *crypto.KeyConfig
@ -67,6 +70,7 @@ func (mig *DefaultInstance) Execute(ctx context.Context) error {
mig.instanceSetup.InstanceName = mig.InstanceName
mig.instanceSetup.CustomDomain = mig.CustomDomain
mig.instanceSetup.DefaultLanguage = mig.DefaultLanguage
mig.instanceSetup.Org = mig.Org
mig.instanceSetup.Org.Human.Email.Address = strings.TrimSpace(mig.instanceSetup.Org.Human.Email.Address)
if mig.instanceSetup.Org.Human.Email.Address == "" {

View File

@ -1,6 +1,7 @@
S3DefaultInstance:
InstanceName: Localhost
CustomDomain: localhost
DefaultLanguage: en
Org:
Name: ZITADEL
Human:

View File

@ -162,6 +162,7 @@ SystemDefaults:
DefaultInstance:
InstanceName:
DefaultLanguage: en
Org:
Name:
Human:

View File

@ -233,6 +233,7 @@ failed event. You can find out if it worked on the `failure_count`
| owner_email | AddInstanceRequest.Email | - | message.required: true<br /> |
| owner_profile | AddInstanceRequest.Profile | - | message.required: false<br /> |
| owner_password | AddInstanceRequest.Password | - | message.required: false<br /> |
| default_language | string | - | string.max_len: 10<br /> |

View File

@ -6,6 +6,7 @@ import (
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/object"
"github.com/zitadel/zitadel/internal/api/grpc/text"
caos_errors "github.com/zitadel/zitadel/internal/errors"
admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin"
@ -20,19 +21,17 @@ func (s *Server) GetSupportedLanguages(ctx context.Context, req *admin_pb.GetSup
}
func (s *Server) SetDefaultLanguage(ctx context.Context, req *admin_pb.SetDefaultLanguageRequest) (*admin_pb.SetDefaultLanguageResponse, error) {
_, err := language.Parse(req.Language)
lang, err := language.Parse(req.Language)
if err != nil {
return nil, caos_errors.ThrowInvalidArgument(err, "API-39nnf", "Errors.Language.Parse")
}
//TODO: Will be added by silvan
//details, err := s.command.SetDefaultLanguage(ctx, lang)
//if err != nil {
// return nil, err
//}
//return &admin_pb.SetDefaultLanguageResponse{
// Details: object.DomainToChangeDetailsPb(details),
//}, nil
return nil, nil
details, err := s.command.SetDefaultLanguage(ctx, lang)
if err != nil {
return nil, err
}
return &admin_pb.SetDefaultLanguageResponse{
Details: object.DomainToChangeDetailsPb(details),
}, nil
}
func (s *Server) GetDefaultLanguage(ctx context.Context, _ *admin_pb.GetDefaultLanguageRequest) (*admin_pb.GetDefaultLanguageResponse, error) {

View File

@ -47,6 +47,9 @@ func AddInstancePbToSetupInstance(req *system_pb.AddInstanceRequest, defaultInst
defaultInstance.Org.Human.Password = req.OwnerPassword.Password
defaultInstance.Org.Human.PasswordChangeRequired = req.OwnerPassword.PasswordChangeRequired
}
if lang := language.Make(req.DefaultLanguage); lang != language.Und {
defaultInstance.DefaultLanguage = lang
}
return &defaultInstance
}

View File

@ -4,6 +4,8 @@ import (
"context"
"time"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/ui/console"
"github.com/zitadel/zitadel/internal/command/preparation"
@ -32,6 +34,7 @@ type InstanceSetup struct {
zitadel ZitadelConfig
InstanceName string
CustomDomain string
DefaultLanguage language.Tag
Org OrgSetup
SecretGenerators struct {
PasswordSaltCost uint
@ -166,7 +169,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
projectAgg := project.NewAggregate(setup.zitadel.projectID, orgID)
validations := []preparation.Validation{
addInstance(instanceAgg, setup.InstanceName),
addInstance(instanceAgg, setup.InstanceName, setup.DefaultLanguage),
addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeAppSecret, setup.SecretGenerators.ClientSecret),
addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeInitCode, setup.SecretGenerators.InitializeUserCode),
addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeVerifyEmailCode, setup.SecretGenerators.EmailVerificationCode),
@ -332,11 +335,30 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
}, nil
}
func addInstance(a *instance.Aggregate, instanceName string) preparation.Validation {
func (c *Commands) SetDefaultLanguage(ctx context.Context, defaultLanguage language.Tag) (*domain.ObjectDetails, error) {
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
validation := c.prepareSetDefaultLanguage(instanceAgg, defaultLanguage)
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validation)
if err != nil {
return nil, err
}
events, err := c.eventstore.Push(ctx, cmds...)
if err != nil {
return nil, err
}
return &domain.ObjectDetails{
Sequence: events[len(events)-1].Sequence(),
EventDate: events[len(events)-1].CreationDate(),
ResourceOwner: events[len(events)-1].Aggregate().InstanceID,
}, nil
}
func addInstance(a *instance.Aggregate, instanceName string, defaultLanguage language.Tag) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
return []eventstore.Command{
instance.NewInstanceAddedEvent(ctx, &a.Aggregate, instanceName),
instance.NewDefaultLanguageSetEvent(ctx, &a.Aggregate, defaultLanguage),
}, nil
}, nil
}
@ -385,3 +407,35 @@ func (c *Commands) setIAMProject(ctx context.Context, iamAgg *eventstore.Aggrega
}
return instance.NewIAMProjectSetEvent(ctx, iamAgg, projectID), nil
}
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")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel, err := getInstanceWriteModel(ctx, filter)
if err != nil {
return nil, err
}
if writeModel.DefaultLanguage == defaultLanguage {
return nil, errors.ThrowPreconditionFailed(nil, "INST-DS3rq", "Errors.Instance.NotChanged")
}
return []eventstore.Command{instance.NewDefaultLanguageSetEvent(ctx, &a.Aggregate, defaultLanguage)}, nil
}, nil
}
}
func getInstanceWriteModel(ctx context.Context, filter preparation.FilterToQueryReducer) (*InstanceWriteModel, error) {
writeModel := NewInstanceWriteModel(authz.GetInstance(ctx).InstanceID())
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
if len(events) == 0 {
return writeModel, nil
}
writeModel.AppendEvents(events...)
err = writeModel.Reduce()
return writeModel, err
}

View File

@ -98,9 +98,6 @@ func AddHumanCommand(a *user.Aggregate, human *AddHuman, passwordAlg crypto.Hash
return nil, errors.ThrowInvalidArgument(nil, "V2-zzad3", "Errors.Invalid.Argument")
}
if human.PreferredLanguage == language.Und {
return nil, errors.ThrowInvalidArgument(nil, "USER-Sfd11", "Errors.Invalid.Argument")
}
if human.FirstName = strings.TrimSpace(human.FirstName); human.FirstName == "" {
return nil, errors.ThrowInvalidArgument(nil, "USER-UCej2", "Errors.Invalid.Argument")
}

View File

@ -2856,21 +2856,6 @@ func TestAddHumanCommand(t *testing.T) {
ValidationErr: errors.ThrowInvalidArgument(nil, "USER-Ec7dM", "Errors.Invalid.Argument"),
},
},
{
name: "invalid preferred language",
args: args{
a: agg,
human: &AddHuman{
Username: "username",
Email: Email{
Address: "support@zitadel.ch",
},
},
},
want: Want{
ValidationErr: errors.ThrowInvalidArgument(nil, "USER-Sfd11", "Errors.Invalid.Argument"),
},
},
{
name: "invalid first name",
args: args{

View File

@ -281,6 +281,7 @@ func prepareInstancesQuery() (sq.SelectBuilder, func(*sql.Rows) (*Instances, err
&lang,
&count,
)
instance.DefaultLang = language.Make(lang)
if err != nil {
return nil, err
}
@ -378,6 +379,7 @@ func prepareInstanceDomainQuery(host string) (sq.SelectBuilder, func(*sql.Rows)
InstanceID: instance.ID,
})
}
instance.DefaultLang = language.Make(lang)
if err := rows.Close(); err != nil {
return nil, errors.ThrowInternal(err, "QUERY-Dfbe2", "Errors.Query.CloseRows")
}

View File

@ -4,15 +4,15 @@ import (
"context"
"encoding/json"
"github.com/zitadel/zitadel/internal/eventstore"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/repository"
)
const (
DefaultLanguageSetEventType eventstore.EventType = "iam.default.language.set"
DefaultLanguageSetEventType eventstore.EventType = "instance.default.language.set"
)
type DefaultLanguageSetEvent struct {

View File

@ -342,6 +342,7 @@ message AddInstanceRequest {
Email owner_email = 5 [(validate.rules).message.required = true];
Profile owner_profile = 6 [(validate.rules).message.required = false];
Password owner_password = 7 [(validate.rules).message.required = false];
string default_language = 8 [(validate.rules).string = {max_len: 10}];
}
message AddInstanceResponse {