feat: Custom text login (#1925)

* feat: default custom message text

* feat: org custom message text

* feat: org custom message text

* feat: custom messages query side

* feat: default messages

* feat: message text user fields

* feat: check for inactive user

* feat: fix send password reset

* feat: fix custom org text

* feat: add variables to docs

* feat: custom text tests

* feat: fix notifications

* feat: add custom text feature

* feat: add custom text feature

* feat: feature in custom message texts

* feat: add custom text feature in frontend

* feat: merge main

* feat: feature tests

* feat: change phone message in setup

* fix: remove unused code, add event translation

* fix: merge main and fix problems

* fix: english translation file

* fix: migration versions

* fix: setup

* fix: custom login text

* feat: add all possible custom texts for login

* feat: iam login texts

* feat: org login texts

* feat: protos

* fix: custom text in admin api

* fix: add success login text

* fix: docs

* fix: add custom login texts to management api

* fix: add sub messages to custom login texts

* fix: setup custom texts

* feat: get org login texts

* feat: get org login texts

* feat: handler in adminapi

* feat: handlers in auth and admin

* feat: render login texts

* feat: custom login text

* feat: add all login text keys

* feat: handle correct login texts

* feat: custom login texts in command side

* feat: custom login texts in command side

* feat: fix yaml file

* feat: merge master and add confirmation text

* feat: fix html

* feat: read default login texts

* feat: get default text files

* feat: get custom texts org

* feat: tests

* feat: change translator handling

* fix translator from authReq

* feat: change h1 on login screens

* feat: add custom login text for remove

* feat: add custom login text for remove

* feat: cache translation files

* feat: cache translation files

* feat: zitadel user in env var

* feat: add registration user description

* feat: better func naming

* feat: tests

* feat: add mutex to read file

* feat: add mutex to read file

* fix mutex for accessing translation map

* fix: translation key

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Fabi 2021-07-05 15:10:49 +02:00 committed by GitHub
parent 7c0bc8f63d
commit 99b2c33ccb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
124 changed files with 21023 additions and 474 deletions

View File

@ -32,7 +32,7 @@ ZITADEL_CSRF_DEV=true
#currently needed
TWILIO_SENDER_NAME=ZITADEL developer
SMTP_HOST=smtp.gmail.com:465
SMTP_USER=zitadel-dev@caos.ch
SMTP_USER=zitadel@caos.ch
EMAIL_SENDER_ADDRESS=noreply@caos.ch
EMAIL_SENDER_NAME=CAOS AG
SMTP_TLS=true

View File

@ -664,6 +664,37 @@ The Following Variables can be used:
### GetDefaultLoginTexts
> **rpc** GetDefaultLoginTexts([GetDefaultLoginTextsRequest](#getdefaultlogintextsrequest))
[GetDefaultLoginTextsResponse](#getdefaultlogintextsresponse)
Returns the default custom texts for login ui
### GetCustomLoginTexts
> **rpc** GetCustomLoginTexts([GetCustomLoginTextsRequest](#getcustomlogintextsrequest))
[GetCustomLoginTextsResponse](#getcustomlogintextsresponse)
Returns the custom texts for login ui
### SetCustomLoginText
> **rpc** SetCustomLoginText([SetCustomLoginTextsRequest](#setcustomlogintextsrequest))
[SetCustomLoginTextsResponse](#setcustomlogintextsresponse)
Sets the custom text for login ui
it impacts all organisations without customized login ui texts
### ListIAMMemberRoles
> **rpc** ListIAMMemberRoles([ListIAMMemberRolesRequest](#listiammemberrolesrequest))
@ -990,6 +1021,28 @@ This is an empty response
### GetCustomLoginTextsRequest
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
### GetCustomLoginTextsResponse
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| custom_text | zitadel.text.v1.LoginCustomText | - | |
### GetCustomOrgIAMPolicyRequest
@ -1074,6 +1127,28 @@ This is an empty response
### GetDefaultLoginTextsRequest
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
### GetDefaultLoginTextsResponse
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| custom_text | zitadel.text.v1.LoginCustomText | - | |
### GetDefaultPasswordResetMessageTextRequest
@ -1856,6 +1931,58 @@ This is an empty request
### SetCustomLoginTextsRequest
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
| select_account_text | zitadel.text.v1.SelectAccountScreenText | - | |
| login_text | zitadel.text.v1.LoginScreenText | - | |
| password_text | zitadel.text.v1.PasswordScreenText | - | |
| username_change_text | zitadel.text.v1.UsernameChangeScreenText | - | |
| username_change_done_text | zitadel.text.v1.UsernameChangeDoneScreenText | - | |
| init_password_text | zitadel.text.v1.InitPasswordScreenText | - | |
| init_password_done_text | zitadel.text.v1.InitPasswordDoneScreenText | - | |
| email_verification_text | zitadel.text.v1.EmailVerificationScreenText | - | |
| email_verification_done_text | zitadel.text.v1.EmailVerificationDoneScreenText | - | |
| initialize_user_text | zitadel.text.v1.InitializeUserScreenText | - | |
| initialize_done_text | zitadel.text.v1.InitializeUserDoneScreenText | - | |
| init_mfa_prompt_text | zitadel.text.v1.InitMFAPromptScreenText | - | |
| init_mfa_otp_text | zitadel.text.v1.InitMFAOTPScreenText | - | |
| init_mfa_u2f_text | zitadel.text.v1.InitMFAU2FScreenText | - | |
| init_mfa_done_text | zitadel.text.v1.InitMFADoneScreenText | - | |
| mfa_providers_text | zitadel.text.v1.MFAProvidersText | - | |
| verify_mfa_otp_text | zitadel.text.v1.VerifyMFAOTPScreenText | - | |
| verify_mfa_u2f_text | zitadel.text.v1.VerifyMFAU2FScreenText | - | |
| passwordless_text | zitadel.text.v1.PasswordlessScreenText | - | |
| password_change_text | zitadel.text.v1.PasswordChangeScreenText | - | |
| password_change_done_text | zitadel.text.v1.PasswordChangeDoneScreenText | - | |
| password_reset_done_text | zitadel.text.v1.PasswordResetDoneScreenText | - | |
| registration_option_text | zitadel.text.v1.RegistrationOptionScreenText | - | |
| registration_user_text | zitadel.text.v1.RegistrationUserScreenText | - | |
| registration_org_text | zitadel.text.v1.RegistrationOrgScreenText | - | |
| linking_user_done_text | zitadel.text.v1.LinkingUserDoneScreenText | - | |
| external_user_not_found_text | zitadel.text.v1.ExternalUserNotFoundScreenText | - | |
| success_login_text | zitadel.text.v1.SuccessLoginScreenText | - | |
| logout_text | zitadel.text.v1.LogoutDoneScreenText | - | |
| footer_text | zitadel.text.v1.FooterText | - | |
### SetCustomLoginTextsResponse
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| details | zitadel.v1.ObjectDetails | - | |
### SetDefaultDomainClaimedMessageTextRequest

View File

@ -1987,6 +1987,48 @@ The default text of the IAM will trigger after
### GetCustomLoginTexts
> **rpc** GetCustomLoginTexts([GetCustomLoginTextsRequest](#getcustomlogintextsrequest))
[GetCustomLoginTextsResponse](#getcustomlogintextsresponse)
Returns the custom texts for login ui
### GetDefaultLoginTexts
> **rpc** GetDefaultLoginTexts([GetDefaultLoginTextsRequest](#getdefaultlogintextsrequest))
[GetDefaultLoginTextsResponse](#getdefaultlogintextsresponse)
Returns the custom texts for login ui
### SetCustomLoginText
> **rpc** SetCustomLoginText([SetCustomLoginTextsRequest](#setcustomlogintextsrequest))
[SetCustomLoginTextsResponse](#setcustomlogintextsresponse)
Sets the default custom text for login ui
it impacts all organisations without customized login ui texts
### ResetCustomLoginTextToDefault
> **rpc** ResetCustomLoginTextToDefault([ResetCustomLoginTextsToDefaultRequest](#resetcustomlogintextstodefaultrequest))
[ResetCustomLoginTextsToDefaultResponse](#resetcustomlogintextstodefaultresponse)
Removes the custom login text of the organisation
The default text of the IAM will trigger after
### GetOrgIDPByID
> **rpc** GetOrgIDPByID([GetOrgIDPByIDRequest](#getorgidpbyidrequest))
@ -3100,6 +3142,28 @@ This is an empty request
### GetCustomLoginTextsRequest
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
### GetCustomLoginTextsResponse
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| custom_text | zitadel.text.v1.LoginCustomText | - | |
### GetCustomPasswordResetMessageTextRequest
@ -3244,6 +3308,28 @@ This is an empty request
### GetDefaultLoginTextsRequest
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
### GetDefaultLoginTextsResponse
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| custom_text | zitadel.text.v1.LoginCustomText | - | |
### GetDefaultPasswordAgePolicyRequest
This is an empty request
@ -5568,6 +5654,28 @@ This is an empty request
### ResetCustomLoginTextsToDefaultRequest
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
### ResetCustomLoginTextsToDefaultResponse
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| details | zitadel.v1.ObjectDetails | - | |
### ResetCustomPasswordResetMessageTextToDefaultRequest
@ -5817,6 +5925,58 @@ This is an empty request
### SetCustomLoginTextsRequest
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| language | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
| select_account_text | zitadel.text.v1.SelectAccountScreenText | - | |
| login_text | zitadel.text.v1.LoginScreenText | - | |
| password_text | zitadel.text.v1.PasswordScreenText | - | |
| username_change_text | zitadel.text.v1.UsernameChangeScreenText | - | |
| username_change_done_text | zitadel.text.v1.UsernameChangeDoneScreenText | - | |
| init_password_text | zitadel.text.v1.InitPasswordScreenText | - | |
| init_password_done_text | zitadel.text.v1.InitPasswordDoneScreenText | - | |
| email_verification_text | zitadel.text.v1.EmailVerificationScreenText | - | |
| email_verification_done_text | zitadel.text.v1.EmailVerificationDoneScreenText | - | |
| initialize_user_text | zitadel.text.v1.InitializeUserScreenText | - | |
| initialize_done_text | zitadel.text.v1.InitializeUserDoneScreenText | - | |
| init_mfa_prompt_text | zitadel.text.v1.InitMFAPromptScreenText | - | |
| init_mfa_otp_text | zitadel.text.v1.InitMFAOTPScreenText | - | |
| init_mfa_u2f_text | zitadel.text.v1.InitMFAU2FScreenText | - | |
| init_mfa_done_text | zitadel.text.v1.InitMFADoneScreenText | - | |
| mfa_providers_text | zitadel.text.v1.MFAProvidersText | - | |
| verify_mfa_otp_text | zitadel.text.v1.VerifyMFAOTPScreenText | - | |
| verify_mfa_u2f_text | zitadel.text.v1.VerifyMFAU2FScreenText | - | |
| passwordless_text | zitadel.text.v1.PasswordlessScreenText | - | |
| password_change_text | zitadel.text.v1.PasswordChangeScreenText | - | |
| password_change_done_text | zitadel.text.v1.PasswordChangeDoneScreenText | - | |
| password_reset_done_text | zitadel.text.v1.PasswordResetDoneScreenText | - | |
| registration_option_text | zitadel.text.v1.RegistrationOptionScreenText | - | |
| registration_user_text | zitadel.text.v1.RegistrationUserScreenText | - | |
| registration_org_text | zitadel.text.v1.RegistrationOrgScreenText | - | |
| linking_user_done_text | zitadel.text.v1.LinkingUserDoneScreenText | - | |
| external_user_not_found_text | zitadel.text.v1.ExternalUserNotFoundScreenText | - | |
| success_login_text | zitadel.text.v1.SuccessLoginScreenText | - | |
| logout_text | zitadel.text.v1.LogoutDoneScreenText | - | |
| footer_text | zitadel.text.v1.FooterText | - | |
### SetCustomLoginTextsResponse
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| details | zitadel.v1.ObjectDetails | - | |
### SetCustomPasswordResetMessageTextRequest

1
go.sum
View File

@ -240,6 +240,7 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.1 h1:4CF52PCseTFt4bE+Yk3dIpdVi7XWuPVMhPtm4FaIJPM=
github.com/envoyproxy/protoc-gen-validate v0.6.1/go.mod h1:txg5va2Qkip90uYoSKH+nkAAmXrb2j3iq4FLwdrCbXQ=

View File

@ -30,7 +30,7 @@ With this command you can generate the stub for the backend.
# generates grpc stub
DOCKER_BUILDKIT=1 docker build -f build/dockerfile . -t zitadel:gen-be --target go-copy -o .
# generates keys for cryptography
DOCKER_BUILDKIT=1 docker build --target copy_keys -f build/Dockerfile.dev . -o .keys
DOCKER_BUILDKIT=1 docker build --target copy-keys -f build/local/Dockerfile.keys . -o .keys
```
## Run

View File

@ -2,7 +2,13 @@ package eventstore
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"strings"
"sync"
"github.com/ghodss/yaml"
"github.com/caos/zitadel/internal/domain"
v1 "github.com/caos/zitadel/internal/eventstore/v1"
@ -23,12 +29,15 @@ import (
)
type IAMRepository struct {
Eventstore v1.Eventstore
SearchLimit uint64
View *admin_view.View
SystemDefaults systemdefaults.SystemDefaults
Roles []string
PrefixAvatarURL string
Eventstore v1.Eventstore
SearchLimit uint64
View *admin_view.View
SystemDefaults systemdefaults.SystemDefaults
Roles []string
PrefixAvatarURL string
LoginDir http.FileSystem
TranslationFileContents map[string][]byte
mutex sync.Mutex
}
func (repo *IAMRepository) IAMMemberByID(ctx context.Context, iamID, userID string) (*iam_model.IAMMemberView, error) {
@ -399,6 +408,32 @@ func (repo *IAMRepository) GetDefaultPrivacyPolicy(ctx context.Context) (*iam_mo
return result, nil
}
func (repo *IAMRepository) GetDefaultLoginTexts(ctx context.Context, lang string) (*domain.CustomLoginText, error) {
repo.mutex.Lock()
defer repo.mutex.Unlock()
contents, ok := repo.TranslationFileContents[lang]
if !ok {
contents, err := repo.readTranslationFile(fmt.Sprintf("/i18n/%s.yaml", lang))
if err != nil {
return nil, err
}
repo.TranslationFileContents[lang] = contents
}
loginText := new(domain.CustomLoginText)
if err := yaml.Unmarshal(contents, loginText); err != nil {
return nil, caos_errs.ThrowInternal(err, "TEXT-GHR3Q", "Errors.TranslationFile.ReadError")
}
return loginText, nil
}
func (repo *IAMRepository) GetCustomLoginTexts(ctx context.Context, lang string) (*domain.CustomLoginText, error) {
texts, err := repo.View.CustomTextsByAggregateIDAndTemplateAndLand(repo.SystemDefaults.IamID, domain.LoginCustomText, lang)
if err != nil {
return nil, err
}
return iam_es_model.CustomTextViewsToLoginDomain(repo.SystemDefaults.IamID, lang, texts), err
}
func (repo *IAMRepository) getIAMEvents(ctx context.Context, sequence uint64) ([]*models.Event, error) {
query, err := iam_view.IAMByIDQuery(domain.IAMID, sequence)
if err != nil {
@ -406,3 +441,15 @@ func (repo *IAMRepository) getIAMEvents(ctx context.Context, sequence uint64) ([
}
return repo.Eventstore.FilterEvents(ctx, query)
}
func (repo *IAMRepository) readTranslationFile(filename string) ([]byte, error) {
r, err := repo.LoginDir.Open(filename)
if err != nil {
return nil, caos_errs.ThrowInternal(err, "TEXT-93njw", "Errors.TranslationFile.ReadError")
}
contents, err := ioutil.ReadAll(r)
if err != nil {
return nil, caos_errs.ThrowInternal(err, "TEXT-l0fse", "Errors.TranslationFile.ReadError")
}
return contents, nil
}

View File

@ -13,6 +13,7 @@ import (
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/logging"
admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
"github.com/caos/zitadel/internal/config/systemdefaults"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"

View File

@ -0,0 +1,121 @@
package handler
import (
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query"
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
type CustomText struct {
handler
subscription *v1.Subscription
}
func newCustomText(handler handler) *CustomText {
h := &CustomText{
handler: handler,
}
h.subscribe()
return h
}
func (m *CustomText) subscribe() {
m.subscription = m.es.Subscribe(m.AggregateTypes()...)
go func() {
for event := range m.subscription.Events {
query.ReduceEvent(m, event)
}
}()
}
const (
customTextTable = "adminapi.custom_texts"
)
func (m *CustomText) ViewModel() string {
return customTextTable
}
func (_ *CustomText) AggregateTypes() []es_models.AggregateType {
return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
}
func (p *CustomText) CurrentSequence() (uint64, error) {
sequence, err := p.view.GetLatestCustomTextSequence()
if err != nil {
return 0, err
}
return sequence.CurrentSequence, nil
}
func (m *CustomText) EventQuery() (*es_models.SearchQuery, error) {
sequence, err := m.view.GetLatestCustomTextSequence()
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
func (m *CustomText) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
err = m.processCustomText(event)
}
return err
}
func (m *CustomText) processCustomText(event *es_models.Event) (err error) {
customText := new(iam_model.CustomTextView)
switch event.Type {
case iam_es_model.CustomTextSet, model.CustomTextSet:
text := new(iam_model.CustomTextView)
err = text.SetData(event)
if err != nil {
return err
}
customText, err = m.view.CustomTextByIDs(event.AggregateID, text.Template, text.Key, text.Language)
if err != nil && !caos_errs.IsNotFound(err) {
return err
}
if caos_errs.IsNotFound(err) {
err = nil
customText = new(iam_model.CustomTextView)
customText.Language = text.Language
customText.Template = text.Template
customText.CreationDate = event.CreationDate
}
err = customText.AppendEvent(event)
case iam_es_model.CustomTextRemoved, model.CustomTextRemoved:
text := new(iam_model.CustomTextView)
err = text.SetData(event)
if err != nil {
return err
}
return m.view.DeleteCustomText(event.AggregateID, text.Template, text.Language, event)
default:
return m.view.ProcessedCustomTextSequence(event)
}
if err != nil {
return err
}
return m.view.PutCustomText(customText, event)
}
func (m *CustomText) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-3m912", "id", event.AggregateID).WithError(err).Warn("something went wrong in custom text handler")
return spooler.HandleError(event, err, m.view.GetLatestCustomTextFailedEvent, m.view.ProcessedCustomTextFailedEvent, m.view.ProcessedCustomTextSequence, m.errorCountUntilSkip)
}
func (o *CustomText) OnSuccess() error {
return spooler.HandleSuccess(o.view.UpdateCustomTextSpoolerRunTimestamp)
}

View File

@ -68,6 +68,8 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
handler{view, bulkLimit, configs.cycleDuration("Features"), errorCount, es}),
newPrivacyPolicy(
handler{view, bulkLimit, configs.cycleDuration("PrivacyPolicy"), errorCount, es}),
newCustomText(
handler{view, bulkLimit, configs.cycleDuration("CustomTexts"), errorCount, es}),
}
if static != nil {
handlers = append(handlers, newStyling(

View File

@ -80,19 +80,19 @@ func (m *MessageText) processMessageText(event *es_models.Event) (err error) {
switch event.Type {
case model.CustomTextSet,
model.CustomTextRemoved:
text := new(iam_model.CustomText)
text := new(iam_model.CustomTextView)
err = text.SetData(event)
if err != nil {
return err
}
message, err = m.view.MessageTextByIDs(event.AggregateID, text.Template, text.Language.String())
message, err = m.view.MessageTextByIDs(event.AggregateID, text.Template, text.Language)
if err != nil && !caos_errs.IsNotFound(err) {
return err
}
if caos_errs.IsNotFound(err) {
err = nil
message = new(iam_model.MessageTextView)
message.Language = text.Language.String()
message.Language = text.Language
message.MessageTextType = text.Template
message.CreationDate = event.CreationDate
}

View File

@ -3,6 +3,9 @@ package eventsourcing
import (
"context"
"github.com/caos/logging"
"github.com/rakyll/statik/fs"
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/eventstore"
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/spooler"
admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
@ -48,6 +51,9 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, s
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults, static, localDevMode)
assetsAPI := conf.APIDomain + "/assets/v1/"
statikLoginFS, err := fs.NewWithNamespace("login")
logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start login statik dir")
return &EsRepository{
spooler: spool,
OrgRepo: eventstore.OrgRepo{
@ -57,12 +63,14 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, s
SystemDefaults: systemDefaults,
},
IAMRepository: eventstore.IAMRepository{
Eventstore: es,
View: view,
SystemDefaults: systemDefaults,
SearchLimit: conf.SearchLimit,
Roles: roles,
PrefixAvatarURL: assetsAPI,
Eventstore: es,
View: view,
SystemDefaults: systemDefaults,
SearchLimit: conf.SearchLimit,
Roles: roles,
PrefixAvatarURL: assetsAPI,
LoginDir: statikLoginFS,
TranslationFileContents: make(map[string][]byte),
},
AdministratorRepo: eventstore.AdministratorRepo{
View: view,

View File

@ -0,0 +1,57 @@
package view
import (
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
)
const (
customTextTable = "adminapi.custom_texts"
)
func (v *View) CustomTextByIDs(aggregateID, template, lang, key string) (*model.CustomTextView, error) {
return view.CustomTextByIDs(v.Db, customTextTable, aggregateID, template, lang, key)
}
func (v *View) CustomTextsByAggregateIDAndTemplateAndLand(aggregateID, template, lang string) ([]*model.CustomTextView, error) {
return view.GetCustomTexts(v.Db, customTextTable, aggregateID, template, lang)
}
func (v *View) PutCustomText(template *model.CustomTextView, event *models.Event) error {
err := view.PutCustomText(v.Db, customTextTable, template)
if err != nil {
return err
}
return v.ProcessedCustomTextSequence(event)
}
func (v *View) DeleteCustomText(aggregateID, textType, lang string, event *models.Event) error {
err := view.DeleteCustomText(v.Db, customTextTable, aggregateID, textType, lang)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedCustomTextSequence(event)
}
func (v *View) GetLatestCustomTextSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(customTextTable)
}
func (v *View) ProcessedCustomTextSequence(event *models.Event) error {
return v.saveCurrentSequence(customTextTable, event)
}
func (v *View) UpdateCustomTextSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(customTextTable)
}
func (v *View) GetLatestCustomTextFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
return v.latestFailedEvent(customTextTable, sequence)
}
func (v *View) ProcessedCustomTextFailedEvent(failedEvent *global_view.FailedEvent) error {
return v.saveFailedEvent(failedEvent)
}

View File

@ -2,6 +2,7 @@ package repository
import (
"context"
"github.com/caos/zitadel/internal/domain"
usr_model "github.com/caos/zitadel/internal/user/model"
iam_model "github.com/caos/zitadel/internal/iam/model"
@ -30,6 +31,8 @@ type IAMRepository interface {
GetDefaultMessageTexts(ctx context.Context) (*iam_model.MessageTextsView, error)
GetDefaultMessageText(ctx context.Context, textType string, language string) (*iam_model.MessageTextView, error)
GetDefaultLoginTexts(ctx context.Context, lang string) (*domain.CustomLoginText, error)
GetCustomLoginTexts(ctx context.Context, lang string) (*domain.CustomLoginText, error)
GetDefaultPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error)

View File

@ -128,3 +128,36 @@ func (s *Server) SetDefaultDomainClaimedMessageText(ctx context.Context, req *ad
),
}, nil
}
func (s *Server) GetDefaultLoginTexts(ctx context.Context, req *admin_pb.GetDefaultLoginTextsRequest) (*admin_pb.GetDefaultLoginTextsResponse, error) {
msg, err := s.iam.GetDefaultLoginTexts(ctx, req.Language)
if err != nil {
return nil, err
}
return &admin_pb.GetDefaultLoginTextsResponse{
CustomText: text_grpc.CustomLoginTextToPb(msg),
}, nil
}
func (s *Server) GetCustomLoginTexts(ctx context.Context, req *admin_pb.GetCustomLoginTextsRequest) (*admin_pb.GetCustomLoginTextsResponse, error) {
msg, err := s.iam.GetCustomLoginTexts(ctx, req.Language)
if err != nil {
return nil, err
}
return &admin_pb.GetCustomLoginTextsResponse{
CustomText: text_grpc.CustomLoginTextToPb(msg),
}, nil
}
func (s *Server) SetCustomLoginText(ctx context.Context, req *admin_pb.SetCustomLoginTextsRequest) (*admin_pb.SetCustomLoginTextsResponse, error) {
result, err := s.command.SetCustomIAMLoginText(ctx, SetLoginTextToDomain(req))
if err != nil {
return nil, err
}
return &admin_pb.SetCustomLoginTextsResponse{
Details: object.ChangeToDetailsPb(
result.Sequence,
result.EventDate,
result.ResourceOwner,
),
}, nil
}

View File

@ -3,6 +3,7 @@ package admin
import (
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/api/grpc/text"
"github.com/caos/zitadel/internal/domain"
admin_pb "github.com/caos/zitadel/pkg/grpc/admin"
)
@ -81,3 +82,42 @@ func SetDomainClaimedCustomTextToDomain(msg *admin_pb.SetDefaultDomainClaimedMes
FooterText: msg.FooterText,
}
}
func SetLoginTextToDomain(req *admin_pb.SetCustomLoginTextsRequest) *domain.CustomLoginText {
langTag := language.Make(req.Language)
result := &domain.CustomLoginText{
Language: langTag,
}
result.SelectAccount = text.SelectAccountScreenTextPbToDomain(req.SelectAccountText)
result.Login = text.LoginScreenTextPbToDomain(req.LoginText)
result.Password = text.PasswordScreenTextPbToDomain(req.PasswordText)
result.UsernameChange = text.UsernameChangeScreenTextPbToDomain(req.UsernameChangeText)
result.UsernameChangeDone = text.UsernameChangeDoneScreenTextPbToDomain(req.UsernameChangeDoneText)
result.Password = text.PasswordScreenTextPbToDomain(req.PasswordText)
result.InitPassword = text.InitPasswordScreenTextPbToDomain(req.InitPasswordText)
result.InitPasswordDone = text.InitPasswordDoneScreenTextPbToDomain(req.InitPasswordDoneText)
result.EmailVerification = text.EmailVerificationScreenTextPbToDomain(req.EmailVerificationText)
result.EmailVerificationDone = text.EmailVerificationDoneScreenTextPbToDomain(req.EmailVerificationDoneText)
result.InitUser = text.InitializeUserScreenTextPbToDomain(req.InitializeUserText)
result.InitUserDone = text.InitializeDoneScreenTextPbToDomain(req.InitializeDoneText)
result.InitMFAPrompt = text.InitMFAPromptScreenTextPbToDomain(req.InitMfaPromptText)
result.InitMFAOTP = text.InitMFAOTPScreenTextPbToDomain(req.InitMfaOtpText)
result.InitMFAU2F = text.InitMFAU2FScreenTextPbToDomain(req.InitMfaU2FText)
result.InitMFADone = text.InitMFADoneScreenTextPbToDomain(req.InitMfaDoneText)
result.MFAProvider = text.MFAProvidersTextPbToDomain(req.MfaProvidersText)
result.VerifyMFAOTP = text.VerifyMFAOTPScreenTextPbToDomain(req.VerifyMfaOtpText)
result.VerifyMFAU2F = text.VerifyMFAU2FScreenTextPbToDomain(req.VerifyMfaU2FText)
result.Passwordless = text.PasswordlessScreenTextPbToDomain(req.PasswordlessText)
result.PasswordChange = text.PasswordChangeScreenTextPbToDomain(req.PasswordChangeText)
result.PasswordChangeDone = text.PasswordChangeDoneScreenTextPbToDomain(req.PasswordChangeDoneText)
result.PasswordResetDone = text.PasswordResetDoneScreenTextPbToDomain(req.PasswordResetDoneText)
result.RegisterOption = text.RegistrationOptionScreenTextPbToDomain(req.RegistrationOptionText)
result.RegistrationUser = text.RegistrationUserScreenTextPbToDomain(req.RegistrationUserText)
result.RegistrationOrg = text.RegistrationOrgScreenTextPbToDomain(req.RegistrationOrgText)
result.LinkingUsersDone = text.LinkingUserDoneScreenTextPbToDomain(req.LinkingUserDoneText)
result.ExternalNotFoundOption = text.ExternalUserNotFoundScreenTextPbToDomain(req.ExternalUserNotFoundText)
result.LoginSuccess = text.SuccessLoginScreenTextPbToDomain(req.SuccessLoginText)
result.LogoutDone = text.LogoutDoneScreenTextPbToDomain(req.LogoutText)
result.Footer = text.FooterTextPbToDomain(req.FooterText)
return result
}

View File

@ -251,3 +251,51 @@ func (s *Server) ResetCustomDomainClaimedMessageTextToDefault(ctx context.Contex
),
}, nil
}
func (s *Server) GetCustomLoginTexts(ctx context.Context, req *mgmt_pb.GetCustomLoginTextsRequest) (*mgmt_pb.GetCustomLoginTextsResponse, error) {
msg, err := s.org.GetLoginTexts(ctx, authz.GetCtxData(ctx).OrgID, req.Language)
if err != nil {
return nil, err
}
return &mgmt_pb.GetCustomLoginTextsResponse{
CustomText: text_grpc.CustomLoginTextToPb(msg),
}, nil
}
func (s *Server) GetDefaultLoginTexts(ctx context.Context, req *mgmt_pb.GetDefaultLoginTextsRequest) (*mgmt_pb.GetDefaultLoginTextsResponse, error) {
msg, err := s.org.GetDefaultLoginTexts(ctx, req.Language)
if err != nil {
return nil, err
}
return &mgmt_pb.GetDefaultLoginTextsResponse{
CustomText: text_grpc.CustomLoginTextToPb(msg),
}, nil
}
func (s *Server) SetCustomLoginText(ctx context.Context, req *mgmt_pb.SetCustomLoginTextsRequest) (*mgmt_pb.SetCustomLoginTextsResponse, error) {
result, err := s.command.SetOrgLoginText(ctx, authz.GetCtxData(ctx).OrgID, SetLoginCustomTextToDomain(req))
if err != nil {
return nil, err
}
return &mgmt_pb.SetCustomLoginTextsResponse{
Details: object.ChangeToDetailsPb(
result.Sequence,
result.EventDate,
result.ResourceOwner,
),
}, nil
}
func (s *Server) ResetCustomLoginTextToDefault(ctx context.Context, req *mgmt_pb.ResetCustomLoginTextsToDefaultRequest) (*mgmt_pb.ResetCustomLoginTextsToDefaultResponse, error) {
result, err := s.command.RemoveOrgLoginTexts(ctx, authz.GetCtxData(ctx).OrgID, language.Make(req.Language))
if err != nil {
return nil, err
}
return &mgmt_pb.ResetCustomLoginTextsToDefaultResponse{
Details: object.ChangeToDetailsPb(
result.Sequence,
result.EventDate,
result.ResourceOwner,
),
}, nil
}

View File

@ -3,6 +3,7 @@ package management
import (
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/api/grpc/text"
"github.com/caos/zitadel/internal/domain"
mgmt_pb "github.com/caos/zitadel/pkg/grpc/management"
)
@ -81,3 +82,40 @@ func SetDomainClaimedCustomTextToDomain(msg *mgmt_pb.SetCustomDomainClaimedMessa
FooterText: msg.FooterText,
}
}
func SetLoginCustomTextToDomain(req *mgmt_pb.SetCustomLoginTextsRequest) *domain.CustomLoginText {
langTag := language.Make(req.Language)
result := &domain.CustomLoginText{
Language: langTag,
}
result.SelectAccount = text.SelectAccountScreenTextPbToDomain(req.SelectAccountText)
result.Login = text.LoginScreenTextPbToDomain(req.LoginText)
result.Password = text.PasswordScreenTextPbToDomain(req.PasswordText)
result.UsernameChange = text.UsernameChangeScreenTextPbToDomain(req.UsernameChangeText)
result.UsernameChangeDone = text.UsernameChangeDoneScreenTextPbToDomain(req.UsernameChangeDoneText)
result.InitPassword = text.InitPasswordScreenTextPbToDomain(req.InitPasswordText)
result.InitPasswordDone = text.InitPasswordDoneScreenTextPbToDomain(req.InitPasswordDoneText)
result.EmailVerification = text.EmailVerificationScreenTextPbToDomain(req.EmailVerificationText)
result.EmailVerificationDone = text.EmailVerificationDoneScreenTextPbToDomain(req.EmailVerificationDoneText)
result.InitUser = text.InitializeUserScreenTextPbToDomain(req.InitializeUserText)
result.InitUserDone = text.InitializeDoneScreenTextPbToDomain(req.InitializeDoneText)
result.InitMFAPrompt = text.InitMFAPromptScreenTextPbToDomain(req.InitMfaPromptText)
result.InitMFAOTP = text.InitMFAOTPScreenTextPbToDomain(req.InitMfaOtpText)
result.InitMFAU2F = text.InitMFAU2FScreenTextPbToDomain(req.InitMfaU2FText)
result.InitMFADone = text.InitMFADoneScreenTextPbToDomain(req.InitMfaDoneText)
result.MFAProvider = text.MFAProvidersTextPbToDomain(req.MfaProvidersText)
result.VerifyMFAOTP = text.VerifyMFAOTPScreenTextPbToDomain(req.VerifyMfaOtpText)
result.VerifyMFAU2F = text.VerifyMFAU2FScreenTextPbToDomain(req.VerifyMfaU2FText)
result.Passwordless = text.PasswordlessScreenTextPbToDomain(req.PasswordlessText)
result.PasswordChange = text.PasswordChangeScreenTextPbToDomain(req.PasswordChangeText)
result.PasswordChangeDone = text.PasswordChangeDoneScreenTextPbToDomain(req.PasswordChangeDoneText)
result.PasswordResetDone = text.PasswordResetDoneScreenTextPbToDomain(req.PasswordResetDoneText)
result.RegisterOption = text.RegistrationOptionScreenTextPbToDomain(req.RegistrationOptionText)
result.RegistrationUser = text.RegistrationUserScreenTextPbToDomain(req.RegistrationUserText)
result.RegistrationOrg = text.RegistrationOrgScreenTextPbToDomain(req.RegistrationOrgText)
result.LoginSuccess = text.SuccessLoginScreenTextPbToDomain(req.SuccessLoginText)
result.LogoutDone = text.LogoutDoneScreenTextPbToDomain(req.LogoutText)
result.Footer = text.FooterTextPbToDomain(req.FooterText)
return result
}

View File

@ -2,6 +2,7 @@ package text
import (
"github.com/caos/zitadel/internal/api/grpc/object"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/iam/model"
text_pb "github.com/caos/zitadel/pkg/grpc/text"
)
@ -23,3 +24,812 @@ func ModelCustomMsgTextToPb(msg *model.MessageTextView) *text_pb.MessageCustomTe
),
}
}
func CustomLoginTextToPb(text *domain.CustomLoginText) *text_pb.LoginCustomText {
return &text_pb.LoginCustomText{
Details: object.ToViewDetailsPb(
text.Sequence,
text.CreationDate,
text.ChangeDate,
text.AggregateID,
),
SelectAccountText: SelectAccountScreenToPb(text.SelectAccount),
LoginText: LoginScreenTextToPb(text.Login),
PasswordText: PasswordScreenTextToPb(text.Password),
UsernameChangeText: UsernameChangeScreenTextToPb(text.UsernameChange),
UsernameChangeDoneText: UsernameChangeDoneScreenTextToPb(text.UsernameChangeDone),
InitPasswordText: InitPasswordScreenTextToPb(text.InitPassword),
InitPasswordDoneText: InitPasswordDoneScreenTextToPb(text.InitPasswordDone),
EmailVerificationText: EmailVerificationScreenTextToPb(text.EmailVerification),
EmailVerificationDoneText: EmailVerificationDoneScreenTextToPb(text.EmailVerificationDone),
InitializeUserText: InitializeUserScreenTextToPb(text.InitUser),
InitializeDoneText: InitializeUserDoneScreenTextToPb(text.InitUserDone),
InitMfaPromptText: InitMFAPromptScreenTextToPb(text.InitMFAPrompt),
InitMfaOtpText: InitMFAOTPScreenTextToPb(text.InitMFAOTP),
InitMfaU2FText: InitMFAU2FScreenTextToPb(text.InitMFAU2F),
InitMfaDoneText: InitMFADoneScreenTextToPb(text.InitMFADone),
MfaProvidersText: MFAProvidersTextToPb(text.MFAProvider),
VerifyMfaOtpText: VerifyMFAOTPScreenTextToPb(text.VerifyMFAOTP),
VerifyMfaU2FText: VerifyMFAU2FScreenTextToPb(text.VerifyMFAU2F),
PasswordlessText: PasswordlessScreenTextToPb(text.Passwordless),
PasswordChangeText: PasswordChangeScreenTextToPb(text.PasswordChange),
PasswordChangeDoneText: PasswordChangeDoneScreenTextToPb(text.PasswordChangeDone),
PasswordResetDoneText: PasswordResetDoneScreenTextToPb(text.PasswordResetDone),
RegistrationOptionText: RegistrationOptionScreenTextToPb(text.RegisterOption),
RegistrationUserText: RegistrationUserScreenTextToPb(text.RegistrationUser),
RegistrationOrgText: RegistrationOrgScreenTextToPb(text.RegistrationOrg),
LinkingUserDoneText: LinkingUserDoneScreenTextToPb(text.LinkingUsersDone),
ExternalUserNotFoundText: ExternalUserNotFoundScreenTextToPb(text.ExternalNotFoundOption),
SuccessLoginText: SuccessLoginScreenTextToPb(text.LoginSuccess),
LogoutText: LogoutDoneScreenTextToPb(text.LogoutDone),
FooterText: FooterTextToPb(text.Footer),
}
}
func SelectAccountScreenToPb(text domain.SelectAccountScreenText) *text_pb.SelectAccountScreenText {
return &text_pb.SelectAccountScreenText{
Title: text.Title,
Description: text.Description,
TitleLinkingProcess: text.TitleLinking,
DescriptionLinkingProcess: text.DescriptionLinking,
OtherUser: text.OtherUser,
SessionStateActive: text.SessionState0,
SessionStateInactive: text.SessionState1,
UserMustBeMemberOfOrg: text.MustBeMemberOfOrg,
}
}
func LoginScreenTextToPb(text domain.LoginScreenText) *text_pb.LoginScreenText {
return &text_pb.LoginScreenText{
Title: text.Title,
Description: text.Description,
TitleLinkingProcess: text.TitleLinking,
DescriptionLinkingProcess: text.DescriptionLinking,
LoginNameLabel: text.LoginNameLabel,
UserNamePlaceholder: text.UsernamePlaceholder,
LoginNamePlaceholder: text.LoginnamePlaceholder,
RegisterButtonText: text.RegisterButtonText,
NextButtonText: text.NextButtonText,
ExternalUserDescription: text.ExternalUserDescription,
UserMustBeMemberOfOrg: text.MustBeMemberOfOrg,
}
}
func PasswordScreenTextToPb(text domain.PasswordScreenText) *text_pb.PasswordScreenText {
return &text_pb.PasswordScreenText{
Title: text.Title,
Description: text.Description,
PasswordLabel: text.PasswordLabel,
ResetLinkText: text.ResetLinkText,
BackButtonText: text.BackButtonText,
NextButtonText: text.NextButtonText,
MinLength: text.MinLength,
HasUppercase: text.HasUppercase,
HasLowercase: text.HasLowercase,
HasNumber: text.HasNumber,
HasSymbol: text.HasSymbol,
Confirmation: text.Confirmation,
}
}
func UsernameChangeScreenTextToPb(text domain.UsernameChangeScreenText) *text_pb.UsernameChangeScreenText {
return &text_pb.UsernameChangeScreenText{
Title: text.Title,
Description: text.Description,
UsernameLabel: text.UsernameLabel,
CancelButtonText: text.CancelButtonText,
NextButtonText: text.NextButtonText,
}
}
func UsernameChangeDoneScreenTextToPb(text domain.UsernameChangeDoneScreenText) *text_pb.UsernameChangeDoneScreenText {
return &text_pb.UsernameChangeDoneScreenText{
Title: text.Title,
Description: text.Description,
NextButtonText: text.NextButtonText,
}
}
func InitPasswordScreenTextToPb(text domain.InitPasswordScreenText) *text_pb.InitPasswordScreenText {
return &text_pb.InitPasswordScreenText{
Title: text.Title,
Description: text.Description,
CodeLabel: text.CodeLabel,
NewPasswordLabel: text.NewPasswordLabel,
NewPasswordConfirmLabel: text.NewPasswordConfirmLabel,
NextButtonText: text.NextButtonText,
ResendButtonText: text.ResendButtonText,
}
}
func InitPasswordDoneScreenTextToPb(text domain.InitPasswordDoneScreenText) *text_pb.InitPasswordDoneScreenText {
return &text_pb.InitPasswordDoneScreenText{
Title: text.Title,
Description: text.Description,
NextButtonText: text.NextButtonText,
CancelButtonText: text.CancelButtonText,
}
}
func EmailVerificationScreenTextToPb(text domain.EmailVerificationScreenText) *text_pb.EmailVerificationScreenText {
return &text_pb.EmailVerificationScreenText{
Title: text.Title,
Description: text.Description,
CodeLabel: text.CodeLabel,
NextButtonText: text.NextButtonText,
ResendButtonText: text.ResendButtonText,
}
}
func EmailVerificationDoneScreenTextToPb(text domain.EmailVerificationDoneScreenText) *text_pb.EmailVerificationDoneScreenText {
return &text_pb.EmailVerificationDoneScreenText{
Title: text.Title,
Description: text.Description,
NextButtonText: text.NextButtonText,
CancelButtonText: text.CancelButtonText,
LoginButtonText: text.LoginButtonText,
}
}
func InitializeUserScreenTextToPb(text domain.InitializeUserScreenText) *text_pb.InitializeUserScreenText {
return &text_pb.InitializeUserScreenText{
Title: text.Title,
Description: text.Description,
CodeLabel: text.CodeLabel,
NewPasswordLabel: text.NewPasswordLabel,
NewPasswordConfirmLabel: text.NewPasswordConfirmLabel,
ResendButtonText: text.ResendButtonText,
NextButtonText: text.NextButtonText,
}
}
func InitializeUserDoneScreenTextToPb(text domain.InitializeUserDoneScreenText) *text_pb.InitializeUserDoneScreenText {
return &text_pb.InitializeUserDoneScreenText{
Title: text.Title,
Description: text.Description,
CancelButtonText: text.CancelButtonText,
NextButtonText: text.NextButtonText,
}
}
func InitMFAPromptScreenTextToPb(text domain.InitMFAPromptScreenText) *text_pb.InitMFAPromptScreenText {
return &text_pb.InitMFAPromptScreenText{
Title: text.Title,
Description: text.Description,
OtpOption: text.Provider0,
U2FOption: text.Provider1,
SkipButtonText: text.SkipButtonText,
NextButtonText: text.NextButtonText,
}
}
func InitMFAOTPScreenTextToPb(text domain.InitMFAOTPScreenText) *text_pb.InitMFAOTPScreenText {
return &text_pb.InitMFAOTPScreenText{
Title: text.Title,
Description: text.Description,
DescriptionOtp: text.OTPDescription,
SecretLabel: text.SecretLabel,
CodeLabel: text.CodeLabel,
NextButtonText: text.NextButtonText,
CancelButtonText: text.CancelButtonText,
}
}
func InitMFAU2FScreenTextToPb(text domain.InitMFAU2FScreenText) *text_pb.InitMFAU2FScreenText {
return &text_pb.InitMFAU2FScreenText{
Title: text.Title,
Description: text.Description,
TokenNameLabel: text.TokenNameLabel,
RegisterTokenButtonText: text.RegisterTokenButtonText,
NotSupported: text.NotSupported,
ErrorRetry: text.ErrorRetry,
}
}
func InitMFADoneScreenTextToPb(text domain.InitMFADoneScreenText) *text_pb.InitMFADoneScreenText {
return &text_pb.InitMFADoneScreenText{
Title: text.Title,
Description: text.Description,
CancelButtonText: text.CancelButtonText,
NextButtonText: text.NextButtonText,
}
}
func MFAProvidersTextToPb(text domain.MFAProvidersText) *text_pb.MFAProvidersText {
return &text_pb.MFAProvidersText{
ChooseOther: text.ChooseOther,
Otp: text.Provider0,
U2F: text.Provider1,
}
}
func VerifyMFAOTPScreenTextToPb(text domain.VerifyMFAOTPScreenText) *text_pb.VerifyMFAOTPScreenText {
return &text_pb.VerifyMFAOTPScreenText{
Title: text.Title,
Description: text.Description,
CodeLabel: text.CodeLabel,
NextButtonText: text.NextButtonText,
}
}
func VerifyMFAU2FScreenTextToPb(text domain.VerifyMFAU2FScreenText) *text_pb.VerifyMFAU2FScreenText {
return &text_pb.VerifyMFAU2FScreenText{
Title: text.Title,
Description: text.Description,
ValidateTokenText: text.ValidateTokenButtonText,
NotSupported: text.NotSupported,
ErrorRetry: text.ErrorRetry,
}
}
func PasswordlessScreenTextToPb(text domain.PasswordlessScreenText) *text_pb.PasswordlessScreenText {
return &text_pb.PasswordlessScreenText{
Title: text.Title,
Description: text.Description,
LoginWithPwButtonText: text.LoginWithPwButtonText,
ValidateTokenButtonText: text.ValidateTokenButtonText,
NotSupported: text.NotSupported,
ErrorRetry: text.ErrorRetry,
}
}
func PasswordChangeScreenTextToPb(text domain.PasswordChangeScreenText) *text_pb.PasswordChangeScreenText {
return &text_pb.PasswordChangeScreenText{
Title: text.Title,
Description: text.Description,
OldPasswordLabel: text.OldPasswordLabel,
NewPasswordLabel: text.NewPasswordLabel,
NewPasswordConfirmLabel: text.NewPasswordConfirmLabel,
CancelButtonText: text.CancelButtonText,
NextButtonText: text.NextButtonText,
}
}
func PasswordChangeDoneScreenTextToPb(text domain.PasswordChangeDoneScreenText) *text_pb.PasswordChangeDoneScreenText {
return &text_pb.PasswordChangeDoneScreenText{
Title: text.Title,
Description: text.Description,
NextButtonText: text.NextButtonText,
}
}
func PasswordResetDoneScreenTextToPb(text domain.PasswordResetDoneScreenText) *text_pb.PasswordResetDoneScreenText {
return &text_pb.PasswordResetDoneScreenText{
Title: text.Title,
Description: text.Description,
NextButtonText: text.NextButtonText,
}
}
func RegistrationOptionScreenTextToPb(text domain.RegistrationOptionScreenText) *text_pb.RegistrationOptionScreenText {
return &text_pb.RegistrationOptionScreenText{
Title: text.Title,
Description: text.Description,
UserNameButtonText: text.RegisterUsernamePasswordButtonText,
ExternalLoginDescription: text.ExternalLoginDescription,
}
}
func RegistrationUserScreenTextToPb(text domain.RegistrationUserScreenText) *text_pb.RegistrationUserScreenText {
return &text_pb.RegistrationUserScreenText{
Title: text.Title,
Description: text.Description,
DescriptionOrgRegister: text.DescriptionOrgRegister,
FirstnameLabel: text.FirstnameLabel,
LastnameLabel: text.LastnameLabel,
EmailLabel: text.EmailLabel,
UsernameLabel: text.UsernameLabel,
LanguageLabel: text.LanguageLabel,
GenderLabel: text.GenderLabel,
PasswordLabel: text.PasswordLabel,
PasswordConfirmLabel: text.PasswordConfirmLabel,
TosAndPrivacyLabel: text.TOSAndPrivacyLabel,
TosConfirm: text.TOSConfirm,
TosLink: text.TOSLink,
TosLinkText: text.TOSLinkText,
PrivacyConfirm: text.PrivacyConfirm,
PrivacyLink: text.PrivacyLink,
PrivacyLinkText: text.PrivacyLinkText,
ExternalLoginDescription: text.ExternalLoginDescription,
NextButtonText: text.NextButtonText,
BackButtonText: text.BackButtonText,
}
}
func RegistrationOrgScreenTextToPb(text domain.RegistrationOrgScreenText) *text_pb.RegistrationOrgScreenText {
return &text_pb.RegistrationOrgScreenText{
Title: text.Title,
Description: text.Description,
OrgnameLabel: text.OrgNameLabel,
FirstnameLabel: text.FirstnameLabel,
LastnameLabel: text.LastnameLabel,
EmailLabel: text.EmailLabel,
UsernameLabel: text.UsernameLabel,
PasswordLabel: text.PasswordLabel,
PasswordConfirmLabel: text.PasswordConfirmLabel,
TosAndPrivacyLabel: text.TOSAndPrivacyLabel,
TosConfirm: text.TOSConfirm,
TosLink: text.TOSLink,
TosLinkText: text.TOSLinkText,
PrivacyConfirm: text.PrivacyConfirm,
PrivacyLink: text.PrivacyLink,
PrivacyLinkText: text.PrivacyLinkText,
ExternalLoginDescription: text.ExternalLoginDescription,
SaveButtonText: text.SaveButtonText,
}
}
func LinkingUserDoneScreenTextToPb(text domain.LinkingUserDoneScreenText) *text_pb.LinkingUserDoneScreenText {
return &text_pb.LinkingUserDoneScreenText{
Title: text.Title,
Description: text.Description,
CancelButtonText: text.CancelButtonText,
NextButtonText: text.NextButtonText,
}
}
func ExternalUserNotFoundScreenTextToPb(text domain.ExternalUserNotFoundScreenText) *text_pb.ExternalUserNotFoundScreenText {
return &text_pb.ExternalUserNotFoundScreenText{
Title: text.Title,
Description: text.Description,
LinkButtonText: text.LinkButtonText,
AutoRegisterButtonText: text.AutoRegisterButtonText,
}
}
func SuccessLoginScreenTextToPb(text domain.SuccessLoginScreenText) *text_pb.SuccessLoginScreenText {
return &text_pb.SuccessLoginScreenText{
Title: text.Title,
AutoRedirectDescription: text.AutoRedirectDescription,
RedirectedDescription: text.RedirectedDescription,
NextButtonText: text.NextButtonText,
}
}
func LogoutDoneScreenTextToPb(text domain.LogoutDoneScreenText) *text_pb.LogoutDoneScreenText {
return &text_pb.LogoutDoneScreenText{
Title: text.Title,
Description: text.Description,
LoginButtonText: text.LoginButtonText,
}
}
func FooterTextToPb(text domain.FooterText) *text_pb.FooterText {
return &text_pb.FooterText{
Tos: text.TOS,
TosLink: text.TOSLink,
PrivacyPolicy: text.PrivacyPolicy,
PrivacyPolicyLink: text.PrivacyPolicyLink,
Help: text.Help,
HelpLink: text.HelpLink,
}
}
func SelectAccountScreenTextPbToDomain(text *text_pb.SelectAccountScreenText) domain.SelectAccountScreenText {
if text == nil {
return domain.SelectAccountScreenText{}
}
return domain.SelectAccountScreenText{
Title: text.Title,
Description: text.Description,
TitleLinking: text.TitleLinkingProcess,
DescriptionLinking: text.DescriptionLinkingProcess,
OtherUser: text.OtherUser,
SessionState0: text.SessionStateActive,
SessionState1: text.SessionStateInactive,
MustBeMemberOfOrg: text.UserMustBeMemberOfOrg,
}
}
func LoginScreenTextPbToDomain(text *text_pb.LoginScreenText) domain.LoginScreenText {
if text == nil {
return domain.LoginScreenText{}
}
return domain.LoginScreenText{
Title: text.Title,
Description: text.Description,
TitleLinking: text.TitleLinkingProcess,
DescriptionLinking: text.DescriptionLinkingProcess,
LoginNameLabel: text.LoginNameLabel,
UsernamePlaceholder: text.UserNamePlaceholder,
LoginnamePlaceholder: text.LoginNamePlaceholder,
RegisterButtonText: text.RegisterButtonText,
NextButtonText: text.NextButtonText,
ExternalUserDescription: text.ExternalUserDescription,
MustBeMemberOfOrg: text.UserMustBeMemberOfOrg,
}
}
func PasswordScreenTextPbToDomain(text *text_pb.PasswordScreenText) domain.PasswordScreenText {
if text == nil {
return domain.PasswordScreenText{}
}
return domain.PasswordScreenText{
Title: text.Title,
Description: text.Description,
PasswordLabel: text.PasswordLabel,
ResetLinkText: text.ResetLinkText,
BackButtonText: text.BackButtonText,
NextButtonText: text.NextButtonText,
MinLength: text.MinLength,
HasUppercase: text.HasUppercase,
HasLowercase: text.HasLowercase,
HasNumber: text.HasNumber,
HasSymbol: text.HasSymbol,
Confirmation: text.Confirmation,
}
}
func UsernameChangeScreenTextPbToDomain(text *text_pb.UsernameChangeScreenText) domain.UsernameChangeScreenText {
if text == nil {
return domain.UsernameChangeScreenText{}
}
return domain.UsernameChangeScreenText{
Title: text.Title,
Description: text.Description,
UsernameLabel: text.UsernameLabel,
CancelButtonText: text.CancelButtonText,
NextButtonText: text.NextButtonText,
}
}
func UsernameChangeDoneScreenTextPbToDomain(text *text_pb.UsernameChangeDoneScreenText) domain.UsernameChangeDoneScreenText {
if text == nil {
return domain.UsernameChangeDoneScreenText{}
}
return domain.UsernameChangeDoneScreenText{
Title: text.Title,
Description: text.Description,
NextButtonText: text.NextButtonText,
}
}
func InitPasswordScreenTextPbToDomain(text *text_pb.InitPasswordScreenText) domain.InitPasswordScreenText {
if text == nil {
return domain.InitPasswordScreenText{}
}
return domain.InitPasswordScreenText{
Title: text.Title,
Description: text.Description,
CodeLabel: text.CodeLabel,
NewPasswordLabel: text.NewPasswordLabel,
NewPasswordConfirmLabel: text.NewPasswordConfirmLabel,
NextButtonText: text.NextButtonText,
ResendButtonText: text.ResendButtonText,
}
}
func InitPasswordDoneScreenTextPbToDomain(text *text_pb.InitPasswordDoneScreenText) domain.InitPasswordDoneScreenText {
if text == nil {
return domain.InitPasswordDoneScreenText{}
}
return domain.InitPasswordDoneScreenText{
Title: text.Title,
Description: text.Description,
NextButtonText: text.NextButtonText,
CancelButtonText: text.CancelButtonText,
}
}
func EmailVerificationScreenTextPbToDomain(text *text_pb.EmailVerificationScreenText) domain.EmailVerificationScreenText {
if text == nil {
return domain.EmailVerificationScreenText{}
}
return domain.EmailVerificationScreenText{
Title: text.Title,
Description: text.Description,
CodeLabel: text.CodeLabel,
NextButtonText: text.NextButtonText,
ResendButtonText: text.ResendButtonText,
}
}
func EmailVerificationDoneScreenTextPbToDomain(text *text_pb.EmailVerificationDoneScreenText) domain.EmailVerificationDoneScreenText {
if text == nil {
return domain.EmailVerificationDoneScreenText{}
}
return domain.EmailVerificationDoneScreenText{
Title: text.Title,
Description: text.Description,
NextButtonText: text.NextButtonText,
CancelButtonText: text.CancelButtonText,
LoginButtonText: text.LoginButtonText,
}
}
func InitializeUserScreenTextPbToDomain(text *text_pb.InitializeUserScreenText) domain.InitializeUserScreenText {
if text == nil {
return domain.InitializeUserScreenText{}
}
return domain.InitializeUserScreenText{
Title: text.Title,
Description: text.Description,
CodeLabel: text.CodeLabel,
NewPasswordLabel: text.NewPasswordLabel,
NewPasswordConfirmLabel: text.NewPasswordConfirmLabel,
ResendButtonText: text.ResendButtonText,
NextButtonText: text.NextButtonText,
}
}
func InitializeDoneScreenTextPbToDomain(text *text_pb.InitializeUserDoneScreenText) domain.InitializeUserDoneScreenText {
if text == nil {
return domain.InitializeUserDoneScreenText{}
}
return domain.InitializeUserDoneScreenText{
Title: text.Title,
Description: text.Description,
CancelButtonText: text.CancelButtonText,
NextButtonText: text.NextButtonText,
}
}
func InitMFAPromptScreenTextPbToDomain(text *text_pb.InitMFAPromptScreenText) domain.InitMFAPromptScreenText {
if text == nil {
return domain.InitMFAPromptScreenText{}
}
return domain.InitMFAPromptScreenText{
Title: text.Title,
Description: text.Description,
Provider0: text.OtpOption,
Provider1: text.U2FOption,
SkipButtonText: text.SkipButtonText,
NextButtonText: text.NextButtonText,
}
}
func InitMFAOTPScreenTextPbToDomain(text *text_pb.InitMFAOTPScreenText) domain.InitMFAOTPScreenText {
if text == nil {
return domain.InitMFAOTPScreenText{}
}
return domain.InitMFAOTPScreenText{
Title: text.Title,
Description: text.Description,
OTPDescription: text.DescriptionOtp,
SecretLabel: text.SecretLabel,
CodeLabel: text.CodeLabel,
NextButtonText: text.NextButtonText,
CancelButtonText: text.CancelButtonText,
}
}
func InitMFAU2FScreenTextPbToDomain(text *text_pb.InitMFAU2FScreenText) domain.InitMFAU2FScreenText {
if text == nil {
return domain.InitMFAU2FScreenText{}
}
return domain.InitMFAU2FScreenText{
Title: text.Title,
Description: text.Description,
TokenNameLabel: text.TokenNameLabel,
RegisterTokenButtonText: text.RegisterTokenButtonText,
NotSupported: text.NotSupported,
ErrorRetry: text.ErrorRetry,
}
}
func InitMFADoneScreenTextPbToDomain(text *text_pb.InitMFADoneScreenText) domain.InitMFADoneScreenText {
if text == nil {
return domain.InitMFADoneScreenText{}
}
return domain.InitMFADoneScreenText{
Title: text.Title,
Description: text.Description,
CancelButtonText: text.CancelButtonText,
NextButtonText: text.NextButtonText,
}
}
func MFAProvidersTextPbToDomain(text *text_pb.MFAProvidersText) domain.MFAProvidersText {
if text == nil {
return domain.MFAProvidersText{}
}
return domain.MFAProvidersText{
ChooseOther: text.ChooseOther,
Provider0: text.Otp,
Provider1: text.U2F,
}
}
func VerifyMFAOTPScreenTextPbToDomain(text *text_pb.VerifyMFAOTPScreenText) domain.VerifyMFAOTPScreenText {
if text == nil {
return domain.VerifyMFAOTPScreenText{}
}
return domain.VerifyMFAOTPScreenText{
Title: text.Title,
Description: text.Description,
CodeLabel: text.CodeLabel,
NextButtonText: text.NextButtonText,
}
}
func VerifyMFAU2FScreenTextPbToDomain(text *text_pb.VerifyMFAU2FScreenText) domain.VerifyMFAU2FScreenText {
if text == nil {
return domain.VerifyMFAU2FScreenText{}
}
return domain.VerifyMFAU2FScreenText{
Title: text.Title,
Description: text.Description,
ValidateTokenButtonText: text.ValidateTokenText,
NotSupported: text.NotSupported,
ErrorRetry: text.ErrorRetry,
}
}
func PasswordlessScreenTextPbToDomain(text *text_pb.PasswordlessScreenText) domain.PasswordlessScreenText {
if text == nil {
return domain.PasswordlessScreenText{}
}
return domain.PasswordlessScreenText{
Title: text.Title,
Description: text.Description,
LoginWithPwButtonText: text.LoginWithPwButtonText,
ValidateTokenButtonText: text.ValidateTokenButtonText,
NotSupported: text.NotSupported,
ErrorRetry: text.ErrorRetry,
}
}
func PasswordChangeScreenTextPbToDomain(text *text_pb.PasswordChangeScreenText) domain.PasswordChangeScreenText {
if text == nil {
return domain.PasswordChangeScreenText{}
}
return domain.PasswordChangeScreenText{
Title: text.Title,
Description: text.Description,
OldPasswordLabel: text.OldPasswordLabel,
NewPasswordLabel: text.NewPasswordLabel,
NewPasswordConfirmLabel: text.NewPasswordConfirmLabel,
CancelButtonText: text.CancelButtonText,
NextButtonText: text.NextButtonText,
}
}
func PasswordChangeDoneScreenTextPbToDomain(text *text_pb.PasswordChangeDoneScreenText) domain.PasswordChangeDoneScreenText {
if text == nil {
return domain.PasswordChangeDoneScreenText{}
}
return domain.PasswordChangeDoneScreenText{
Title: text.Title,
Description: text.Description,
NextButtonText: text.NextButtonText,
}
}
func PasswordResetDoneScreenTextPbToDomain(text *text_pb.PasswordResetDoneScreenText) domain.PasswordResetDoneScreenText {
if text == nil {
return domain.PasswordResetDoneScreenText{}
}
return domain.PasswordResetDoneScreenText{
Title: text.Title,
Description: text.Description,
NextButtonText: text.NextButtonText,
}
}
func RegistrationOptionScreenTextPbToDomain(text *text_pb.RegistrationOptionScreenText) domain.RegistrationOptionScreenText {
if text == nil {
return domain.RegistrationOptionScreenText{}
}
return domain.RegistrationOptionScreenText{
Title: text.Title,
Description: text.Description,
RegisterUsernamePasswordButtonText: text.UserNameButtonText,
ExternalLoginDescription: text.ExternalLoginDescription,
}
}
func RegistrationUserScreenTextPbToDomain(text *text_pb.RegistrationUserScreenText) domain.RegistrationUserScreenText {
if text == nil {
return domain.RegistrationUserScreenText{}
}
return domain.RegistrationUserScreenText{
Title: text.Title,
Description: text.Description,
DescriptionOrgRegister: text.DescriptionOrgRegister,
FirstnameLabel: text.FirstnameLabel,
LastnameLabel: text.LastnameLabel,
EmailLabel: text.EmailLabel,
UsernameLabel: text.UsernameLabel,
LanguageLabel: text.LanguageLabel,
GenderLabel: text.GenderLabel,
PasswordLabel: text.PasswordLabel,
PasswordConfirmLabel: text.PasswordConfirmLabel,
TOSAndPrivacyLabel: text.TosAndPrivacyLabel,
TOSConfirm: text.TosConfirm,
TOSLink: text.TosLink,
TOSLinkText: text.TosLinkText,
PrivacyConfirm: text.PrivacyConfirm,
PrivacyLink: text.PrivacyLink,
PrivacyLinkText: text.PrivacyLinkText,
ExternalLoginDescription: text.ExternalLoginDescription,
NextButtonText: text.NextButtonText,
BackButtonText: text.BackButtonText,
}
}
func RegistrationOrgScreenTextPbToDomain(text *text_pb.RegistrationOrgScreenText) domain.RegistrationOrgScreenText {
if text == nil {
return domain.RegistrationOrgScreenText{}
}
return domain.RegistrationOrgScreenText{
Title: text.Title,
Description: text.Description,
OrgNameLabel: text.OrgnameLabel,
FirstnameLabel: text.FirstnameLabel,
LastnameLabel: text.LastnameLabel,
EmailLabel: text.EmailLabel,
UsernameLabel: text.UsernameLabel,
PasswordLabel: text.PasswordLabel,
PasswordConfirmLabel: text.PasswordConfirmLabel,
TOSAndPrivacyLabel: text.TosAndPrivacyLabel,
TOSConfirm: text.TosConfirm,
TOSLink: text.TosLink,
TOSLinkText: text.TosLinkText,
PrivacyConfirm: text.PrivacyConfirm,
PrivacyLink: text.PrivacyLink,
PrivacyLinkText: text.PrivacyLinkText,
ExternalLoginDescription: text.ExternalLoginDescription,
SaveButtonText: text.SaveButtonText,
}
}
func LinkingUserDoneScreenTextPbToDomain(text *text_pb.LinkingUserDoneScreenText) domain.LinkingUserDoneScreenText {
if text == nil {
return domain.LinkingUserDoneScreenText{}
}
return domain.LinkingUserDoneScreenText{
Title: text.Title,
Description: text.Description,
CancelButtonText: text.CancelButtonText,
NextButtonText: text.NextButtonText,
}
}
func ExternalUserNotFoundScreenTextPbToDomain(text *text_pb.ExternalUserNotFoundScreenText) domain.ExternalUserNotFoundScreenText {
if text == nil {
return domain.ExternalUserNotFoundScreenText{}
}
return domain.ExternalUserNotFoundScreenText{
Title: text.Title,
Description: text.Description,
LinkButtonText: text.LinkButtonText,
AutoRegisterButtonText: text.AutoRegisterButtonText,
}
}
func SuccessLoginScreenTextPbToDomain(text *text_pb.SuccessLoginScreenText) domain.SuccessLoginScreenText {
if text == nil {
return domain.SuccessLoginScreenText{}
}
return domain.SuccessLoginScreenText{
Title: text.Title,
AutoRedirectDescription: text.AutoRedirectDescription,
RedirectedDescription: text.RedirectedDescription,
NextButtonText: text.NextButtonText,
}
}
func LogoutDoneScreenTextPbToDomain(text *text_pb.LogoutDoneScreenText) domain.LogoutDoneScreenText {
if text == nil {
return domain.LogoutDoneScreenText{}
}
return domain.LogoutDoneScreenText{
Title: text.Title,
Description: text.Description,
LoginButtonText: text.LoginButtonText,
}
}
func FooterTextPbToDomain(text *text_pb.FooterText) domain.FooterText {
if text == nil {
return domain.FooterText{}
}
return domain.FooterText{
TOS: text.Tos,
TOSLink: text.TosLink,
PrivacyPolicy: text.PrivacyPolicy,
PrivacyPolicyLink: text.PrivacyPolicyLink,
Help: text.Help,
HelpLink: text.HelpLink,
}
}

View File

@ -157,7 +157,7 @@ func (repo *AuthRequestRepo) AuthRequestByCode(ctx context.Context, code string)
if err != nil {
return nil, err
}
err = repo.fillLoginPolicy(ctx, request)
err = repo.fillPolicies(ctx, request)
if err != nil {
return nil, err
}
@ -399,7 +399,7 @@ func (repo *AuthRequestRepo) getAuthRequest(ctx context.Context, id, userAgentID
if request.AgentID != userAgentID {
return nil, errors.ThrowPermissionDenied(nil, "EVENT-adk13", "Errors.AuthRequest.UserAgentNotCorresponding")
}
err = repo.fillLoginPolicy(ctx, request)
err = repo.fillPolicies(ctx, request)
if err != nil {
return nil, err
}
@ -423,7 +423,7 @@ func (repo *AuthRequestRepo) getLoginPolicyAndIDPProviders(ctx context.Context,
return policy.ToLoginPolicyDomain(), providers, nil
}
func (repo *AuthRequestRepo) fillLoginPolicy(ctx context.Context, request *domain.AuthRequest) error {
func (repo *AuthRequestRepo) fillPolicies(ctx context.Context, request *domain.AuthRequest) error {
orgID := request.RequestedOrgID
if orgID == "" {
orgID = request.UserOrgID
@ -450,6 +450,16 @@ func (repo *AuthRequestRepo) fillLoginPolicy(ctx context.Context, request *domai
return err
}
request.LabelPolicy = labelPolicy
defaultLoginTranslations, err := repo.getLoginTexts(ctx, domain.IAMID)
if err != nil {
return err
}
request.DefaultTranslations = defaultLoginTranslations
orgLoginTranslations, err := repo.getLoginTexts(ctx, orgID)
if err != nil {
return err
}
request.OrgTranslations = orgLoginTranslations
return nil
}
@ -754,6 +764,14 @@ func (repo *AuthRequestRepo) getLabelPolicy(ctx context.Context, orgID string) (
return policy.ToDomain(), err
}
func (repo *AuthRequestRepo) getLoginTexts(ctx context.Context, aggregateID string) ([]*domain.CustomText, error) {
loginTexts, err := repo.View.CustomTextsByAggregateIDAndTemplate(aggregateID, domain.LoginCustomText)
if err != nil {
return nil, err
}
return iam_view_model.CustomTextViewsToDomain(loginTexts), err
}
func setOrgID(orgViewProvider orgViewProvider, request *domain.AuthRequest) error {
primaryDomain := request.GetScopeOrgPrimaryDomain()
if primaryDomain == "" {

View File

@ -0,0 +1,121 @@
package handler
import (
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query"
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
type CustomText struct {
handler
subscription *v1.Subscription
}
func newCustomText(handler handler) *CustomText {
h := &CustomText{
handler: handler,
}
h.subscribe()
return h
}
func (m *CustomText) subscribe() {
m.subscription = m.es.Subscribe(m.AggregateTypes()...)
go func() {
for event := range m.subscription.Events {
query.ReduceEvent(m, event)
}
}()
}
const (
customTextTable = "auth.custom_texts"
)
func (m *CustomText) ViewModel() string {
return customTextTable
}
func (_ *CustomText) AggregateTypes() []es_models.AggregateType {
return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
}
func (p *CustomText) CurrentSequence() (uint64, error) {
sequence, err := p.view.GetLatestCustomTextSequence()
if err != nil {
return 0, err
}
return sequence.CurrentSequence, nil
}
func (m *CustomText) EventQuery() (*es_models.SearchQuery, error) {
sequence, err := m.view.GetLatestCustomTextSequence()
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
func (m *CustomText) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
err = m.processCustomText(event)
}
return err
}
func (m *CustomText) processCustomText(event *es_models.Event) (err error) {
customText := new(iam_model.CustomTextView)
switch event.Type {
case iam_es_model.CustomTextSet, model.CustomTextSet:
text := new(iam_model.CustomTextView)
err = text.SetData(event)
if err != nil {
return err
}
customText, err = m.view.CustomTextByIDs(event.AggregateID, text.Template, text.Key, text.Language)
if err != nil && !caos_errs.IsNotFound(err) {
return err
}
if caos_errs.IsNotFound(err) {
err = nil
customText = new(iam_model.CustomTextView)
customText.Language = text.Language
customText.Template = text.Template
customText.CreationDate = event.CreationDate
}
err = customText.AppendEvent(event)
case iam_es_model.CustomTextRemoved, model.CustomTextRemoved:
text := new(iam_model.CustomTextView)
err = text.SetData(event)
if err != nil {
return err
}
return m.view.DeleteCustomText(event.AggregateID, text.Template, text.Language, event)
default:
return m.view.ProcessedCustomTextSequence(event)
}
if err != nil {
return err
}
return m.view.PutCustomText(customText, event)
}
func (m *CustomText) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-3m0fs", "id", event.AggregateID).WithError(err).Warn("something went wrong in custom text handler")
return spooler.HandleError(event, err, m.view.GetLatestCustomTextFailedEvent, m.view.ProcessedCustomTextFailedEvent, m.view.ProcessedCustomTextSequence, m.errorCountUntilSkip)
}
func (o *CustomText) OnSuccess() error {
return spooler.HandleSuccess(o.view.UpdateCustomTextSpoolerRunTimestamp)
}

View File

@ -71,6 +71,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
newFeatures(handler{view, bulkLimit, configs.cycleDuration("Features"), errorCount, es}),
newRefreshToken(handler{view, bulkLimit, configs.cycleDuration("RefreshToken"), errorCount, es}),
newPrivacyPolicy(handler{view, bulkLimit, configs.cycleDuration("PrivacyPolicy"), errorCount, es}),
newCustomText(handler{view, bulkLimit, configs.cycleDuration("CustomTexts"), errorCount, es}),
}
}

View File

@ -110,7 +110,7 @@ func (m *LabelPolicy) processLabelPolicy(event *models.Event) (err error) {
}
func (m *LabelPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in label policy handler")
logging.LogWithFields("SPOOL-2ff7s", "id", event.AggregateID).WithError(err).Warn("something went wrong in label policy handler")
return spooler.HandleError(event, err, m.view.GetLatestLabelPolicyFailedEvent, m.view.ProcessedLabelPolicyFailedEvent, m.view.ProcessedLabelPolicySequence, m.errorCountUntilSkip)
}

View File

@ -97,7 +97,7 @@ func (p *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *es_mod
}
func (p *PasswordComplexityPolicy) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordComplexity policy handler")
logging.LogWithFields("SPOOL-6M99S", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordComplexity policy handler")
return spooler.HandleError(event, err, p.view.GetLatestPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicySequence, p.errorCountUntilSkip)
}

View File

@ -0,0 +1,61 @@
package view
import (
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
)
const (
customTextTable = "auth.custom_texts"
)
func (v *View) CustomTextByIDs(aggregateID, template, lang, key string) (*model.CustomTextView, error) {
return view.CustomTextByIDs(v.Db, customTextTable, aggregateID, template, lang, key)
}
func (v *View) CustomTextsByAggregateIDAndTemplateAndLand(aggregateID, template, lang string) ([]*model.CustomTextView, error) {
return view.GetCustomTexts(v.Db, customTextTable, aggregateID, template, lang)
}
func (v *View) CustomTextsByAggregateIDAndTemplate(aggregateID, template string) ([]*model.CustomTextView, error) {
return view.GetCustomTextsByAggregateIDAndTemplate(v.Db, customTextTable, aggregateID, template)
}
func (v *View) PutCustomText(template *model.CustomTextView, event *models.Event) error {
err := view.PutCustomText(v.Db, customTextTable, template)
if err != nil {
return err
}
return v.ProcessedCustomTextSequence(event)
}
func (v *View) DeleteCustomText(aggregateID, textType, lang string, event *models.Event) error {
err := view.DeleteCustomText(v.Db, customTextTable, aggregateID, textType, lang)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedCustomTextSequence(event)
}
func (v *View) GetLatestCustomTextSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(customTextTable)
}
func (v *View) ProcessedCustomTextSequence(event *models.Event) error {
return v.saveCurrentSequence(customTextTable, event)
}
func (v *View) UpdateCustomTextSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(customTextTable)
}
func (v *View) GetLatestCustomTextFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
return v.latestFailedEvent(customTextTable, sequence)
}
func (v *View) ProcessedCustomTextFailedEvent(failedEvent *global_view.FailedEvent) error {
return v.saveFailedEvent(failedEvent)
}

View File

@ -0,0 +1,969 @@
package command
import (
"context"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/org"
)
func (c *Commands) createAllLoginTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
events = append(events, c.createSelectLoginTextEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createLoginTextEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createPasswordTextEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createUsernameChangeTextEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createUsernameChangeDoneTextEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createPasswordInitTextEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createPasswordInitDoneTextEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createEmailVerificationTextEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createEmailVerificationDoneTextEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createInitUserEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createInitUserDoneEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createInitMFAPromptEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createInitMFAOTPEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createInitMFAU2FEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createInitMFADoneEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.crateMFAProviderEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createVerifyMFAOTPEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createVerifyMFAU2FEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createPasswordlessEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createPasswordChangeEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createPasswordChangeDoneEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createPasswordResetDoneEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createRegistrationOptionEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createRegistrationUserEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createRegistrationOrgEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createLinkingUserEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createExternalUserNotFoundEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createSuccessLoginEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createLogoutDoneEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createFooterTextEvents(ctx, agg, existingText, text, defaultText)...)
return events
}
func (c *Commands) createSelectLoginTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountTitle, existingText.SelectAccountTitle, text.SelectAccount.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountDescription, existingText.SelectAccountDescription, text.SelectAccount.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountTitleLinkingProcess, existingText.SelectAccountTitleLinkingProcess, text.SelectAccount.TitleLinking, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountDescriptionLinkingProcess, existingText.SelectAccountDescriptionLinkingProcess, text.SelectAccount.DescriptionLinking, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountOtherUser, existingText.SelectAccountOtherUser, text.SelectAccount.OtherUser, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountSessionStateActive, existingText.SelectAccountSessionStateActive, text.SelectAccount.SessionState0, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountSessionStateInactive, existingText.SelectAccountSessionStateInactive, text.SelectAccount.SessionState1, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySelectAccountUserMustBeMemberOfOrg, existingText.SelectAccountUserMustBeMemberOfOrg, text.SelectAccount.MustBeMemberOfOrg, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createLoginTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginTitle, existingText.LoginTitle, text.Login.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginDescription, existingText.LoginDescription, text.Login.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginTitleLinkingProcess, existingText.LoginTitleLinkingProcess, text.Login.TitleLinking, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginDescriptionLinkingProcess, existingText.LoginDescriptionLinkingProcess, text.Login.DescriptionLinking, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginNameLabel, existingText.LoginNameLabel, text.Login.LoginNameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginUsernamePlaceHolder, existingText.LoginUsernamePlaceholder, text.Login.UsernamePlaceholder, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginLoginnamePlaceHolder, existingText.LoginLoginnamePlaceholder, text.Login.LoginnamePlaceholder, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginRegisterButtonText, existingText.LoginRegisterButtonText, text.Login.RegisterButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginNextButtonText, existingText.LoginNextButtonText, text.Login.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginExternalUserDescription, existingText.LoginExternalUserDescription, text.Login.ExternalUserDescription, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLoginUserMustBeMemberOfOrg, existingText.LoginUserMustBeMemberOfOrg, text.Login.MustBeMemberOfOrg, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createPasswordTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordTitle, existingText.PasswordTitle, text.Password.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordDescription, existingText.PasswordDescription, text.Password.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordLabel, existingText.PasswordLabel, text.Password.PasswordLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetLinkText, existingText.PasswordResetLinkText, text.Password.ResetLinkText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordBackButtonText, existingText.PasswordBackButtonText, text.Password.BackButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordNextButtonText, existingText.PasswordNextButtonText, text.Password.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordMinLength, existingText.PasswordMinLength, text.Password.MinLength, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasUppercase, existingText.PasswordHasUppercase, text.Password.HasUppercase, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasLowercase, existingText.PasswordHasLowercase, text.Password.HasLowercase, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasNumber, existingText.PasswordHasNumber, text.Password.HasNumber, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordHasSymbol, existingText.PasswordHasSymbol, text.Password.HasSymbol, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordConfirmation, existingText.PasswordConfirmation, text.Password.Confirmation, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createUsernameChangeTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeTitle, existingText.UsernameChangeTitle, text.UsernameChange.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDescription, existingText.UsernameChangeDescription, text.UsernameChange.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeUsernameLabel, existingText.UsernameChangeUsernameLabel, text.UsernameChange.UsernameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeCancelButtonText, existingText.UsernameChangeCancelButtonText, text.UsernameChange.CancelButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeNextButtonText, existingText.UsernameChangeNextButtonText, text.UsernameChange.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createUsernameChangeDoneTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDoneTitle, existingText.UsernameChangeDoneTitle, text.UsernameChangeDone.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDoneDescription, existingText.UsernameChangeDoneDescription, text.UsernameChangeDone.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyUsernameChangeDoneNextButtonText, existingText.UsernameChangeDoneNextButtonText, text.UsernameChangeDone.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createPasswordInitTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordTitle, existingText.InitPasswordTitle, text.InitPassword.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDescription, existingText.InitPasswordDescription, text.InitPassword.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordCodeLabel, existingText.InitPasswordCodeLabel, text.InitPassword.CodeLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordNewPasswordLabel, existingText.InitPasswordNewPasswordLabel, text.InitPassword.NewPasswordLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordNewPasswordConfirmLabel, existingText.InitPasswordNewPasswordConfirmLabel, text.InitPassword.NewPasswordConfirmLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordNextButtonText, existingText.InitPasswordNextButtonText, text.InitPassword.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordResendButtonText, existingText.InitPasswordResendButtonText, text.InitPassword.ResendButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createPasswordInitDoneTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneTitle, existingText.InitPasswordDoneTitle, text.InitPasswordDone.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneDescription, existingText.InitPasswordDoneDescription, text.InitPasswordDone.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneNextButtonText, existingText.InitPasswordDoneNextButtonText, text.InitPasswordDone.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitPasswordDoneCancelButtonText, existingText.InitPasswordDoneCancelButtonText, text.InitPasswordDone.CancelButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createEmailVerificationTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationTitle, existingText.EmailVerificationTitle, text.EmailVerification.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDescription, existingText.EmailVerificationDescription, text.EmailVerification.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationCodeLabel, existingText.EmailVerificationCodeLabel, text.EmailVerification.CodeLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationNextButtonText, existingText.EmailVerificationNextButtonText, text.EmailVerification.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationResendButtonText, existingText.EmailVerificationResendButtonText, text.EmailVerification.ResendButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createEmailVerificationDoneTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneTitle, existingText.EmailVerificationDoneTitle, text.EmailVerificationDone.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneDescription, existingText.EmailVerificationDoneDescription, text.EmailVerificationDone.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneNextButtonText, existingText.EmailVerificationDoneNextButtonText, text.EmailVerificationDone.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneCancelButtonText, existingText.EmailVerificationDoneCancelButtonText, text.EmailVerificationDone.CancelButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyEmailVerificationDoneLoginButtonText, existingText.EmailVerificationDoneLoginButtonText, text.EmailVerificationDone.LoginButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createInitUserEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserTitle, existingText.InitializeTitle, text.InitUser.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserDescription, existingText.InitializeDescription, text.InitUser.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserCodeLabel, existingText.InitializeCodeLabel, text.InitUser.CodeLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserNewPasswordLabel, existingText.InitializeNewPassword, text.InitUser.NewPasswordLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserNewPasswordConfirmLabel, existingText.InitializeNewPasswordConfirm, text.InitUser.NewPasswordConfirmLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserResendButtonText, existingText.InitializeResendButtonText, text.InitUser.ResendButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitializeUserNextButtonText, existingText.InitializeNextButtonText, text.InitUser.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createInitUserDoneEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneTitle, existingText.InitializeDoneTitle, text.InitUserDone.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneDescription, existingText.InitializeDoneDescription, text.InitUserDone.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneCancelButtonText, existingText.InitializeDoneAbortButtonText, text.InitUserDone.CancelButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitUserDoneNextButtonText, existingText.InitializeDoneNextButtonText, text.InitUserDone.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createInitMFAPromptEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptTitle, existingText.InitMFAPromptTitle, text.InitMFAPrompt.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptDescription, existingText.InitMFAPromptDescription, text.InitMFAPrompt.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptOTPOption, existingText.InitMFAPromptOTPOption, text.InitMFAPrompt.Provider0, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptU2FOption, existingText.InitMFAPromptU2FOption, text.InitMFAPrompt.Provider1, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptSkipButtonText, existingText.InitMFAPromptSkipButtonText, text.InitMFAPrompt.SkipButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAPromptNextButtonText, existingText.InitMFAPromptNextButtonText, text.InitMFAPrompt.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createInitMFAOTPEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPTitle, existingText.InitMFAOTPTitle, text.InitMFAOTP.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPDescription, existingText.InitMFAOTPDescription, text.InitMFAOTP.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPDescriptionOTP, existingText.InitMFAOTPDescriptionOTP, text.InitMFAOTP.OTPDescription, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPSecretLabel, existingText.InitMFAOTPSecretLabel, text.InitMFAOTP.SecretLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPCodeLabel, existingText.InitMFAOTPCodeLabel, text.InitMFAOTP.CodeLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPNextButtonText, existingText.InitMFAOTPNextButtonText, text.InitMFAOTP.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAOTPCancelButtonText, existingText.InitMFAOTPCancelButtonText, text.InitMFAOTP.CancelButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createInitMFAU2FEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FTitle, existingText.InitMFAU2FTitle, text.InitMFAU2F.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FDescription, existingText.InitMFAU2FDescription, text.InitMFAU2F.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FTokenNameLabel, existingText.InitMFAU2FTokenNameLabel, text.InitMFAU2F.TokenNameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FRegisterTokenButtonText, existingText.InitMFAU2FRegisterTokenButtonText, text.InitMFAU2F.RegisterTokenButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FNotSupported, existingText.InitMFAU2FNotSupported, text.InitMFAU2F.NotSupported, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFAU2FErrorRetry, existingText.InitMFAU2FErrorRetry, text.InitMFAU2F.ErrorRetry, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createInitMFADoneEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneTitle, existingText.InitMFADoneTitle, text.InitMFADone.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneDescription, existingText.InitMFADoneDescription, text.InitMFADone.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneCancelButtonText, existingText.InitMFADoneAbortButtonText, text.InitMFADone.CancelButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyInitMFADoneNextButtonText, existingText.InitMFADoneNextButtonText, text.InitMFADone.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) crateMFAProviderEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyMFAProvidersChooseOther, existingText.MFAProvidersChooseOther, text.MFAProvider.ChooseOther, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyMFAProvidersOTP, existingText.MFAProvidersOTP, text.MFAProvider.Provider0, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyMFAProvidersU2F, existingText.MFAProvidersU2F, text.MFAProvider.Provider1, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createVerifyMFAOTPEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPTitle, existingText.VerifyMFAOTPTitle, text.VerifyMFAOTP.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPDescription, existingText.VerifyMFAOTPDescription, text.VerifyMFAOTP.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPCodeLabel, existingText.VerifyMFAOTPCodeLabel, text.VerifyMFAOTP.CodeLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAOTPNextButtonText, existingText.VerifyMFAOTPNextButtonText, text.VerifyMFAOTP.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createVerifyMFAU2FEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FTitle, existingText.VerifyMFAU2FTitle, text.VerifyMFAU2F.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FDescription, existingText.VerifyMFAU2FDescription, text.VerifyMFAU2F.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FValidateTokenText, existingText.VerifyMFAU2FValidateTokenText, text.VerifyMFAU2F.ValidateTokenButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FNotSupported, existingText.VerifyMFAU2FNotSupported, text.VerifyMFAU2F.NotSupported, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyVerifyMFAU2FErrorRetry, existingText.VerifyMFAU2FErrorRetry, text.VerifyMFAU2F.ErrorRetry, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createPasswordlessEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessTitle, existingText.PasswordlessTitle, text.Passwordless.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessDescription, existingText.PasswordlessDescription, text.Passwordless.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessLoginWithPwButtonText, existingText.PasswordlessLoginWithPwButtonText, text.Passwordless.LoginWithPwButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessValidateTokenButtonText, existingText.PasswordlessValidateTokenButtonText, text.Passwordless.ValidateTokenButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessNotSupported, existingText.PasswordlessNotSupported, text.Passwordless.NotSupported, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessErrorRetry, existingText.PasswordlessErrorRetry, text.Passwordless.ErrorRetry, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createPasswordChangeEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeTitle, existingText.PasswordChangeTitle, text.PasswordChange.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDescription, existingText.PasswordChangeDescription, text.PasswordChange.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeOldPasswordLabel, existingText.PasswordChangeOldPasswordLabel, text.PasswordChange.OldPasswordLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeNewPasswordLabel, existingText.PasswordChangeNewPasswordLabel, text.PasswordChange.NewPasswordLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeNewPasswordConfirmLabel, existingText.PasswordChangeNewPasswordConfirmLabel, text.PasswordChange.NewPasswordConfirmLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeCancelButtonText, existingText.PasswordChangeCancelButtonText, text.PasswordChange.CancelButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeNextButtonText, existingText.PasswordChangeNextButtonText, text.PasswordChange.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createPasswordChangeDoneEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDoneTitle, existingText.PasswordChangeDoneTitle, text.PasswordChangeDone.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDoneDescription, existingText.PasswordChangeDoneDescription, text.PasswordChangeDone.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordChangeDoneNextButtonText, existingText.PasswordChangeDoneNextButtonText, text.PasswordChangeDone.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createPasswordResetDoneEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetDoneTitle, existingText.PasswordResetDoneTitle, text.PasswordResetDone.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetDoneDescription, existingText.PasswordResetDoneDescription, text.PasswordResetDone.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordResetDoneNextButtonText, existingText.PasswordResetDoneNextButtonText, text.PasswordResetDone.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createRegistrationOptionEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionTitle, existingText.RegistrationOptionTitle, text.RegisterOption.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionDescription, existingText.RegistrationOptionDescription, text.RegisterOption.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionUserNameButtonText, existingText.RegistrationOptionUserNameButtonText, text.RegisterOption.RegisterUsernamePasswordButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationOptionExternalLoginDescription, existingText.RegistrationOptionExternalLoginDescription, text.RegisterOption.ExternalLoginDescription, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createRegistrationUserEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTitle, existingText.RegistrationUserTitle, text.RegistrationUser.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserDescription, existingText.RegistrationUserDescription, text.RegistrationUser.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserDescriptionOrgRegister, existingText.RegistrationUserDescriptionOrgRegister, text.RegistrationUser.DescriptionOrgRegister, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserFirstnameLabel, existingText.RegistrationUserFirstnameLabel, text.RegistrationUser.FirstnameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserLastnameLabel, existingText.RegistrationUserLastnameLabel, text.RegistrationUser.LastnameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserEmailLabel, existingText.RegistrationUserEmailLabel, text.RegistrationUser.EmailLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserUsernameLabel, existingText.RegistrationUserUsernameLabel, text.RegistrationUser.UsernameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserLanguageLabel, existingText.RegistrationUserLanguageLabel, text.RegistrationUser.LanguageLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserGenderLabel, existingText.RegistrationUserGenderLabel, text.RegistrationUser.GenderLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPasswordLabel, existingText.RegistrationUserPasswordLabel, text.RegistrationUser.PasswordLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPasswordConfirmLabel, existingText.RegistrationUserPasswordConfirmLabel, text.RegistrationUser.PasswordConfirmLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTOSAndPrivacyLabel, existingText.RegistrationUserTOSAndPrivacyLabel, text.RegistrationUser.TOSAndPrivacyLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTOSConfirm, existingText.RegistrationUserTOSConfirm, text.RegistrationUser.TOSConfirm, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTOSLink, existingText.RegistrationUserTOSLink, text.RegistrationUser.TOSLink, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserTOSLinkText, existingText.RegistrationUserTOSLinkText, text.RegistrationUser.TOSLinkText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPrivacyConfirm, existingText.RegistrationUserPrivacyConfirm, text.RegistrationUser.PrivacyConfirm, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPrivacyLink, existingText.RegistrationUserPrivacyLink, text.RegistrationUser.PrivacyLink, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserPrivacyLinkText, existingText.RegistrationUserPrivacyLinkText, text.RegistrationUser.PrivacyLinkText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserExternalLoginDescription, existingText.RegistrationUserExternalLoginDescription, text.RegistrationUser.ExternalLoginDescription, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserNextButtonText, existingText.RegistrationUserNextButtonText, text.RegistrationUser.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegistrationUserBackButtonText, existingText.RegistrationUserBackButtonText, text.RegistrationUser.BackButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createRegistrationOrgEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTitle, existingText.RegisterOrgTitle, text.RegistrationOrg.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgDescription, existingText.RegisterOrgDescription, text.RegistrationOrg.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgOrgNameLabel, existingText.RegisterOrgOrgNameLabel, text.RegistrationOrg.OrgNameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgFirstnameLabel, existingText.RegisterOrgFirstnameLabel, text.RegistrationOrg.FirstnameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgLastnameLabel, existingText.RegisterOrgLastnameLabel, text.RegistrationOrg.LastnameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgUsernameLabel, existingText.RegisterOrgUsernameLabel, text.RegistrationOrg.UsernameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgEmailLabel, existingText.RegisterOrgEmailLabel, text.RegistrationOrg.EmailLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPasswordLabel, existingText.RegisterOrgPasswordLabel, text.RegistrationOrg.PasswordLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPasswordConfirmLabel, existingText.RegisterOrgPasswordConfirmLabel, text.RegistrationOrg.PasswordConfirmLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTOSAndPrivacyLabel, existingText.RegisterOrgTOSAndPrivacyLabel, text.RegistrationOrg.TOSAndPrivacyLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTOSConfirm, existingText.RegisterOrgTOSConfirm, text.RegistrationOrg.TOSConfirm, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTOSLink, existingText.RegisterOrgTOSLink, text.RegistrationOrg.TOSLink, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTOSLinkText, existingText.RegisterOrgTOSLinkText, text.RegistrationOrg.TOSLinkText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPrivacyConfirm, existingText.RegisterOrgPrivacyConfirm, text.RegistrationOrg.PrivacyConfirm, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPrivacyLink, existingText.RegisterOrgPrivacyLink, text.RegistrationOrg.PrivacyLink, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgPrivacyLinkText, existingText.RegisterOrgPrivacyLinkText, text.RegistrationOrg.PrivacyLinkText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgExternalLoginDescription, existingText.RegisterOrgExternalLoginDescription, text.RegistrationOrg.ExternalLoginDescription, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgSaveButtonText, existingText.RegisterOrgSaveButtonText, text.RegistrationOrg.SaveButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createLinkingUserEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneTitle, existingText.LinkingUserDoneTitle, text.LinkingUsersDone.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneDescription, existingText.LinkingUserDoneDescription, text.LinkingUsersDone.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneCancelButtonText, existingText.LinkingUserDoneCancelButtonText, text.LinkingUsersDone.CancelButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLinkingUserDoneNextButtonText, existingText.LinkingUserDoneNextButtonText, text.LinkingUsersDone.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createExternalUserNotFoundEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTitle, existingText.ExternalUserNotFoundTitle, text.ExternalNotFoundOption.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundDescription, existingText.ExternalUserNotFoundDescription, text.ExternalNotFoundOption.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundLinkButtonText, existingText.ExternalUserNotFoundLinkButtonText, text.ExternalNotFoundOption.LinkButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundAutoRegisterButtonText, existingText.ExternalUserNotFoundAutoRegisterButtonText, text.ExternalNotFoundOption.AutoRegisterButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createSuccessLoginEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginTitle, existingText.SuccessLoginTitle, text.LoginSuccess.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginAutoRedirectDescription, existingText.SuccessLoginAutoRedirectDescription, text.LoginSuccess.AutoRedirectDescription, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginRedirectedDescription, existingText.SuccessLoginRedirectedDescription, text.LoginSuccess.RedirectedDescription, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeySuccessLoginNextButtonText, existingText.SuccessLoginNextButtonText, text.LoginSuccess.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createLogoutDoneEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLogoutDoneTitle, existingText.LogoutDoneTitle, text.LogoutDone.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLogoutDoneDescription, existingText.LogoutDoneDescription, text.LogoutDone.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyLogoutDoneLoginButtonText, existingText.LogoutDoneLoginButtonText, text.LogoutDone.LoginButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createFooterTextEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterTOS, existingText.FooterTOS, text.Footer.TOS, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterTOSLink, existingText.FooterTOSLink, text.Footer.TOSLink, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterPrivacy, existingText.FooterPrivacyPolicy, text.Footer.PrivacyPolicy, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterPrivacyLink, existingText.FooterPrivacyPolicyLink, text.Footer.PrivacyPolicyLink, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterHelp, existingText.FooterHelp, text.Footer.Help, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterHelpLink, existingText.FooterHelpLink, text.Footer.HelpLink, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createCustomLoginTextEvent(ctx context.Context, agg *eventstore.Aggregate, textKey, existingText, newText string, lang language.Tag, defaultText bool) eventstore.EventPusher {
if existingText == newText {
return nil
}
if defaultText {
if newText != "" {
return iam.NewCustomTextSetEvent(ctx, agg, domain.LoginCustomText, textKey, newText, lang)
}
return iam.NewCustomTextRemovedEvent(ctx, agg, domain.LoginCustomText, textKey, lang)
}
if newText != "" {
return org.NewCustomTextSetEvent(ctx, agg, domain.LoginCustomText, textKey, newText, lang)
}
return org.NewCustomTextRemovedEvent(ctx, agg, domain.LoginCustomText, textKey, lang)
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
package command
import (
"context"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
)
func (c *Commands) SetCustomIAMLoginText(ctx context.Context, loginText *domain.CustomLoginText) (*domain.ObjectDetails, error) {
iamAgg := iam.NewAggregate()
events, existingMailText, err := c.setCustomIAMLoginText(ctx, &iamAgg.Aggregate, loginText)
if err != nil {
return nil, err
}
pushedEvents, err := c.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingMailText, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&existingMailText.WriteModel), nil
}
func (c *Commands) setCustomIAMLoginText(ctx context.Context, iamAgg *eventstore.Aggregate, text *domain.CustomLoginText) ([]eventstore.EventPusher, *IAMCustomLoginTextReadModel, error) {
if !text.IsValid() {
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "IAM-kd9fs", "Errors.CustomText.Invalid")
}
existingLoginText, err := c.defaultLoginTextWriteModelByID(ctx, text.Language)
if err != nil {
return nil, nil, err
}
events := c.createAllLoginTextEvents(ctx, iamAgg, &existingLoginText.CustomLoginTextReadModel, text, true)
return events, existingLoginText, nil
}
func (c *Commands) defaultLoginTextWriteModelByID(ctx context.Context, lang language.Tag) (*IAMCustomLoginTextReadModel, error) {
writeModel := NewIAMCustomLoginTextReadModel(lang)
err := c.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@ -0,0 +1,49 @@
package command
import (
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
)
type IAMCustomLoginTextReadModel struct {
CustomLoginTextReadModel
}
func NewIAMCustomLoginTextReadModel(lang language.Tag) *IAMCustomLoginTextReadModel {
return &IAMCustomLoginTextReadModel{
CustomLoginTextReadModel{
WriteModel: eventstore.WriteModel{
AggregateID: domain.IAMID,
ResourceOwner: domain.IAMID,
},
Language: lang,
},
}
}
func (wm *IAMCustomLoginTextReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.CustomTextSetEvent:
wm.CustomLoginTextReadModel.AppendEvents(&e.CustomTextSetEvent)
case *iam.CustomTextRemovedEvent:
wm.CustomLoginTextReadModel.AppendEvents(&e.CustomTextRemovedEvent)
}
}
}
func (wm *IAMCustomLoginTextReadModel) Reduce() error {
return wm.CustomLoginTextReadModel.Reduce()
}
func (wm *IAMCustomLoginTextReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.CustomLoginTextReadModel.AggregateID).
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.CustomTextSetEventType,
iam.CustomTextRemovedEventType)
}

File diff suppressed because it is too large Load Diff

View File

@ -114,7 +114,7 @@ func TestCommandSide_SetDefaultMessageText(t *testing.T) {
&iam.NewAggregate().Aggregate,
"Template",
domain.MessageFooterText,
"FooterText",
"Footer",
language.English,
),
),
@ -133,7 +133,7 @@ func TestCommandSide_SetDefaultMessageText(t *testing.T) {
PreHeader: "PreHeader",
Text: "Text",
ButtonText: "ButtonText",
FooterText: "FooterText",
FooterText: "Footer",
},
},
res: res{

View File

@ -0,0 +1,61 @@
package command
import (
"context"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
iam_repo "github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/telemetry/tracing"
)
func (c *Commands) SetIAMCustomText(ctx context.Context, customText *domain.CustomText) (*domain.CustomText, error) {
setText := NewIAMCustomTextWriteModel(customText.Key, customText.Language)
iamAgg := IAMAggregateFromWriteModel(&setText.CustomTextWriteModel.WriteModel)
event, err := c.setDefaultCustomText(ctx, iamAgg, setText, customText)
if err != nil {
return nil, err
}
pushedEvents, err := c.eventstore.PushEvents(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(setText, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToCustomText(&setText.CustomTextWriteModel), nil
}
func (c *Commands) setDefaultCustomText(ctx context.Context, iamAgg *eventstore.Aggregate, addedPolicy *IAMCustomTextWriteModel, text *domain.CustomText) (eventstore.EventPusher, error) {
if !text.IsValid() {
return nil, caos_errs.ThrowInvalidArgument(nil, "IAM-3MN0s", "Errors.CustomText.Invalid")
}
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
return iam_repo.NewCustomTextSetEvent(
ctx,
iamAgg,
text.Template,
text.Key,
text.Text,
text.Language), nil
}
func (c *Commands) defaultCustomTextWriteModelByID(ctx context.Context, key string, language language.Tag) (policy *IAMCustomTextWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewIAMCustomTextWriteModel(key, language)
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@ -0,0 +1,47 @@
package command
import (
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
)
type IAMCustomTextWriteModel struct {
CustomTextWriteModel
}
func NewIAMCustomTextWriteModel(key string, language language.Tag) *IAMCustomTextWriteModel {
return &IAMCustomTextWriteModel{
CustomTextWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: domain.IAMID,
ResourceOwner: domain.IAMID,
},
Key: key,
Language: language,
},
}
}
func (wm *IAMCustomTextWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.CustomTextSetEvent:
wm.CustomTextWriteModel.AppendEvents(&e.CustomTextSetEvent)
}
}
}
func (wm *IAMCustomTextWriteModel) Reduce() error {
return wm.CustomTextWriteModel.Reduce()
}
func (wm *IAMCustomTextWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.CustomTextWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner).
EventTypes(
iam.CustomTextSetEventType)
}

View File

@ -0,0 +1,77 @@
package command
import (
"context"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/org"
)
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")
}
iamAgg := org.NewAggregate(resourceOwner, resourceOwner)
events, existingLoginText, err := c.setOrgLoginText(ctx, &iamAgg.Aggregate, loginText)
if err != nil {
return nil, err
}
pushedEvents, err := c.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingLoginText, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&existingLoginText.WriteModel), nil
}
func (c *Commands) setOrgLoginText(ctx context.Context, orgAgg *eventstore.Aggregate, loginText *domain.CustomLoginText) ([]eventstore.EventPusher, *OrgCustomLoginTextReadModel, error) {
if !loginText.IsValid() {
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "ORG-PPo2w", "Errors.CustomText.Invalid")
}
existingLoginText, err := c.orgCustomLoginTextWriteModelByID(ctx, orgAgg.ID, loginText.Language)
if err != nil {
return nil, nil, err
}
events := c.createAllLoginTextEvents(ctx, orgAgg, &existingLoginText.CustomLoginTextReadModel, loginText, false)
return events, existingLoginText, nil
}
func (c *Commands) RemoveOrgLoginTexts(ctx context.Context, resourceOwner string, lang language.Tag) (*domain.ObjectDetails, error) {
if resourceOwner == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-1B8dw", "Errors.ResourceOwnerMissing")
}
if lang == language.Und {
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-5ZZmo", "Errors.CustomText.Invalid")
}
customText, err := c.orgCustomLoginTextWriteModelByID(ctx, resourceOwner, lang)
if err != nil {
return nil, err
}
if customText.State == domain.PolicyStateUnspecified || customText.State == domain.PolicyStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "Org-9ru44", "Errors.CustomText.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&customText.WriteModel)
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewCustomTextTemplateRemovedEvent(ctx, orgAgg, domain.LoginCustomText, lang))
err = AppendAndReduce(customText, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&customText.WriteModel), nil
}
func (c *Commands) orgCustomLoginTextWriteModelByID(ctx context.Context, orgID string, lang language.Tag) (*OrgCustomLoginTextReadModel, error) {
writeModel := NewOrgCustomLoginTextReadModel(orgID, lang)
err := c.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@ -0,0 +1,51 @@
package command
import (
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/org"
)
type OrgCustomLoginTextReadModel struct {
CustomLoginTextReadModel
}
func NewOrgCustomLoginTextReadModel(orgID string, lang language.Tag) *OrgCustomLoginTextReadModel {
return &OrgCustomLoginTextReadModel{
CustomLoginTextReadModel{
WriteModel: eventstore.WriteModel{
AggregateID: orgID,
ResourceOwner: orgID,
},
Language: lang,
},
}
}
func (wm *OrgCustomLoginTextReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.CustomTextSetEvent:
wm.CustomLoginTextReadModel.AppendEvents(&e.CustomTextSetEvent)
case *org.CustomTextRemovedEvent:
wm.CustomLoginTextReadModel.AppendEvents(&e.CustomTextRemovedEvent)
case *org.CustomTextTemplateRemovedEvent:
wm.CustomLoginTextReadModel.AppendEvents(&e.CustomTextTemplateRemovedEvent)
}
}
}
func (wm *OrgCustomLoginTextReadModel) Reduce() error {
return wm.CustomLoginTextReadModel.Reduce()
}
func (wm *OrgCustomLoginTextReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.CustomLoginTextReadModel.AggregateID).
ResourceOwner(wm.ResourceOwner).
EventTypes(
org.CustomTextSetEventType,
org.CustomTextRemovedEventType,
org.CustomTextTemplateRemovedEventType)
}

File diff suppressed because it is too large Load Diff

View File

@ -131,7 +131,7 @@ func TestCommandSide_SetCustomMessageText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate,
"Template",
domain.MessageFooterText,
"FooterText",
"Footer",
language.English,
),
),
@ -151,7 +151,7 @@ func TestCommandSide_SetCustomMessageText(t *testing.T) {
PreHeader: "PreHeader",
Text: "Text",
ButtonText: "ButtonText",
FooterText: "FooterText",
FooterText: "Footer",
},
},
res: res{
@ -225,7 +225,7 @@ func TestCommandSide_SetCustomMessageText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate,
"Template",
domain.MessageFooterText,
"FooterText",
"Footer",
language.English,
),
),
@ -466,7 +466,7 @@ func TestCommandSide_RemoveCustomMessageText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate,
"Template",
domain.MessageFooterText,
"FooterText",
"Footer",
language.English,
),
),

View File

@ -34,7 +34,7 @@ func (c *Commands) AddHumanOTP(ctx context.Context, userID, resourceowner string
return nil, err
}
if otpWriteModel.State == domain.MFAStateReady {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-do9se", "Errors.User.MFA.OTP.AlreadyReady")
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-do9se", "Errors.User.MFA.Provider0.AlreadyReady")
}
userAgg := UserAggregateFromWriteModel(&otpWriteModel.WriteModel)
accountName := domain.GenerateLoginName(human.GetUsername(), org.PrimaryDomain, orgPolicy.UserLoginMustBeDomain)
@ -69,10 +69,10 @@ func (c *Commands) HumanCheckMFAOTPSetup(ctx context.Context, userID, code, user
return nil, err
}
if existingOTP.State == domain.MFAStateUnspecified || existingOTP.State == domain.MFAStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3Mif9s", "Errors.User.MFA.OTP.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3Mif9s", "Errors.User.MFA.Provider0.NotExisting")
}
if existingOTP.State == domain.MFAStateReady {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-qx4ls", "Errors.Users.MFA.OTP.AlreadyReady")
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-qx4ls", "Errors.Users.MFA.Provider0.AlreadyReady")
}
if err := domain.VerifyMFAOTP(code, existingOTP.Secret, c.multifactors.OTP.CryptoMFA); err != nil {
return nil, err
@ -99,7 +99,7 @@ func (c *Commands) HumanCheckMFAOTP(ctx context.Context, userID, code, resourceo
return err
}
if existingOTP.State != domain.MFAStateReady {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-3Mif9s", "Errors.User.MFA.OTP.NotReady")
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-3Mif9s", "Errors.User.MFA.Provider0.NotReady")
}
userAgg := UserAggregateFromWriteModel(&existingOTP.WriteModel)
err = domain.VerifyMFAOTP(code, existingOTP.Secret, c.multifactors.OTP.CryptoMFA)
@ -122,7 +122,7 @@ func (c *Commands) HumanRemoveOTP(ctx context.Context, userID, resourceOwner str
return nil, err
}
if existingOTP.State == domain.MFAStateUnspecified || existingOTP.State == domain.MFAStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-Hd9sd", "Errors.User.MFA.OTP.NotExisting")
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-Hd9sd", "Errors.User.MFA.Provider0.NotExisting")
}
userAgg := UserAggregateFromWriteModel(&existingOTP.WriteModel)
pushedEvents, err := c.eventstore.PushEvents(ctx, user.NewHumanOTPRemovedEvent(ctx, userAgg))

View File

@ -48,6 +48,8 @@ type AuthRequest struct {
AllowedExternalIDPs []*IDPProvider
LabelPolicy *LabelPolicy
PrivacyPolicy *PrivacyPolicy
DefaultTranslations []*CustomText
OrgTranslations []*CustomText
}
type ExternalUser struct {

View File

@ -0,0 +1,582 @@
package domain
import (
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/eventstore/v1/models"
)
const (
LoginCustomText = "Login"
LoginKeyLogin = "Login."
LoginKeyLoginTitle = LoginKeyLogin + "Title"
LoginKeyLoginDescription = LoginKeyLogin + "Description"
LoginKeyLoginTitleLinkingProcess = LoginKeyLogin + "TitleLinking"
LoginKeyLoginDescriptionLinkingProcess = LoginKeyLogin + "DescriptionLinking"
LoginKeyLoginNameLabel = LoginKeyLogin + "LoginNameLabel"
LoginKeyLoginUsernamePlaceHolder = LoginKeyLogin + "UsernamePlaceHolder"
LoginKeyLoginLoginnamePlaceHolder = LoginKeyLogin + "LoginnamePlaceHolder"
LoginKeyLoginRegisterButtonText = LoginKeyLogin + "RegisterButtonText"
LoginKeyLoginNextButtonText = LoginKeyLogin + "NextButtonText"
LoginKeyLoginExternalUserDescription = LoginKeyLogin + "ExternalUserDescription"
LoginKeyLoginUserMustBeMemberOfOrg = LoginKeyLogin + "MustBeMemberOfOrg"
LoginKeySelectAccount = "SelectAccount."
LoginKeySelectAccountTitle = LoginKeySelectAccount + "Title"
LoginKeySelectAccountDescription = LoginKeySelectAccount + "Description"
LoginKeySelectAccountTitleLinkingProcess = LoginKeySelectAccount + "TitleLinking"
LoginKeySelectAccountDescriptionLinkingProcess = LoginKeySelectAccount + "DescriptionLinking"
LoginKeySelectAccountOtherUser = LoginKeySelectAccount + "OtherUser"
LoginKeySelectAccountSessionStateActive = LoginKeySelectAccount + "SessionState0"
LoginKeySelectAccountSessionStateInactive = LoginKeySelectAccount + "SessionState1"
LoginKeySelectAccountUserMustBeMemberOfOrg = LoginKeySelectAccount + "MustBeMemberOfOrg"
LoginKeyPassword = "Password."
LoginKeyPasswordTitle = LoginKeyPassword + "Title"
LoginKeyPasswordDescription = LoginKeyPassword + "Description"
LoginKeyPasswordLabel = LoginKeyPassword + "PasswordLabel"
LoginKeyPasswordMinLength = LoginKeyPassword + "MinLength"
LoginKeyPasswordHasUppercase = LoginKeyPassword + "HasUppercase"
LoginKeyPasswordHasLowercase = LoginKeyPassword + "HasLowercase"
LoginKeyPasswordHasNumber = LoginKeyPassword + "HasNumber"
LoginKeyPasswordHasSymbol = LoginKeyPassword + "HasSymbol"
LoginKeyPasswordConfirmation = LoginKeyPassword + "Confirmation"
LoginKeyPasswordResetLinkText = LoginKeyPassword + "ResetLinkText"
LoginKeyPasswordBackButtonText = LoginKeyPassword + "BackButtonText"
LoginKeyPasswordNextButtonText = LoginKeyPassword + "NextButtonText"
LoginKeyUsernameChange = "UsernameChange."
LoginKeyUsernameChangeTitle = LoginKeyUsernameChange + "Title"
LoginKeyUsernameChangeDescription = LoginKeyUsernameChange + "Description"
LoginKeyUsernameChangeUsernameLabel = LoginKeyUsernameChange + "UsernameLabel"
LoginKeyUsernameChangeCancelButtonText = LoginKeyUsernameChange + "CancelButtonText"
LoginKeyUsernameChangeNextButtonText = LoginKeyUsernameChange + "NextButtonText"
LoginKeyUsernameChangeDone = "UsernameChangeDone."
LoginKeyUsernameChangeDoneTitle = LoginKeyUsernameChangeDone + "Title"
LoginKeyUsernameChangeDoneDescription = LoginKeyUsernameChangeDone + "Description"
LoginKeyUsernameChangeDoneNextButtonText = LoginKeyUsernameChangeDone + "NextButtonText"
LoginKeyInitPassword = "InitPassword."
LoginKeyInitPasswordTitle = LoginKeyInitPassword + "Title"
LoginKeyInitPasswordDescription = LoginKeyInitPassword + "Description"
LoginKeyInitPasswordCodeLabel = LoginKeyInitPassword + "CodeLabel"
LoginKeyInitPasswordNewPasswordLabel = LoginKeyInitPassword + "NewPasswordLabel"
LoginKeyInitPasswordNewPasswordConfirmLabel = LoginKeyInitPassword + "NewPasswordConfirmLabel"
LoginKeyInitPasswordNextButtonText = LoginKeyInitPassword + "NextButtonText"
LoginKeyInitPasswordResendButtonText = LoginKeyInitPassword + "ResendButtonText"
LoginKeyInitPasswordDone = "InitPasswordDone."
LoginKeyInitPasswordDoneTitle = LoginKeyInitPasswordDone + "Title"
LoginKeyInitPasswordDoneDescription = LoginKeyInitPasswordDone + "Description"
LoginKeyInitPasswordDoneNextButtonText = LoginKeyInitPasswordDone + "NextButtonText"
LoginKeyInitPasswordDoneCancelButtonText = LoginKeyInitPasswordDone + "CancelButtonText"
LoginKeyEmailVerification = "EmailVerification."
LoginKeyEmailVerificationTitle = LoginKeyEmailVerification + "Title"
LoginKeyEmailVerificationDescription = LoginKeyEmailVerification + "Description"
LoginKeyEmailVerificationCodeLabel = LoginKeyEmailVerification + "CodeLabel"
LoginKeyEmailVerificationNextButtonText = LoginKeyEmailVerification + "NextButtonText"
LoginKeyEmailVerificationResendButtonText = LoginKeyEmailVerification + "ResendButtonText"
LoginKeyEmailVerificationDone = "EmailVerificationDone."
LoginKeyEmailVerificationDoneTitle = LoginKeyEmailVerificationDone + "Title"
LoginKeyEmailVerificationDoneDescription = LoginKeyEmailVerificationDone + "Description"
LoginKeyEmailVerificationDoneNextButtonText = LoginKeyEmailVerificationDone + "NextButtonText"
LoginKeyEmailVerificationDoneCancelButtonText = LoginKeyEmailVerificationDone + "CancelButtonText"
LoginKeyEmailVerificationDoneLoginButtonText = LoginKeyEmailVerificationDone + "LoginButtonText"
LoginKeyInitializeUser = "InitUser."
LoginKeyInitializeUserTitle = LoginKeyInitializeUser + "Title"
LoginKeyInitializeUserDescription = LoginKeyInitializeUser + "Description"
LoginKeyInitializeUserCodeLabel = LoginKeyInitializeUser + "CodeLabel"
LoginKeyInitializeUserNewPasswordLabel = LoginKeyInitializeUser + "NewPasswordLabel"
LoginKeyInitializeUserNewPasswordConfirmLabel = LoginKeyInitializeUser + "NewPasswordConfirm"
LoginKeyInitializeUserResendButtonText = LoginKeyInitializeUser + "ResendButtonText"
LoginKeyInitializeUserNextButtonText = LoginKeyInitializeUser + "NextButtonText"
LoginKeyInitUserDone = "InitUserDone."
LoginKeyInitUserDoneTitle = LoginKeyInitUserDone + "Title"
LoginKeyInitUserDoneDescription = LoginKeyInitUserDone + "Description"
LoginKeyInitUserDoneCancelButtonText = LoginKeyInitUserDone + "CancelButtonText"
LoginKeyInitUserDoneNextButtonText = LoginKeyInitUserDone + "NextButtonText"
LoginKeyInitMFAPrompt = "InitMFAPrompt."
LoginKeyInitMFAPromptTitle = LoginKeyInitMFAPrompt + "Title"
LoginKeyInitMFAPromptDescription = LoginKeyInitMFAPrompt + "Description"
LoginKeyInitMFAPromptOTPOption = LoginKeyInitMFAPrompt + "Provider0"
LoginKeyInitMFAPromptU2FOption = LoginKeyInitMFAPrompt + "Provider1"
LoginKeyInitMFAPromptSkipButtonText = LoginKeyInitMFAPrompt + "SkipButtonText"
LoginKeyInitMFAPromptNextButtonText = LoginKeyInitMFAPrompt + "NextButtonText"
LoginKeyInitMFAOTP = "InitMFAOTP."
LoginKeyInitMFAOTPTitle = LoginKeyInitMFAOTP + "Title"
LoginKeyInitMFAOTPDescription = LoginKeyInitMFAOTP + "Description"
LoginKeyInitMFAOTPDescriptionOTP = LoginKeyInitMFAOTP + "OTPDescription"
LoginKeyInitMFAOTPSecretLabel = LoginKeyInitMFAOTP + "SecretLabel"
LoginKeyInitMFAOTPCodeLabel = LoginKeyInitMFAOTP + "CodeLabel"
LoginKeyInitMFAOTPNextButtonText = LoginKeyInitMFAOTP + "NextButtonText"
LoginKeyInitMFAOTPCancelButtonText = LoginKeyInitMFAOTP + "CancelButtonText"
LoginKeyInitMFAU2F = "InitMFAU2F."
LoginKeyInitMFAU2FTitle = LoginKeyInitMFAU2F + "Title"
LoginKeyInitMFAU2FDescription = LoginKeyInitMFAU2F + "Description"
LoginKeyInitMFAU2FTokenNameLabel = LoginKeyInitMFAU2F + "TokenNameLabel"
LoginKeyInitMFAU2FNotSupported = LoginKeyInitMFAU2F + "NotSupported"
LoginKeyInitMFAU2FRegisterTokenButtonText = LoginKeyInitMFAU2F + "RegisterTokenButtonText"
LoginKeyInitMFAU2FErrorRetry = LoginKeyInitMFAU2F + "ErrorRetry"
LoginKeyInitMFADone = "InitMFADone."
LoginKeyInitMFADoneTitle = LoginKeyInitMFADone + "Title"
LoginKeyInitMFADoneDescription = LoginKeyInitMFADone + "Description"
LoginKeyInitMFADoneCancelButtonText = LoginKeyInitMFADone + "CancelButtonText"
LoginKeyInitMFADoneNextButtonText = LoginKeyInitMFADone + "NextButtonText"
LoginKeyMFAProviders = "MFAProvider."
LoginKeyMFAProvidersChooseOther = LoginKeyMFAProviders + "ChooseOther"
LoginKeyMFAProvidersOTP = LoginKeyMFAProviders + "Provider0"
LoginKeyMFAProvidersU2F = LoginKeyMFAProviders + "Provider1"
LoginKeyVerifyMFAOTP = "VerifyMFAOTP."
LoginKeyVerifyMFAOTPTitle = LoginKeyVerifyMFAOTP + "Title"
LoginKeyVerifyMFAOTPDescription = LoginKeyVerifyMFAOTP + "Description"
LoginKeyVerifyMFAOTPCodeLabel = LoginKeyVerifyMFAOTP + "CodeLabel"
LoginKeyVerifyMFAOTPNextButtonText = LoginKeyVerifyMFAOTP + "NextButtonText"
LoginKeyVerifyMFAU2F = "VerifyMFAU2F."
LoginKeyVerifyMFAU2FTitle = LoginKeyVerifyMFAU2F + "Title"
LoginKeyVerifyMFAU2FDescription = LoginKeyVerifyMFAU2F + "Description"
LoginKeyVerifyMFAU2FNotSupported = LoginKeyVerifyMFAU2F + "NotSupported"
LoginKeyVerifyMFAU2FValidateTokenText = LoginKeyVerifyMFAU2F + "ValidateTokenButtonText"
LoginKeyVerifyMFAU2FErrorRetry = LoginKeyVerifyMFAU2F + "Error.Retry"
LoginKeyPasswordless = "Passwordless."
LoginKeyPasswordlessTitle = LoginKeyPasswordless + "Title"
LoginKeyPasswordlessDescription = LoginKeyPasswordless + "Description"
LoginKeyPasswordlessLoginWithPwButtonText = LoginKeyPasswordless + "LoginWithPwButtonText"
LoginKeyPasswordlessValidateTokenButtonText = LoginKeyPasswordless + "ValidateTokenButtonText"
LoginKeyPasswordlessNotSupported = LoginKeyPasswordless + "NotSupported"
LoginKeyPasswordlessErrorRetry = LoginKeyPasswordless + "ErrorRetry"
LoginKeyPasswordChange = "PasswordChange."
LoginKeyPasswordChangeTitle = LoginKeyPasswordChange + "Title"
LoginKeyPasswordChangeDescription = LoginKeyPasswordChange + "Description"
LoginKeyPasswordChangeOldPasswordLabel = LoginKeyPasswordChange + "OldPasswordLabel"
LoginKeyPasswordChangeNewPasswordLabel = LoginKeyPasswordChange + "NewPasswordLabel"
LoginKeyPasswordChangeNewPasswordConfirmLabel = LoginKeyPasswordChange + "NewPasswordConfirmationLabel"
LoginKeyPasswordChangeCancelButtonText = LoginKeyPasswordChange + "CancelButtonText"
LoginKeyPasswordChangeNextButtonText = LoginKeyPasswordChange + "NextButtonText"
LoginKeyPasswordChangeDone = "PasswordChangeDone."
LoginKeyPasswordChangeDoneTitle = LoginKeyPasswordChangeDone + "Title"
LoginKeyPasswordChangeDoneDescription = LoginKeyPasswordChangeDone + "Description"
LoginKeyPasswordChangeDoneNextButtonText = LoginKeyPasswordChangeDone + "NextButtonText"
LoginKeyPasswordResetDone = "PasswordResetDone."
LoginKeyPasswordResetDoneTitle = LoginKeyPasswordResetDone + "Title"
LoginKeyPasswordResetDoneDescription = LoginKeyPasswordResetDone + "Description"
LoginKeyPasswordResetDoneNextButtonText = LoginKeyPasswordResetDone + "NextButtonText"
LoginKeyRegistrationOption = "RegisterOption."
LoginKeyRegistrationOptionTitle = LoginKeyRegistrationOption + "Title"
LoginKeyRegistrationOptionDescription = LoginKeyRegistrationOption + "Description"
LoginKeyRegistrationOptionUserNameButtonText = LoginKeyRegistrationOption + "RegisterUsernamePasswordButtonText"
LoginKeyRegistrationOptionExternalLoginDescription = LoginKeyRegistrationOption + "ExternalLoginDescription"
LoginKeyRegistrationUser = "RegistrationUser."
LoginKeyRegistrationUserTitle = LoginKeyRegistrationUser + "Title"
LoginKeyRegistrationUserDescription = LoginKeyRegistrationUser + "Description"
LoginKeyRegistrationUserDescriptionOrgRegister = LoginKeyRegistrationUser + "DescriptionOrgRegister"
LoginKeyRegistrationUserFirstnameLabel = LoginKeyRegistrationUser + "FirstnameLabel"
LoginKeyRegistrationUserLastnameLabel = LoginKeyRegistrationUser + "LastnameLabel"
LoginKeyRegistrationUserEmailLabel = LoginKeyRegistrationUser + "EmailLabel"
LoginKeyRegistrationUserUsernameLabel = LoginKeyRegistrationUser + "UsernameLabel"
LoginKeyRegistrationUserLanguageLabel = LoginKeyRegistrationUser + "LanguageLabel"
LoginKeyRegistrationUserGenderLabel = LoginKeyRegistrationUser + "GenderLabel"
LoginKeyRegistrationUserPasswordLabel = LoginKeyRegistrationUser + "PasswordLabel"
LoginKeyRegistrationUserPasswordConfirmLabel = LoginKeyRegistrationUser + "PasswordConfirmLabel"
LoginKeyRegistrationUserTOSAndPrivacyLabel = LoginKeyRegistrationUser + "TosAndPrivacyLabel"
LoginKeyRegistrationUserTOSConfirm = LoginKeyRegistrationUser + "TosConfirm"
LoginKeyRegistrationUserTOSLink = LoginKeyRegistrationUser + "TosLink"
LoginKeyRegistrationUserTOSLinkText = LoginKeyRegistrationUser + "TosLinkText"
LoginKeyRegistrationUserPrivacyConfirm = LoginKeyRegistrationUser + "TosConfirmAnd"
LoginKeyRegistrationUserPrivacyLink = LoginKeyRegistrationUser + "PrivacyLink"
LoginKeyRegistrationUserPrivacyLinkText = LoginKeyRegistrationUser + "PrivacyLinkText"
LoginKeyRegistrationUserExternalLoginDescription = LoginKeyRegistrationUser + "ExternalUserDescription"
LoginKeyRegistrationUserNextButtonText = LoginKeyRegistrationUser + "NextButtonText"
LoginKeyRegistrationUserBackButtonText = LoginKeyRegistrationUser + "BackButtonText"
LoginKeyRegistrationOrg = "RegistrationOrg."
LoginKeyRegisterOrgTitle = LoginKeyRegistrationOrg + "Title"
LoginKeyRegisterOrgDescription = LoginKeyRegistrationOrg + "Description"
LoginKeyRegisterOrgOrgNameLabel = LoginKeyRegistrationOrg + "OrgNameLabel"
LoginKeyRegisterOrgFirstnameLabel = LoginKeyRegistrationOrg + "FirstnameLabel"
LoginKeyRegisterOrgLastnameLabel = LoginKeyRegistrationOrg + "LastnameLabel"
LoginKeyRegisterOrgUsernameLabel = LoginKeyRegistrationOrg + "UsernameLabel"
LoginKeyRegisterOrgEmailLabel = LoginKeyRegistrationOrg + "EmailLabel"
LoginKeyRegisterOrgPasswordLabel = LoginKeyRegistrationOrg + "PasswordLabel"
LoginKeyRegisterOrgPasswordConfirmLabel = LoginKeyRegistrationOrg + "PasswordConfirmLabel"
LoginKeyRegisterOrgTOSAndPrivacyLabel = LoginKeyRegistrationOrg + "TosAndPrivacyLabel"
LoginKeyRegisterOrgTOSConfirm = LoginKeyRegistrationOrg + "TosConfirm"
LoginKeyRegisterOrgTOSLink = LoginKeyRegistrationOrg + "TosLink"
LoginKeyRegisterOrgTOSLinkText = LoginKeyRegistrationOrg + "TosLinkText"
LoginKeyRegisterOrgPrivacyConfirm = LoginKeyRegistrationOrg + "TosConfirmAnd"
LoginKeyRegisterOrgPrivacyLink = LoginKeyRegistrationOrg + "PrivacyLink"
LoginKeyRegisterOrgPrivacyLinkText = LoginKeyRegistrationOrg + "PrivacyLinkText"
LoginKeyRegisterOrgExternalLoginDescription = LoginKeyRegistrationOrg + "ExternalUserDescription"
LoginKeyRegisterOrgSaveButtonText = LoginKeyRegistrationOrg + "SaveButtonText"
LoginKeyLinkingUserDone = "LinkingUsersDone."
LoginKeyLinkingUserDoneTitle = LoginKeyLinkingUserDone + "Title"
LoginKeyLinkingUserDoneDescription = LoginKeyLinkingUserDone + "Description"
LoginKeyLinkingUserDoneCancelButtonText = LoginKeyLinkingUserDone + "CancelButtonText"
LoginKeyLinkingUserDoneNextButtonText = LoginKeyLinkingUserDone + "NextButtonText"
LoginKeyExternalNotFound = "ExternalNotFound."
LoginKeyExternalNotFoundTitle = LoginKeyExternalNotFound + "Title"
LoginKeyExternalNotFoundDescription = LoginKeyExternalNotFound + "Description"
LoginKeyExternalNotFoundLinkButtonText = LoginKeyExternalNotFound + "LinkButtonText"
LoginKeyExternalNotFoundAutoRegisterButtonText = LoginKeyExternalNotFound + "AutoRegisterButtonText"
LoginKeySuccessLogin = "LoginSuccess."
LoginKeySuccessLoginTitle = LoginKeySuccessLogin + "Title"
LoginKeySuccessLoginAutoRedirectDescription = LoginKeySuccessLogin + "AutoRedirectDescription"
LoginKeySuccessLoginRedirectedDescription = LoginKeySuccessLogin + "RedirectedDescription"
LoginKeySuccessLoginNextButtonText = LoginKeySuccessLogin + "NextButtonText"
LoginKeyLogoutDone = "LogoutDone."
LoginKeyLogoutDoneTitle = LoginKeyLogoutDone + "Title"
LoginKeyLogoutDoneDescription = LoginKeyLogoutDone + "Description"
LoginKeyLogoutDoneLoginButtonText = LoginKeyLogoutDone + "LoginButtonText"
LoginKeyFooter = "Footer."
LoginKeyFooterTOS = LoginKeyFooter + "Tos"
LoginKeyFooterTOSLink = LoginKeyFooter + "TosLink"
LoginKeyFooterPrivacy = LoginKeyFooter + "Privacy"
LoginKeyFooterPrivacyLink = LoginKeyFooter + "PrivacyLink"
LoginKeyFooterHelp = LoginKeyFooter + "Help"
LoginKeyFooterHelpLink = LoginKeyFooter + "HelpLink"
)
type CustomLoginText struct {
models.ObjectRoot
State PolicyState
Default bool
Language language.Tag
SelectAccount SelectAccountScreenText
Login LoginScreenText
Password PasswordScreenText
UsernameChange UsernameChangeScreenText
UsernameChangeDone UsernameChangeDoneScreenText
InitPassword InitPasswordScreenText
InitPasswordDone InitPasswordDoneScreenText
EmailVerification EmailVerificationScreenText
EmailVerificationDone EmailVerificationDoneScreenText
InitUser InitializeUserScreenText
InitUserDone InitializeUserDoneScreenText
InitMFAPrompt InitMFAPromptScreenText
InitMFAOTP InitMFAOTPScreenText
InitMFAU2F InitMFAU2FScreenText
InitMFADone InitMFADoneScreenText
MFAProvider MFAProvidersText
VerifyMFAOTP VerifyMFAOTPScreenText
VerifyMFAU2F VerifyMFAU2FScreenText
Passwordless PasswordlessScreenText
PasswordChange PasswordChangeScreenText
PasswordChangeDone PasswordChangeDoneScreenText
PasswordResetDone PasswordResetDoneScreenText
RegisterOption RegistrationOptionScreenText
RegistrationUser RegistrationUserScreenText
RegistrationOrg RegistrationOrgScreenText
LinkingUsersDone LinkingUserDoneScreenText
ExternalNotFoundOption ExternalUserNotFoundScreenText
LoginSuccess SuccessLoginScreenText
LogoutDone LogoutDoneScreenText
Footer FooterText
}
func (m *CustomLoginText) IsValid() bool {
return m.Language != language.Und
}
type SelectAccountScreenText struct {
Title string
Description string
TitleLinking string
DescriptionLinking string
OtherUser string
SessionState0 string //active
SessionState1 string //inactive
MustBeMemberOfOrg string
}
type LoginScreenText struct {
Title string
Description string
TitleLinking string
DescriptionLinking string
LoginNameLabel string
UsernamePlaceholder string
LoginnamePlaceholder string
RegisterButtonText string
NextButtonText string
ExternalUserDescription string
MustBeMemberOfOrg string
}
type PasswordScreenText struct {
Title string
Description string
PasswordLabel string
ResetLinkText string
BackButtonText string
NextButtonText string
MinLength string
HasUppercase string
HasLowercase string
HasNumber string
HasSymbol string
Confirmation string
}
type UsernameChangeScreenText struct {
Title string
Description string
UsernameLabel string
CancelButtonText string
NextButtonText string
}
type UsernameChangeDoneScreenText struct {
Title string
Description string
NextButtonText string
}
type InitPasswordScreenText struct {
Title string
Description string
CodeLabel string
NewPasswordLabel string
NewPasswordConfirmLabel string
NextButtonText string
ResendButtonText string
}
type InitPasswordDoneScreenText struct {
Title string
Description string
NextButtonText string
CancelButtonText string
}
type EmailVerificationScreenText struct {
Title string
Description string
CodeLabel string
NextButtonText string
ResendButtonText string
}
type EmailVerificationDoneScreenText struct {
Title string
Description string
NextButtonText string
CancelButtonText string
LoginButtonText string
}
type InitializeUserScreenText struct {
Title string
Description string
CodeLabel string
NewPasswordLabel string
NewPasswordConfirmLabel string
ResendButtonText string
NextButtonText string
}
type InitializeUserDoneScreenText struct {
Title string
Description string
CancelButtonText string
NextButtonText string
}
type InitMFAPromptScreenText struct {
Title string
Description string
Provider0 string //OTP
Provider1 string //U2F
SkipButtonText string
NextButtonText string
}
type InitMFAOTPScreenText struct {
Title string
Description string
OTPDescription string
SecretLabel string
CodeLabel string
NextButtonText string
CancelButtonText string
}
type InitMFAU2FScreenText struct {
Title string
Description string
TokenNameLabel string
RegisterTokenButtonText string
NotSupported string
ErrorRetry string
}
type InitMFADoneScreenText struct {
Title string
Description string
CancelButtonText string
NextButtonText string
}
type MFAProvidersText struct {
ChooseOther string
Provider0 string //OTP
Provider1 string //U2F
}
type VerifyMFAOTPScreenText struct {
Title string
Description string
CodeLabel string
NextButtonText string
}
type VerifyMFAU2FScreenText struct {
Title string
Description string
ValidateTokenButtonText string
NotSupported string
ErrorRetry string
}
type PasswordlessScreenText struct {
Title string
Description string
LoginWithPwButtonText string
ValidateTokenButtonText string
NotSupported string
ErrorRetry string
}
type PasswordChangeScreenText struct {
Title string
Description string
OldPasswordLabel string
NewPasswordLabel string
NewPasswordConfirmLabel string
CancelButtonText string
NextButtonText string
}
type PasswordChangeDoneScreenText struct {
Title string
Description string
NextButtonText string
}
type PasswordResetDoneScreenText struct {
Title string
Description string
NextButtonText string
}
type RegistrationOptionScreenText struct {
Title string
Description string
RegisterUsernamePasswordButtonText string
ExternalLoginDescription string
}
type RegistrationUserScreenText struct {
Title string
Description string
DescriptionOrgRegister string
FirstnameLabel string
LastnameLabel string
EmailLabel string
UsernameLabel string
LanguageLabel string
GenderLabel string
PasswordLabel string
PasswordConfirmLabel string
TOSAndPrivacyLabel string
TOSConfirm string
TOSLink string
TOSLinkText string
PrivacyConfirm string
PrivacyLink string
PrivacyLinkText string
ExternalLoginDescription string
NextButtonText string
BackButtonText string
}
type RegistrationOrgScreenText struct {
Title string
Description string
OrgNameLabel string
FirstnameLabel string
LastnameLabel string
UsernameLabel string
EmailLabel string
PasswordLabel string
PasswordConfirmLabel string
TOSAndPrivacyLabel string
TOSConfirm string
TOSLink string
TOSLinkText string
PrivacyConfirm string
PrivacyLink string
PrivacyLinkText string
ExternalLoginDescription string
SaveButtonText string
}
type LinkingUserDoneScreenText struct {
Title string
Description string
CancelButtonText string
NextButtonText string
}
type ExternalUserNotFoundScreenText struct {
Title string
Description string
LinkButtonText string
AutoRegisterButtonText string
}
type SuccessLoginScreenText struct {
Title string
AutoRedirectDescription string
RedirectedDescription string
NextButtonText string
}
type LogoutDoneScreenText struct {
Title string
Description string
LoginButtonText string
}
type FooterText struct {
TOS string
TOSLink string
PrivacyPolicy string
PrivacyPolicyLink string
Help string
HelpLink string
}

View File

@ -18,7 +18,7 @@ const (
MessageGreeting = "Greeting"
MessageText = "Text"
MessageButtonText = "ButtonText"
MessageFooterText = "FooterText"
MessageFooterText = "Footer"
)
type CustomMessageText struct {

View File

@ -37,7 +37,7 @@ func VerifyMFAOTP(code string, secret *crypto.CryptoValue, cryptoAlg crypto.Encr
valid := totp.Validate(code, decrypt)
if !valid {
return caos_errs.ThrowInvalidArgument(nil, "EVENT-8isk2", "Errors.User.MFA.OTP.InvalidCode")
return caos_errs.ThrowInvalidArgument(nil, "EVENT-8isk2", "Errors.User.MFA.Provider0.InvalidCode")
}
return nil
}

View File

@ -3,20 +3,20 @@ package i18n
import (
"context"
"encoding/json"
"github.com/BurntSushi/toml"
"github.com/caos/zitadel/internal/api/authz"
"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils"
"io/ioutil"
"net/http"
"os"
http_util "github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/errors"
"github.com/BurntSushi/toml"
"github.com/caos/logging"
"github.com/ghodss/yaml"
"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/api/authz"
http_util "github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/errors"
)
const (
@ -34,6 +34,11 @@ type TranslatorConfig struct {
CookieName string
}
type Message struct {
ID string
Text string
}
func NewTranslator(dir http.FileSystem, config TranslatorConfig) (*Translator, error) {
t := new(Translator)
var err error
@ -61,14 +66,14 @@ func newBundle(dir http.FileSystem, defaultLanguage language.Tag) (*i18n.Bundle,
return nil, errors.ThrowNotFound(err, "I18N-Gew23", "cannot read dir")
}
for _, file := range files {
if err := addFileToBundle(dir, bundle, file); err != nil {
return nil, errors.ThrowNotFound(err, "I18N-ZS2AW", "cannot append file to bundle")
if err := addFileFromFileSystemToBundle(dir, bundle, file); err != nil {
return nil, errors.ThrowNotFound(err, "I18N-ZS2AW", "cannot append file to Bundle")
}
}
return bundle, nil
}
func addFileToBundle(dir http.FileSystem, bundle *i18n.Bundle, file os.FileInfo) error {
func addFileFromFileSystemToBundle(dir http.FileSystem, bundle *i18n.Bundle, file os.FileInfo) error {
f, err := dir.Open("/i18n/" + file.Name())
if err != nil {
return err
@ -82,6 +87,20 @@ func addFileToBundle(dir http.FileSystem, bundle *i18n.Bundle, file os.FileInfo)
return nil
}
func (t *Translator) AddMessages(tag language.Tag, messages ...Message) error {
if len(messages) == 0 {
return nil
}
i18nMessages := make([]*i18n.Message, len(messages))
for i, message := range messages {
i18nMessages[i] = &i18n.Message{
ID: message.ID,
Other: message.Text,
}
}
return t.bundle.AddMessages(tag, i18nMessages...)
}
func (t *Translator) LocalizeFromRequest(r *http.Request, id string, args map[string]interface{}) string {
return localize(t.localizerFromRequest(r), id, args)
}

View File

@ -0,0 +1,54 @@
package model
import (
"time"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/domain"
)
type CustomTextView struct {
AggregateID string
Template string
Language language.Tag
Key string
Text string
CreationDate time.Time
ChangeDate time.Time
Sequence uint64
}
type CustomTextSearchRequest struct {
Offset uint64
Limit uint64
SortingColumn CustomTextSearchKey
Asc bool
Queries []*CustomTextSearchQuery
}
type CustomTextSearchKey int32
const (
CustomTextSearchKeyUnspecified CustomTextSearchKey = iota
CustomTextSearchKeyAggregateID
CustomTextSearchKeyTemplate
CustomTextSearchKeyLanguage
CustomTextSearchKeyKey
)
type CustomTextSearchQuery struct {
Key CustomTextSearchKey
Method domain.SearchMethod
Value interface{}
}
type CustomTextSearchResponse struct {
Offset uint64
Limit uint64
TotalResult uint64
Result []*CustomTextView
Sequence uint64
Timestamp time.Time
}

View File

@ -0,0 +1,87 @@
package view
import (
"github.com/jinzhu/gorm"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
)
func GetCustomTexts(db *gorm.DB, table string, aggregateID, template, lang string) ([]*model.CustomTextView, error) {
texts := make([]*model.CustomTextView, 0)
queries := []*iam_model.CustomTextSearchQuery{
{
Key: iam_model.CustomTextSearchKeyAggregateID,
Value: aggregateID,
Method: domain.SearchMethodEquals,
},
{
Key: iam_model.CustomTextSearchKeyTemplate,
Value: template,
Method: domain.SearchMethodEquals,
},
{
Key: iam_model.CustomTextSearchKeyLanguage,
Value: lang,
Method: domain.SearchMethodEquals,
},
}
query := repository.PrepareSearchQuery(table, model.CustomTextSearchRequest{Queries: queries})
_, err := query(db, &texts)
if err != nil {
return nil, err
}
return texts, nil
}
func GetCustomTextsByAggregateIDAndTemplate(db *gorm.DB, table string, aggregateID, template string) ([]*model.CustomTextView, error) {
texts := make([]*model.CustomTextView, 0)
queries := []*iam_model.CustomTextSearchQuery{
{
Key: iam_model.CustomTextSearchKeyAggregateID,
Value: aggregateID,
Method: domain.SearchMethodEquals,
},
{
Key: iam_model.CustomTextSearchKeyTemplate,
Value: template,
Method: domain.SearchMethodEquals,
},
}
query := repository.PrepareSearchQuery(table, model.CustomTextSearchRequest{Queries: queries})
_, err := query(db, &texts)
if err != nil {
return nil, err
}
return texts, nil
}
func CustomTextByIDs(db *gorm.DB, table, aggregateID, template, lang, key string) (*model.CustomTextView, error) {
customText := new(model.CustomTextView)
aggregateIDQuery := &model.CustomTextSearchQuery{Key: iam_model.CustomTextSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
textTypeQuery := &model.CustomTextSearchQuery{Key: iam_model.CustomTextSearchKeyTemplate, Value: template, Method: domain.SearchMethodEquals}
languageQuery := &model.CustomTextSearchQuery{Key: iam_model.CustomTextSearchKeyLanguage, Value: lang, Method: domain.SearchMethodEquals}
keyQuery := &model.CustomTextSearchQuery{Key: iam_model.CustomTextSearchKeyKey, Value: key, Method: domain.SearchMethodEquals}
query := repository.PrepareGetByQuery(table, aggregateIDQuery, textTypeQuery, languageQuery, keyQuery)
err := query(db, customText)
if caos_errs.IsNotFound(err) {
return nil, caos_errs.ThrowNotFound(nil, "VIEW-8nUU3", "Errors.CustomCustomText.NotExisting")
}
return customText, err
}
func PutCustomText(db *gorm.DB, table string, customText *model.CustomTextView) error {
save := repository.PrepareSave(table)
return save(db, customText)
}
func DeleteCustomText(db *gorm.DB, table, aggregateID, template, lang string) error {
aggregateIDSearch := repository.Key{Key: model.CustomTextSearchKey(iam_model.CustomTextSearchKeyAggregateID), Value: aggregateID}
templateSearch := repository.Key{Key: model.CustomTextSearchKey(iam_model.CustomTextSearchKeyTemplate), Value: template}
languageSearch := repository.Key{Key: model.CustomTextSearchKey(iam_model.CustomTextSearchKeyLanguage), Value: lang}
delete := repository.PrepareDeleteByKeys(table, aggregateIDSearch, templateSearch, languageSearch)
return delete(db)
}

View File

@ -0,0 +1,877 @@
package model
import (
"encoding/json"
"strings"
"time"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/domain"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/iam/model"
)
const (
CustomTextKeyAggregateID = "aggregate_id"
CustomTextKeyTemplate = "template"
CustomTextKeyLanguage = "language"
CustomTextKeyKey = "key"
)
type CustomTextView struct {
AggregateID string `json:"-" gorm:"column:aggregate_id;primary_key"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
Template string `json:"Template" gorm:"column:template;primary_key"`
Language string `json:"Language" gorm:"column:language;primary_key"`
Key string `json:"Key" gorm:"column:key;primary_key"`
Text string `json:"Text" gorm:"column:text"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
}
func CustomTextViewFromModel(template *model.CustomTextView) *CustomTextView {
return &CustomTextView{
AggregateID: template.AggregateID,
Sequence: template.Sequence,
CreationDate: template.CreationDate,
ChangeDate: template.ChangeDate,
Language: template.Language.String(),
Template: template.Template,
Key: template.Key,
Text: template.Text,
}
}
func CustomTextViewsToDomain(texts []*CustomTextView) []*domain.CustomText {
result := make([]*domain.CustomText, len(texts))
for i, text := range texts {
result[i] = CustomTextViewToDomain(text)
}
return result
}
func CustomTextViewToDomain(text *CustomTextView) *domain.CustomText {
lang := language.Make(text.Language)
return &domain.CustomText{
ObjectRoot: models.ObjectRoot{
AggregateID: text.AggregateID,
Sequence: text.Sequence,
CreationDate: text.CreationDate,
ChangeDate: text.ChangeDate,
},
Template: text.Template,
Language: lang,
Key: text.Key,
Text: text.Text,
}
}
func (i *CustomTextView) AppendEvent(event *models.Event) (err error) {
i.Sequence = event.Sequence
switch event.Type {
case es_model.CustomTextSet, org_es_model.CustomTextSet:
i.setRootData(event)
err = i.SetData(event)
if err != nil {
return err
}
i.ChangeDate = event.CreationDate
}
return err
}
func (r *CustomTextView) setRootData(event *models.Event) {
r.AggregateID = event.AggregateID
}
func (r *CustomTextView) SetData(event *models.Event) error {
if err := json.Unmarshal(event.Data, r); err != nil {
logging.Log("MODEL-3n9fs").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-5CVaR", "Could not unmarshal data")
}
return nil
}
func (r *CustomTextView) IsMessageTemplate() bool {
return r.Template == domain.InitCodeMessageType ||
r.Template == domain.PasswordResetMessageType ||
r.Template == domain.VerifyEmailMessageType ||
r.Template == domain.VerifyPhoneMessageType ||
r.Template == domain.DomainClaimedMessageType
}
func CustomTextViewsToLoginDomain(aggregateID, lang string, texts []*CustomTextView) *domain.CustomLoginText {
langTag := language.Make(lang)
result := &domain.CustomLoginText{
ObjectRoot: models.ObjectRoot{
AggregateID: aggregateID,
},
Language: langTag,
}
for _, text := range texts {
if text.CreationDate.Before(result.CreationDate) {
result.CreationDate = text.CreationDate
}
if text.ChangeDate.After(result.ChangeDate) {
result.ChangeDate = text.ChangeDate
}
if strings.HasPrefix(text.Key, domain.LoginKeySelectAccount) {
selectAccountKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyLogin) {
loginKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyPassword) {
passwordKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyUsernameChange) {
usernameChangeKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyUsernameChangeDone) {
usernameChangeDoneKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyInitPassword) {
initPasswordKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyInitPasswordDone) {
initPasswordDoneKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyEmailVerification) {
emailVerificationKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyEmailVerificationDone) {
emailVerificationDoneKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyInitializeUser) {
initializeUserKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyInitUserDone) {
initializeUserDoneKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyInitMFAPrompt) {
initMFAPromptKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyInitMFAOTP) {
initMFAOTPKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyInitMFAU2F) {
initMFAU2FKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyInitMFADone) {
initMFADoneKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyMFAProviders) {
mfaProvidersKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyVerifyMFAOTP) {
verifyMFAOTPKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyVerifyMFAU2F) {
verifyMFAU2FKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyPasswordless) {
passwordlessKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyPasswordChange) {
passwordChangeKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyPasswordChangeDone) {
passwordChangeDoneKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyPasswordResetDone) {
passwordResetDoneKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyRegistrationOption) {
registrationOptionKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyRegistrationUser) {
registrationUserKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyRegistrationOrg) {
registrationOrgKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyLinkingUserDone) {
linkingUserKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyExternalNotFound) {
externalUserNotFoundKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeySuccessLogin) {
successLoginKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyLogoutDone) {
logoutDoneKeyToDomain(text, result)
}
if strings.HasPrefix(text.Key, domain.LoginKeyFooter) {
footerKeyToDomain(text, result)
}
}
return result
}
func selectAccountKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeySelectAccountTitle {
result.SelectAccount.Title = text.Text
}
if text.Key == domain.LoginKeySelectAccountDescription {
result.SelectAccount.Description = text.Text
}
if text.Key == domain.LoginKeySelectAccountTitleLinkingProcess {
result.SelectAccount.TitleLinking = text.Text
}
if text.Key == domain.LoginKeySelectAccountDescriptionLinkingProcess {
result.SelectAccount.DescriptionLinking = text.Text
}
if text.Key == domain.LoginKeySelectAccountOtherUser {
result.SelectAccount.OtherUser = text.Text
}
if text.Key == domain.LoginKeySelectAccountSessionStateActive {
result.SelectAccount.SessionState0 = text.Text
}
if text.Key == domain.LoginKeySelectAccountSessionStateInactive {
result.SelectAccount.SessionState1 = text.Text
}
if text.Key == domain.LoginKeySelectAccountUserMustBeMemberOfOrg {
result.SelectAccount.MustBeMemberOfOrg = text.Text
}
}
func loginKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyLoginTitle {
result.Login.Title = text.Text
}
if text.Key == domain.LoginKeyLoginDescription {
result.Login.Description = text.Text
}
if text.Key == domain.LoginKeyLoginTitleLinkingProcess {
result.Login.TitleLinking = text.Text
}
if text.Key == domain.LoginKeyLoginDescriptionLinkingProcess {
result.Login.DescriptionLinking = text.Text
}
if text.Key == domain.LoginKeyLoginNameLabel {
result.Login.LoginNameLabel = text.Text
}
if text.Key == domain.LoginKeyLoginUsernamePlaceHolder {
result.Login.UsernamePlaceholder = text.Text
}
if text.Key == domain.LoginKeyLoginLoginnamePlaceHolder {
result.Login.LoginnamePlaceholder = text.Text
}
if text.Key == domain.LoginKeyLoginExternalUserDescription {
result.Login.ExternalUserDescription = text.Text
}
if text.Key == domain.LoginKeyLoginUserMustBeMemberOfOrg {
result.Login.MustBeMemberOfOrg = text.Text
}
if text.Key == domain.LoginKeyLoginRegisterButtonText {
result.Login.RegisterButtonText = text.Text
}
if text.Key == domain.LoginKeyLoginNextButtonText {
result.Login.NextButtonText = text.Text
}
}
func passwordKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyPasswordlessValidateTokenButtonText {
result.Password.Title = text.Text
}
if text.Key == domain.LoginKeyPasswordDescription {
result.Password.Description = text.Text
}
if text.Key == domain.LoginKeyPasswordLabel {
result.Password.PasswordLabel = text.Text
}
if text.Key == domain.LoginKeyPasswordResetLinkText {
result.Password.ResetLinkText = text.Text
}
if text.Key == domain.LoginKeyPasswordBackButtonText {
result.Password.BackButtonText = text.Text
}
if text.Key == domain.LoginKeyPasswordNextButtonText {
result.Password.NextButtonText = text.Text
}
if text.Key == domain.LoginKeyPasswordMinLength {
result.Password.MinLength = text.Text
}
if text.Key == domain.LoginKeyPasswordHasUppercase {
result.Password.HasUppercase = text.Text
}
if text.Key == domain.LoginKeyPasswordHasLowercase {
result.Password.HasLowercase = text.Text
}
if text.Key == domain.LoginKeyPasswordHasNumber {
result.Password.HasNumber = text.Text
}
if text.Key == domain.LoginKeyPasswordHasSymbol {
result.Password.HasSymbol = text.Text
}
if text.Key == domain.LoginKeyPasswordConfirmation {
result.Password.Confirmation = text.Text
}
}
func usernameChangeKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyUsernameChangeTitle {
result.UsernameChange.Title = text.Text
}
if text.Key == domain.LoginKeyUsernameChangeDescription {
result.UsernameChange.Description = text.Text
}
if text.Key == domain.LoginKeyUsernameChangeUsernameLabel {
result.UsernameChange.UsernameLabel = text.Text
}
if text.Key == domain.LoginKeyUsernameChangeCancelButtonText {
result.UsernameChange.CancelButtonText = text.Text
}
if text.Key == domain.LoginKeyUsernameChangeNextButtonText {
result.UsernameChange.NextButtonText = text.Text
}
}
func usernameChangeDoneKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyUsernameChangeDoneTitle {
result.UsernameChangeDone.Title = text.Text
}
if text.Key == domain.LoginKeyUsernameChangeDoneDescription {
result.UsernameChangeDone.Description = text.Text
}
if text.Key == domain.LoginKeyUsernameChangeDoneNextButtonText {
result.UsernameChangeDone.NextButtonText = text.Text
}
}
func initPasswordKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyInitPasswordTitle {
result.InitPassword.Title = text.Text
}
if text.Key == domain.LoginKeyInitPasswordDescription {
result.InitPassword.Description = text.Text
}
if text.Key == domain.LoginKeyInitPasswordCodeLabel {
result.InitPassword.CodeLabel = text.Text
}
if text.Key == domain.LoginKeyInitPasswordNewPasswordLabel {
result.InitPassword.NewPasswordLabel = text.Text
}
if text.Key == domain.LoginKeyInitPasswordNewPasswordConfirmLabel {
result.InitPassword.NewPasswordConfirmLabel = text.Text
}
if text.Key == domain.LoginKeyInitPasswordNextButtonText {
result.InitPassword.NextButtonText = text.Text
}
if text.Key == domain.LoginKeyInitPasswordResendButtonText {
result.InitPassword.ResendButtonText = text.Text
}
}
func initPasswordDoneKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyInitPasswordDoneTitle {
result.InitPasswordDone.Title = text.Text
}
if text.Key == domain.LoginKeyInitPasswordDoneDescription {
result.InitPasswordDone.Description = text.Text
}
if text.Key == domain.LoginKeyInitPasswordDoneNextButtonText {
result.InitPasswordDone.NextButtonText = text.Text
}
if text.Key == domain.LoginKeyInitPasswordDoneCancelButtonText {
result.InitPasswordDone.CancelButtonText = text.Text
}
}
func emailVerificationKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyEmailVerificationTitle {
result.EmailVerification.Title = text.Text
}
if text.Key == domain.LoginKeyEmailVerificationDescription {
result.EmailVerification.Description = text.Text
}
if text.Key == domain.LoginKeyEmailVerificationCodeLabel {
result.EmailVerification.CodeLabel = text.Text
}
if text.Key == domain.LoginKeyEmailVerificationNextButtonText {
result.EmailVerification.NextButtonText = text.Text
}
if text.Key == domain.LoginKeyEmailVerificationResendButtonText {
result.EmailVerification.ResendButtonText = text.Text
}
}
func emailVerificationDoneKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyEmailVerificationDoneTitle {
result.EmailVerificationDone.Title = text.Text
}
if text.Key == domain.LoginKeyEmailVerificationDoneDescription {
result.EmailVerificationDone.Description = text.Text
}
if text.Key == domain.LoginKeyEmailVerificationDoneNextButtonText {
result.EmailVerificationDone.NextButtonText = text.Text
}
if text.Key == domain.LoginKeyEmailVerificationDoneCancelButtonText {
result.EmailVerificationDone.CancelButtonText = text.Text
}
if text.Key == domain.LoginKeyEmailVerificationDoneLoginButtonText {
result.EmailVerificationDone.LoginButtonText = text.Text
}
}
func initializeUserKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyInitializeUserTitle {
result.InitUser.Title = text.Text
}
if text.Key == domain.LoginKeyInitializeUserDescription {
result.InitUser.Description = text.Text
}
if text.Key == domain.LoginKeyInitializeUserCodeLabel {
result.InitUser.CodeLabel = text.Text
}
if text.Key == domain.LoginKeyInitializeUserNewPasswordLabel {
result.InitUser.NewPasswordLabel = text.Text
}
if text.Key == domain.LoginKeyInitializeUserNewPasswordConfirmLabel {
result.InitUser.NewPasswordConfirmLabel = text.Text
}
if text.Key == domain.LoginKeyInitializeUserResendButtonText {
result.InitUser.ResendButtonText = text.Text
}
if text.Key == domain.LoginKeyInitializeUserNextButtonText {
result.InitUser.NextButtonText = text.Text
}
}
func initializeUserDoneKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyInitUserDone {
result.InitUserDone.Title = text.Text
}
if text.Key == domain.LoginKeyInitUserDoneDescription {
result.InitUserDone.Description = text.Text
}
if text.Key == domain.LoginKeyInitUserDoneCancelButtonText {
result.InitUserDone.CancelButtonText = text.Text
}
if text.Key == domain.LoginKeyInitUserDoneNextButtonText {
result.InitUserDone.NextButtonText = text.Text
}
}
func initMFAPromptKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyInitMFAPromptTitle {
result.InitMFAPrompt.Title = text.Text
}
if text.Key == domain.LoginKeyInitMFAPromptDescription {
result.InitMFAPrompt.Description = text.Text
}
if text.Key == domain.LoginKeyInitMFAPromptOTPOption {
result.InitMFAPrompt.Provider0 = text.Text
}
if text.Key == domain.LoginKeyInitMFAPromptU2FOption {
result.InitMFAPrompt.Provider1 = text.Text
}
if text.Key == domain.LoginKeyInitMFAPromptSkipButtonText {
result.InitMFAPrompt.SkipButtonText = text.Text
}
if text.Key == domain.LoginKeyInitMFAPromptNextButtonText {
result.InitMFAPrompt.NextButtonText = text.Text
}
}
func initMFAOTPKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyInitMFAOTPTitle {
result.InitMFAOTP.Title = text.Text
}
if text.Key == domain.LoginKeyInitMFAOTPDescription {
result.InitMFAOTP.Description = text.Text
}
if text.Key == domain.LoginKeyInitMFAOTPDescriptionOTP {
result.InitMFAOTP.OTPDescription = text.Text
}
if text.Key == domain.LoginKeyInitMFAOTPCodeLabel {
result.InitMFAOTP.CodeLabel = text.Text
}
if text.Key == domain.LoginKeyInitMFAOTPSecretLabel {
result.InitMFAOTP.SecretLabel = text.Text
}
if text.Key == domain.LoginKeyInitMFAOTPNextButtonText {
result.InitMFAOTP.NextButtonText = text.Text
}
if text.Key == domain.LoginKeyInitMFAOTPCancelButtonText {
result.InitMFAOTP.CancelButtonText = text.Text
}
}
func initMFAU2FKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyInitMFAU2FTitle {
result.InitMFAU2F.Title = text.Text
}
if text.Key == domain.LoginKeyInitMFAU2FDescription {
result.InitMFAU2F.Description = text.Text
}
if text.Key == domain.LoginKeyInitMFAU2FTokenNameLabel {
result.InitMFAU2F.TokenNameLabel = text.Text
}
if text.Key == domain.LoginKeyInitMFAU2FRegisterTokenButtonText {
result.InitMFAU2F.RegisterTokenButtonText = text.Text
}
if text.Key == domain.LoginKeyInitMFAU2FNotSupported {
result.InitMFAU2F.NotSupported = text.Text
}
if text.Key == domain.LoginKeyInitMFAU2FErrorRetry {
result.InitMFAU2F.ErrorRetry = text.Text
}
}
func initMFADoneKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyInitMFADoneTitle {
result.InitMFADone.Title = text.Text
}
if text.Key == domain.LoginKeyInitMFADoneDescription {
result.InitMFADone.Description = text.Text
}
if text.Key == domain.LoginKeyInitMFADoneCancelButtonText {
result.InitMFADone.CancelButtonText = text.Text
}
if text.Key == domain.LoginKeyInitMFADoneNextButtonText {
result.InitMFADone.NextButtonText = text.Text
}
}
func mfaProvidersKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyMFAProvidersChooseOther {
result.MFAProvider.ChooseOther = text.Text
}
if text.Key == domain.LoginKeyMFAProvidersOTP {
result.MFAProvider.Provider0 = text.Text
}
if text.Key == domain.LoginKeyMFAProvidersU2F {
result.MFAProvider.Provider1 = text.Text
}
}
func verifyMFAOTPKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyVerifyMFAOTPTitle {
result.VerifyMFAOTP.Title = text.Text
}
if text.Key == domain.LoginKeyVerifyMFAOTPDescription {
result.VerifyMFAOTP.Description = text.Text
}
if text.Key == domain.LoginKeyVerifyMFAOTPCodeLabel {
result.VerifyMFAOTP.CodeLabel = text.Text
}
if text.Key == domain.LoginKeyVerifyMFAOTPNextButtonText {
result.VerifyMFAOTP.NextButtonText = text.Text
}
}
func verifyMFAU2FKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyVerifyMFAU2FTitle {
result.VerifyMFAU2F.Title = text.Text
}
if text.Key == domain.LoginKeyVerifyMFAU2FDescription {
result.VerifyMFAU2F.Description = text.Text
}
if text.Key == domain.LoginKeyVerifyMFAU2FValidateTokenText {
result.VerifyMFAU2F.ValidateTokenButtonText = text.Text
}
if text.Key == domain.LoginKeyVerifyMFAU2FNotSupported {
result.VerifyMFAU2F.NotSupported = text.Text
}
if text.Key == domain.LoginKeyVerifyMFAU2FErrorRetry {
result.VerifyMFAU2F.ErrorRetry = text.Text
}
}
func passwordlessKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyPasswordlessTitle {
result.Passwordless.Title = text.Text
}
if text.Key == domain.LoginKeyPasswordlessDescription {
result.Passwordless.Description = text.Text
}
if text.Key == domain.LoginKeyPasswordlessLoginWithPwButtonText {
result.Passwordless.LoginWithPwButtonText = text.Text
}
if text.Key == domain.LoginKeyPasswordlessValidateTokenButtonText {
result.Passwordless.ValidateTokenButtonText = text.Text
}
if text.Key == domain.LoginKeyPasswordlessNotSupported {
result.Passwordless.NotSupported = text.Text
}
if text.Key == domain.LoginKeyPasswordlessErrorRetry {
result.Passwordless.ErrorRetry = text.Text
}
}
func passwordChangeKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyPasswordChangeTitle {
result.PasswordChange.Title = text.Text
}
if text.Key == domain.LoginKeyPasswordChangeDescription {
result.PasswordChange.Description = text.Text
}
if text.Key == domain.LoginKeyPasswordChangeOldPasswordLabel {
result.PasswordChange.OldPasswordLabel = text.Text
}
if text.Key == domain.LoginKeyPasswordChangeNewPasswordLabel {
result.PasswordChange.NewPasswordLabel = text.Text
}
if text.Key == domain.LoginKeyPasswordChangeNewPasswordConfirmLabel {
result.PasswordChange.NewPasswordConfirmLabel = text.Text
}
if text.Key == domain.LoginKeyPasswordChangeCancelButtonText {
result.PasswordChange.CancelButtonText = text.Text
}
if text.Key == domain.LoginKeyPasswordChangeNextButtonText {
result.PasswordChange.NextButtonText = text.Text
}
}
func passwordChangeDoneKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyPasswordChangeDoneTitle {
result.PasswordChangeDone.Title = text.Text
}
if text.Key == domain.LoginKeyPasswordChangeDoneDescription {
result.PasswordChangeDone.Description = text.Text
}
if text.Key == domain.LoginKeyPasswordChangeDoneNextButtonText {
result.PasswordChangeDone.NextButtonText = text.Text
}
}
func passwordResetDoneKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyPasswordResetDoneTitle {
result.PasswordResetDone.Title = text.Text
}
if text.Key == domain.LoginKeyPasswordResetDoneDescription {
result.PasswordResetDone.Description = text.Text
}
if text.Key == domain.LoginKeyPasswordResetDoneNextButtonText {
result.PasswordResetDone.NextButtonText = text.Text
}
}
func registrationOptionKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyRegistrationOptionTitle {
result.RegisterOption.Title = text.Text
}
if text.Key == domain.LoginKeyRegistrationOptionDescription {
result.RegisterOption.Description = text.Text
}
if text.Key == domain.LoginKeyRegistrationOptionExternalLoginDescription {
result.RegisterOption.ExternalLoginDescription = text.Text
}
if text.Key == domain.LoginKeyRegistrationOptionUserNameButtonText {
result.RegisterOption.RegisterUsernamePasswordButtonText = text.Text
}
}
func registrationUserKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyRegistrationUserTitle {
result.RegistrationUser.Title = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserDescription {
result.RegistrationUser.Description = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserDescriptionOrgRegister {
result.RegistrationUser.DescriptionOrgRegister = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserFirstnameLabel {
result.RegistrationUser.FirstnameLabel = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserLastnameLabel {
result.RegistrationUser.LastnameLabel = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserEmailLabel {
result.RegistrationUser.EmailLabel = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserUsernameLabel {
result.RegistrationUser.UsernameLabel = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserLanguageLabel {
result.RegistrationUser.LanguageLabel = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserGenderLabel {
result.RegistrationUser.GenderLabel = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserPasswordLabel {
result.RegistrationUser.PasswordLabel = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserPasswordConfirmLabel {
result.RegistrationUser.PasswordConfirmLabel = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserTOSAndPrivacyLabel {
result.RegistrationUser.TOSAndPrivacyLabel = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserTOSConfirm {
result.RegistrationUser.TOSConfirm = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserTOSLink {
result.RegistrationUser.TOSLink = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserTOSLinkText {
result.RegistrationUser.TOSLinkText = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserPrivacyConfirm {
result.RegistrationUser.PrivacyConfirm = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserPrivacyLink {
result.RegistrationUser.PrivacyLink = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserPrivacyLinkText {
result.RegistrationUser.PrivacyLinkText = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserExternalLoginDescription {
result.RegistrationUser.ExternalLoginDescription = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserNextButtonText {
result.RegistrationUser.NextButtonText = text.Text
}
if text.Key == domain.LoginKeyRegistrationUserBackButtonText {
result.RegistrationUser.BackButtonText = text.Text
}
}
func registrationOrgKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyRegisterOrgTitle {
result.RegistrationOrg.Title = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgDescription {
result.RegistrationOrg.Description = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgOrgNameLabel {
result.RegistrationOrg.OrgNameLabel = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgFirstnameLabel {
result.RegistrationOrg.FirstnameLabel = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgLastnameLabel {
result.RegistrationOrg.LastnameLabel = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgUsernameLabel {
result.RegistrationOrg.UsernameLabel = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgEmailLabel {
result.RegistrationOrg.EmailLabel = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgPasswordLabel {
result.RegistrationOrg.PasswordLabel = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgPasswordConfirmLabel {
result.RegistrationOrg.PasswordConfirmLabel = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgTOSAndPrivacyLabel {
result.RegistrationOrg.TOSAndPrivacyLabel = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgTOSConfirm {
result.RegistrationOrg.TOSConfirm = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgTOSLink {
result.RegistrationOrg.TOSLink = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgTOSLinkText {
result.RegistrationOrg.TOSLinkText = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgPrivacyConfirm {
result.RegistrationOrg.PrivacyConfirm = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgPrivacyLink {
result.RegistrationOrg.PrivacyLink = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgPrivacyLinkText {
result.RegistrationOrg.PrivacyLinkText = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgExternalLoginDescription {
result.RegistrationOrg.ExternalLoginDescription = text.Text
}
if text.Key == domain.LoginKeyRegisterOrgSaveButtonText {
result.RegistrationOrg.SaveButtonText = text.Text
}
}
func linkingUserKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyLinkingUserDoneTitle {
result.LinkingUsersDone.Title = text.Text
}
if text.Key == domain.LoginKeyLinkingUserDoneDescription {
result.LinkingUsersDone.Description = text.Text
}
if text.Key == domain.LoginKeyLinkingUserDoneCancelButtonText {
result.LinkingUsersDone.CancelButtonText = text.Text
}
if text.Key == domain.LoginKeyLinkingUserDoneNextButtonText {
result.LinkingUsersDone.NextButtonText = text.Text
}
}
func externalUserNotFoundKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyExternalNotFoundTitle {
result.ExternalNotFoundOption.Title = text.Text
}
if text.Key == domain.LoginKeyExternalNotFoundDescription {
result.ExternalNotFoundOption.Description = text.Text
}
if text.Key == domain.LoginKeyExternalNotFoundLinkButtonText {
result.ExternalNotFoundOption.LinkButtonText = text.Text
}
if text.Key == domain.LoginKeyExternalNotFoundAutoRegisterButtonText {
result.ExternalNotFoundOption.AutoRegisterButtonText = text.Text
}
}
func successLoginKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeySuccessLoginTitle {
result.LoginSuccess.Title = text.Text
}
if text.Key == domain.LoginKeySuccessLoginAutoRedirectDescription {
result.LoginSuccess.AutoRedirectDescription = text.Text
}
if text.Key == domain.LoginKeySuccessLoginRedirectedDescription {
result.LoginSuccess.RedirectedDescription = text.Text
}
if text.Key == domain.LoginKeySuccessLoginNextButtonText {
result.LoginSuccess.NextButtonText = text.Text
}
}
func logoutDoneKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyLogoutDoneTitle {
result.LogoutDone.Title = text.Text
}
if text.Key == domain.LoginKeyLogoutDoneDescription {
result.LogoutDone.Description = text.Text
}
if text.Key == domain.LoginKeyLogoutDoneLoginButtonText {
result.LogoutDone.LoginButtonText = text.Text
}
}
func footerKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyFooterTOS {
result.Footer.TOS = text.Text
}
if text.Key == domain.LoginKeyFooterTOSLink {
result.Footer.TOSLink = text.Text
}
if text.Key == domain.LoginKeyFooterPrivacy {
result.Footer.PrivacyPolicy = text.Text
}
if text.Key == domain.LoginKeyFooterPrivacyLink {
result.Footer.PrivacyPolicyLink = text.Text
}
if text.Key == domain.LoginKeyFooterHelp {
result.Footer.Help = text.Text
}
if text.Key == domain.LoginKeyFooterHelpLink {
result.Footer.HelpLink = text.Text
}
}

View File

@ -0,0 +1,65 @@
package model
import (
"github.com/caos/zitadel/internal/domain"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/view/repository"
)
type CustomTextSearchRequest iam_model.CustomTextSearchRequest
type CustomTextSearchQuery iam_model.CustomTextSearchQuery
type CustomTextSearchKey iam_model.CustomTextSearchKey
func (req CustomTextSearchRequest) GetLimit() uint64 {
return req.Limit
}
func (req CustomTextSearchRequest) GetOffset() uint64 {
return req.Offset
}
func (req CustomTextSearchRequest) GetSortingColumn() repository.ColumnKey {
if req.SortingColumn == iam_model.CustomTextSearchKeyUnspecified {
return nil
}
return CustomTextSearchKey(req.SortingColumn)
}
func (req CustomTextSearchRequest) GetAsc() bool {
return req.Asc
}
func (req CustomTextSearchRequest) GetQueries() []repository.SearchQuery {
result := make([]repository.SearchQuery, len(req.Queries))
for i, q := range req.Queries {
result[i] = CustomTextSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
}
return result
}
func (req CustomTextSearchQuery) GetKey() repository.ColumnKey {
return CustomTextSearchKey(req.Key)
}
func (req CustomTextSearchQuery) GetMethod() domain.SearchMethod {
return req.Method
}
func (req CustomTextSearchQuery) GetValue() interface{} {
return req.Value
}
func (key CustomTextSearchKey) ToColumnName() string {
switch iam_model.CustomTextSearchKey(key) {
case iam_model.CustomTextSearchKeyAggregateID:
return CustomTextKeyAggregateID
case iam_model.CustomTextSearchKeyTemplate:
return CustomTextKeyTemplate
case iam_model.CustomTextSearchKeyLanguage:
return CustomTextKeyLanguage
case iam_model.CustomTextSearchKeyKey:
return CustomTextKeyKey
default:
return ""
}
}

View File

@ -1,7 +1,6 @@
package model
import (
"encoding/json"
"time"
"golang.org/x/text/language"
@ -11,9 +10,6 @@ import (
es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/iam/model"
)
@ -103,7 +99,7 @@ func (i *MessageTextView) AppendEvent(event *models.Event) (err error) {
switch event.Type {
case es_model.CustomTextSet, org_es_model.CustomTextSet:
i.setRootData(event)
customText := new(CustomText)
customText := new(CustomTextView)
err = customText.SetData(event)
if err != nil {
return err
@ -131,7 +127,7 @@ func (i *MessageTextView) AppendEvent(event *models.Event) (err error) {
}
i.ChangeDate = event.CreationDate
case es_model.CustomTextRemoved, org_es_model.CustomTextRemoved:
customText := new(CustomText)
customText := new(CustomTextView)
err = customText.SetData(event)
if err != nil {
return err
@ -167,18 +163,3 @@ func (i *MessageTextView) AppendEvent(event *models.Event) (err error) {
func (r *MessageTextView) setRootData(event *models.Event) {
r.AggregateID = event.AggregateID
}
type CustomText struct {
Template string `json:"template"`
Key string `json:"key"`
Language language.Tag `json:"language"`
Text string `json:"text"`
}
func (r *CustomText) SetData(event *models.Event) error {
if err := json.Unmarshal(event.Data, r); err != nil {
logging.Log("MODEL-3n9fs").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-5CVaR", "Could not unmarshal data")
}
return nil
}

View File

@ -3,10 +3,15 @@ package eventstore
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"sync"
"time"
"github.com/caos/logging"
"github.com/ghodss/yaml"
"github.com/golang/protobuf/ptypes"
"github.com/caos/zitadel/internal/api/authz"
@ -31,12 +36,15 @@ import (
)
type OrgRepository struct {
SearchLimit uint64
Eventstore v1.Eventstore
View *mgmt_view.View
Roles []string
SystemDefaults systemdefaults.SystemDefaults
PrefixAvatarURL string
SearchLimit uint64
Eventstore v1.Eventstore
View *mgmt_view.View
Roles []string
SystemDefaults systemdefaults.SystemDefaults
PrefixAvatarURL string
LoginDir http.FileSystem
TranslationFileContents map[string][]byte
mutex sync.Mutex
}
func (repo *OrgRepository) OrgByID(ctx context.Context, id string) (*org_model.OrgView, error) {
@ -615,6 +623,52 @@ func (repo *OrgRepository) GetMessageText(ctx context.Context, orgID, textType,
return iam_es_model.MessageTextViewToModel(text), err
}
func (repo *OrgRepository) GetDefaultLoginTexts(ctx context.Context, lang string) (*domain.CustomLoginText, error) {
repo.mutex.Lock()
defer repo.mutex.Unlock()
contents, ok := repo.TranslationFileContents[lang]
if !ok {
contents, err := repo.readTranslationFile(fmt.Sprintf("/i18n/%s.yaml", lang))
if err != nil {
return nil, err
}
repo.TranslationFileContents[lang] = contents
}
loginTextMap := make(map[string]interface{})
if err := yaml.Unmarshal(contents, &loginTextMap); err != nil {
return nil, errors.ThrowInternal(err, "TEXT-l0fse", "Errors.TranslationFile.ReadError")
}
texts, err := repo.View.CustomTextsByAggregateIDAndTemplateAndLand(repo.SystemDefaults.IamID, domain.LoginCustomText, lang)
if err != nil {
return nil, err
}
for _, text := range texts {
keys := strings.Split(text.Key, ".")
screenTextMap, ok := loginTextMap[keys[0]].(map[string]interface{})
if !ok {
continue
}
screenTextMap[keys[1]] = text.Text
}
jsonbody, err := json.Marshal(loginTextMap)
if err != nil {
return nil, errors.ThrowInternal(err, "TEXT-2n8fs", "Errors.TranslationFile.MergeError")
}
loginText := new(domain.CustomLoginText)
if err := json.Unmarshal(jsonbody, &loginText); err != nil {
return nil, errors.ThrowInternal(err, "TEXT-2n8fs", "Errors.TranslationFile.MergeError")
}
return loginText, nil
}
func (repo *OrgRepository) GetLoginTexts(ctx context.Context, orgID, lang string) (*domain.CustomLoginText, error) {
texts, err := repo.View.CustomTextsByAggregateIDAndTemplateAndLand(orgID, domain.LoginCustomText, lang)
if err != nil {
return nil, err
}
return iam_es_model.CustomTextViewsToLoginDomain(repo.SystemDefaults.IamID, lang, texts), err
}
func (repo *OrgRepository) getOrgChanges(ctx context.Context, orgID string, lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*org_model.OrgChanges, error) {
query := org_view.ChangesQuery(orgID, lastSequence, limit, sortAscending, auditLogRetention)
@ -710,3 +764,15 @@ func (repo *OrgRepository) getIAMEvents(ctx context.Context, sequence uint64) ([
}
return repo.Eventstore.FilterEvents(ctx, query)
}
func (repo *OrgRepository) readTranslationFile(filename string) ([]byte, error) {
r, err := repo.LoginDir.Open(filename)
if err != nil {
return nil, errors.ThrowInternal(err, "TEXT-3n8fs", "Errors.TranslationFile.ReadError")
}
contents, err := ioutil.ReadAll(r)
if err != nil {
return nil, errors.ThrowInternal(err, "TEXT-322fs", "Errors.TranslationFile.ReadError")
}
return contents, nil
}

View File

@ -0,0 +1,121 @@
package handler
import (
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query"
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
type CustomText struct {
handler
subscription *v1.Subscription
}
func newCustomText(handler handler) *CustomText {
h := &CustomText{
handler: handler,
}
h.subscribe()
return h
}
func (m *CustomText) subscribe() {
m.subscription = m.es.Subscribe(m.AggregateTypes()...)
go func() {
for event := range m.subscription.Events {
query.ReduceEvent(m, event)
}
}()
}
const (
customTextTable = "management.custom_texts"
)
func (m *CustomText) ViewModel() string {
return customTextTable
}
func (_ *CustomText) AggregateTypes() []es_models.AggregateType {
return []es_models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
}
func (p *CustomText) CurrentSequence() (uint64, error) {
sequence, err := p.view.GetLatestCustomTextSequence()
if err != nil {
return 0, err
}
return sequence.CurrentSequence, nil
}
func (m *CustomText) EventQuery() (*es_models.SearchQuery, error) {
sequence, err := m.view.GetLatestCustomTextSequence()
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
func (m *CustomText) Reduce(event *es_models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
err = m.processCustomText(event)
}
return err
}
func (m *CustomText) processCustomText(event *es_models.Event) (err error) {
customText := new(iam_model.CustomTextView)
switch event.Type {
case iam_es_model.CustomTextSet, model.CustomTextSet:
text := new(iam_model.CustomTextView)
err = text.SetData(event)
if err != nil {
return err
}
customText, err = m.view.CustomTextByIDs(event.AggregateID, text.Template, text.Key, text.Language)
if err != nil && !caos_errs.IsNotFound(err) {
return err
}
if caos_errs.IsNotFound(err) {
err = nil
customText = new(iam_model.CustomTextView)
customText.Language = text.Language
customText.Template = text.Template
customText.CreationDate = event.CreationDate
}
err = customText.AppendEvent(event)
case iam_es_model.CustomTextRemoved, model.CustomTextRemoved:
text := new(iam_model.CustomTextView)
err = text.SetData(event)
if err != nil {
return err
}
return m.view.DeleteCustomText(event.AggregateID, text.Template, text.Language, event)
default:
return m.view.ProcessedCustomTextSequence(event)
}
if err != nil {
return err
}
return m.view.PutCustomText(customText, event)
}
func (m *CustomText) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-3m912", "id", event.AggregateID).WithError(err).Warn("something went wrong in custom text handler")
return spooler.HandleError(event, err, m.view.GetLatestCustomTextFailedEvent, m.view.ProcessedCustomTextFailedEvent, m.view.ProcessedCustomTextSequence, m.errorCountUntilSkip)
}
func (o *CustomText) OnSuccess() error {
return spooler.HandleSuccess(o.view.UpdateCustomTextSpoolerRunTimestamp)
}

View File

@ -83,6 +83,8 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
handler{view, bulkLimit, configs.cycleDuration("Features"), errorCount, es}),
newPrivacyPolicy(
handler{view, bulkLimit, configs.cycleDuration("PrivacyPolicy"), errorCount, es}),
newCustomText(
handler{view, bulkLimit, configs.cycleDuration("CustomText"), errorCount, es}),
}
}

View File

@ -120,7 +120,7 @@ func (m *LabelPolicy) processLabelPolicy(event *es_models.Event) (err error) {
}
func (m *LabelPolicy) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in label policy handler")
logging.LogWithFields("SPOOL-66Cs8", "id", event.AggregateID).WithError(err).Warn("something went wrong in label policy handler")
return spooler.HandleError(event, err, m.view.GetLatestLabelPolicyFailedEvent, m.view.ProcessedLabelPolicyFailedEvent, m.view.ProcessedLabelPolicySequence, m.errorCountUntilSkip)
}

View File

@ -132,7 +132,7 @@ func (m *LoginPolicy) processLoginPolicy(event *es_models.Event) (err error) {
}
func (m *LoginPolicy) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in login policy handler")
logging.LogWithFields("SPOOL-92n8F", "id", event.AggregateID).WithError(err).Warn("something went wrong in login policy handler")
return spooler.HandleError(event, err, m.view.GetLatestLoginPolicyFailedEvent, m.view.ProcessedLoginPolicyFailedEvent, m.view.ProcessedLoginPolicySequence, m.errorCountUntilSkip)
}

View File

@ -97,7 +97,7 @@ func (m *MailTemplate) processMailTemplate(event *es_models.Event) (err error) {
}
func (m *MailTemplate) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in label template handler")
logging.LogWithFields("SPOOL-1n87f", "id", event.AggregateID).WithError(err).Warn("something went wrong in label template handler")
return spooler.HandleError(event, err, m.view.GetLatestMailTemplateFailedEvent, m.view.ProcessedMailTemplateFailedEvent, m.view.ProcessedMailTemplateSequence, m.errorCountUntilSkip)
}

View File

@ -79,30 +79,36 @@ func (m *MessageText) processMessageText(event *es_models.Event) (err error) {
switch event.Type {
case iam_es_model.CustomTextSet, model.CustomTextSet,
iam_es_model.CustomTextRemoved, model.CustomTextRemoved:
text := new(iam_model.CustomText)
text := new(iam_model.CustomTextView)
err = text.SetData(event)
if err != nil {
return err
}
message, err = m.view.MessageTextByIDs(event.AggregateID, text.Template, text.Language.String())
if !text.IsMessageTemplate() {
return m.view.ProcessedMessageTextSequence(event)
}
message, err = m.view.MessageTextByIDs(event.AggregateID, text.Template, text.Language)
if err != nil && !caos_errs.IsNotFound(err) {
return err
}
if caos_errs.IsNotFound(err) {
err = nil
message = new(iam_model.MessageTextView)
message.Language = text.Language.String()
message.Language = text.Language
message.MessageTextType = text.Template
message.CreationDate = event.CreationDate
}
err = message.AppendEvent(event)
case model.CustomTextMessageRemoved:
text := new(iam_model.CustomText)
text := new(iam_model.CustomTextView)
err = text.SetData(event)
if err != nil {
return err
}
return m.view.DeleteMessageText(event.AggregateID, text.Template, text.Language.String(), event)
if !text.IsMessageTemplate() {
return m.view.ProcessedMessageTextSequence(event)
}
return m.view.DeleteMessageText(event.AggregateID, text.Template, text.Language, event)
default:
return m.view.ProcessedMessageTextSequence(event)
}
@ -113,7 +119,7 @@ func (m *MessageText) processMessageText(event *es_models.Event) (err error) {
}
func (m *MessageText) OnError(event *es_models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in label text handler")
logging.LogWithFields("SPOOL-om8Hu", "id", event.AggregateID).WithError(err).Warn("something went wrong in label text handler")
return spooler.HandleError(event, err, m.view.GetLatestMessageTextFailedEvent, m.view.ProcessedMessageTextFailedEvent, m.view.ProcessedMessageTextSequence, m.errorCountUntilSkip)
}

View File

@ -1,6 +1,9 @@
package eventsourcing
import (
"github.com/caos/logging"
"github.com/rakyll/statik/fs"
"github.com/caos/zitadel/internal/eventstore/v1"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/static"
@ -52,9 +55,21 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string, querie
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults, staticStorage)
assetsAPI := conf.APIDomain + "/assets/v1/"
statikLoginFS, err := fs.NewWithNamespace("login")
logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start login statik dir")
return &EsRepository{
spooler: spool,
OrgRepository: eventstore.OrgRepository{conf.SearchLimit, es, view, roles, systemDefaults, assetsAPI},
spooler: spool,
OrgRepository: eventstore.OrgRepository{
SearchLimit: conf.SearchLimit,
Eventstore: es,
View: view,
Roles: roles,
SystemDefaults: systemDefaults,
PrefixAvatarURL: assetsAPI,
LoginDir: statikLoginFS,
TranslationFileContents: make(map[string][]byte),
},
ProjectRepo: eventstore.ProjectRepo{es, conf.SearchLimit, view, roles, systemDefaults.IamID, assetsAPI},
UserRepo: eventstore.UserRepo{es, conf.SearchLimit, view, systemDefaults, assetsAPI},
UserGrantRepo: eventstore.UserGrantRepo{conf.SearchLimit, view, assetsAPI},

View File

@ -0,0 +1,57 @@
package view
import (
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
)
const (
customTextTable = "management.custom_texts"
)
func (v *View) CustomTextByIDs(aggregateID, template, lang, key string) (*model.CustomTextView, error) {
return view.CustomTextByIDs(v.Db, customTextTable, aggregateID, template, lang, key)
}
func (v *View) CustomTextsByAggregateIDAndTemplateAndLand(aggregateID, template, lang string) ([]*model.CustomTextView, error) {
return view.GetCustomTexts(v.Db, customTextTable, aggregateID, template, lang)
}
func (v *View) PutCustomText(template *model.CustomTextView, event *models.Event) error {
err := view.PutCustomText(v.Db, customTextTable, template)
if err != nil {
return err
}
return v.ProcessedCustomTextSequence(event)
}
func (v *View) DeleteCustomText(aggregateID, textType, lang string, event *models.Event) error {
err := view.DeleteCustomText(v.Db, customTextTable, aggregateID, textType, lang)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedCustomTextSequence(event)
}
func (v *View) GetLatestCustomTextSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(customTextTable)
}
func (v *View) ProcessedCustomTextSequence(event *models.Event) error {
return v.saveCurrentSequence(customTextTable, event)
}
func (v *View) UpdateCustomTextSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(customTextTable)
}
func (v *View) GetLatestCustomTextFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
return v.latestFailedEvent(customTextTable, sequence)
}
func (v *View) ProcessedCustomTextFailedEvent(failedEvent *global_view.FailedEvent) error {
return v.saveFailedEvent(failedEvent)
}

View File

@ -4,6 +4,7 @@ import (
"context"
"time"
"github.com/caos/zitadel/internal/domain"
iam_model "github.com/caos/zitadel/internal/iam/model"
org_model "github.com/caos/zitadel/internal/org/model"
@ -52,6 +53,9 @@ type OrgRepository interface {
GetDefaultMessageText(ctx context.Context, textType string, language string) (*iam_model.MessageTextView, error)
GetMessageText(ctx context.Context, orgID, textType, language string) (*iam_model.MessageTextView, error)
GetDefaultLoginTexts(ctx context.Context, lang string) (*domain.CustomLoginText, error)
GetLoginTexts(ctx context.Context, orgID, lang string) (*domain.CustomLoginText, error)
GetLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
GetPreviewLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
GetDefaultLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)

View File

@ -6,11 +6,12 @@ import (
"os"
"text/template"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/i18n"
"github.com/caos/logging"
"golang.org/x/text/language"
)
const (
@ -20,44 +21,64 @@ const (
)
type Renderer struct {
Templates map[string]*template.Template
translator *i18n.Translator
Templates map[string]*template.Template
dir http.FileSystem
translatorConfig i18n.TranslatorConfig
}
func NewRenderer(dir http.FileSystem, tmplMapping map[string]string, funcs map[string]interface{}, translatorConfig i18n.TranslatorConfig) (*Renderer, error) {
var err error
r := new(Renderer)
r.translator, err = i18n.NewTranslator(dir, translatorConfig)
if err != nil {
return nil, err
r := &Renderer{
dir: dir,
translatorConfig: translatorConfig,
}
err = r.loadTemplates(dir, tmplMapping, funcs)
err = r.loadTemplates(dir, nil, tmplMapping, funcs)
if err != nil {
return nil, err
}
return r, nil
}
func (r *Renderer) RenderTemplate(w http.ResponseWriter, req *http.Request, tmpl *template.Template, data interface{}, reqFuncs map[string]interface{}) {
reqFuncs = r.registerTranslateFn(req, reqFuncs)
func (r *Renderer) RenderTemplate(w http.ResponseWriter, req *http.Request, translator *i18n.Translator, tmpl *template.Template, data interface{}, reqFuncs map[string]interface{}) {
reqFuncs = r.registerTranslateFn(req, translator, reqFuncs)
if err := tmpl.Funcs(reqFuncs).Execute(w, data); err != nil {
logging.Log("RENDE-lF8F6w").WithError(err).WithField("template", tmpl.Name).Error("error rendering template")
}
}
func (r *Renderer) Localize(id string, args map[string]interface{}) string {
return r.translator.Localize(id, args)
func (r *Renderer) NewTranslator() (*i18n.Translator, error) {
return i18n.NewTranslator(r.dir, r.translatorConfig)
}
func (r *Renderer) LocalizeFromRequest(req *http.Request, id string, args map[string]interface{}) string {
return r.translator.LocalizeFromRequest(req, id, args)
}
func (r *Renderer) Lang(req *http.Request) language.Tag {
return r.translator.Lang(req)
func (r *Renderer) Localize(translator *i18n.Translator, id string, args map[string]interface{}) string {
if translator == nil {
return ""
}
return translator.Localize(id, args)
}
func (r *Renderer) loadTemplates(dir http.FileSystem, tmplMapping map[string]string, funcs map[string]interface{}) error {
funcs = r.registerTranslateFn(nil, funcs)
func (r *Renderer) AddMessages(translator *i18n.Translator, tag language.Tag, messages ...i18n.Message) error {
if translator == nil {
return nil
}
return translator.AddMessages(tag, messages...)
}
func (r *Renderer) LocalizeFromRequest(translator *i18n.Translator, req *http.Request, id string, args map[string]interface{}) string {
if translator == nil {
return ""
}
return translator.LocalizeFromRequest(req, id, args)
}
func (r *Renderer) ReqLang(translator *i18n.Translator, req *http.Request) language.Tag {
if translator == nil {
return language.Und
}
return translator.Lang(req)
}
func (r *Renderer) loadTemplates(dir http.FileSystem, translator *i18n.Translator, tmplMapping map[string]string, funcs map[string]interface{}) error {
funcs = r.registerTranslateFn(nil, translator, funcs)
funcs[TranslateFn] = func(id string, args ...interface{}) string {
return id
}
@ -100,10 +121,13 @@ func (r *Renderer) addFileToTemplate(dir http.FileSystem, tmpl *template.Templat
return nil
}
func (r *Renderer) registerTranslateFn(req *http.Request, funcs map[string]interface{}) map[string]interface{} {
func (r *Renderer) registerTranslateFn(req *http.Request, translator *i18n.Translator, funcs map[string]interface{}) map[string]interface{} {
if funcs == nil {
funcs = make(map[string]interface{})
}
if translator == nil {
return funcs
}
funcs[TranslateFn] = func(id string, args ...interface{}) string {
m := map[string]interface{}{}
var key string
@ -115,9 +139,9 @@ func (r *Renderer) registerTranslateFn(req *http.Request, funcs map[string]inter
m[key] = arg
}
if r == nil {
return r.Localize(id, m)
return r.Localize(translator, id, m)
}
return r.LocalizeFromRequest(req, id, m)
return r.LocalizeFromRequest(translator, req, id, m)
}
return funcs
}

View File

@ -11,7 +11,8 @@ import (
)
var (
CustomTextSetEventType = iamEventTypePrefix + policy.CustomTextSetEventType
CustomTextSetEventType = iamEventTypePrefix + policy.CustomTextSetEventType
CustomTextRemovedEventType = iamEventTypePrefix + policy.CustomTextRemovedEventType
)
type CustomTextSetEvent struct {
@ -44,3 +45,32 @@ func CustomTextSetEventMapper(event *repository.Event) (eventstore.EventReader,
return &CustomTextSetEvent{CustomTextSetEvent: *e.(*policy.CustomTextSetEvent)}, nil
}
type CustomTextRemovedEvent struct {
policy.CustomTextRemovedEvent
}
func NewCustomTextRemovedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
template,
key string,
language language.Tag,
) *CustomTextRemovedEvent {
return &CustomTextRemovedEvent{
CustomTextRemovedEvent: *policy.NewCustomTextRemovedEvent(
eventstore.NewBaseEventForPush(ctx, aggregate, CustomTextRemovedEventType),
template,
key,
language),
}
}
func CustomTextRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
e, err := policy.CustomTextRemovedEventMapper(event)
if err != nil {
return nil, err
}
return &CustomTextRemovedEvent{CustomTextRemovedEvent: *e.(*policy.CustomTextRemovedEvent)}, nil
}

View File

@ -59,5 +59,6 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
RegisterFilterEventMapper(MailTextAddedEventType, MailTextAddedEventMapper).
RegisterFilterEventMapper(MailTextChangedEventType, MailTextChangedEventMapper).
RegisterFilterEventMapper(CustomTextSetEventType, CustomTextSetEventMapper).
RegisterFilterEventMapper(CustomTextRemovedEventType, CustomTextRemovedEventMapper).
RegisterFilterEventMapper(FeaturesSetEventType, FeaturesSetEventMapper)
}

View File

@ -355,6 +355,9 @@ Errors:
AlreadyExists: Kundenspezifischer Text existiert bereits
Invalid: Kundenspezifischer Text ist ungültig
NotFound: Kundenspezifischer Text nicht gefunden
TranslationFile:
ReadError: Übersetzungsfile konnte nicht gelesen werden
MergeError: Übersetzungsfile konnte nicht mit benutzerdefinierten Übersetzungen zusammengeführt werden
EventTypes:
user:
added: Benutzer hinzugefügt

View File

@ -355,6 +355,9 @@ Errors:
AlreadyExists: Custom text already exists
Invalid: Custom text invalid
NotFound: Custom text not found
TranslationFile:
ReadError: Error in reading translation file
MergeError: Translation file could not be merged with custom translations
EventTypes:
user:
added: User added

View File

@ -43,7 +43,7 @@ func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, aut
baseData: l.getBaseData(r, authReq, "Change Password", errID, errMessage),
profileData: l.getProfileData(authReq),
}
policy, description, _ := l.getPasswordComplexityPolicy(r, authReq.UserOrgID)
policy, description, _ := l.getPasswordComplexityPolicy(r, authReq, authReq.UserOrgID)
if policy != nil {
data.PasswordPolicyDescription = description
data.MinLength = policy.MinLength
@ -60,11 +60,12 @@ func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, aut
data.HasNumber = NumberRegex
}
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangePassword], data, nil)
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplChangePassword], data, nil)
}
func (l *Login) renderChangePasswordDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) {
var errType, errMessage string
data := l.getUserData(r, authReq, "Password Change Done", errType, errMessage)
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangePasswordDone], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplChangePasswordDone], data, nil)
}

View File

@ -148,7 +148,8 @@ func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Requ
data := externalNotFoundOptionData{
baseData: l.getBaseData(r, authReq, "ExternalNotFoundOption", errID, errMessage),
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplExternalNotFoundOption], data, nil)
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplExternalNotFoundOption], data, nil)
}
func (l *Login) handleExternalNotFoundOptionCheck(w http.ResponseWriter, r *http.Request) {

View File

@ -103,14 +103,13 @@ func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authR
if userID == "" && authReq != nil {
userID = authReq.UserID
}
data := initPasswordData{
baseData: l.getBaseData(r, authReq, "Init Password", errID, errMessage),
profileData: l.getProfileData(authReq),
UserID: userID,
Code: code,
}
policy, description, _ := l.getPasswordComplexityPolicyByUserID(r, userID)
policy, description, _ := l.getPasswordComplexityPolicyByUserID(r, authReq, userID)
if policy != nil {
data.PasswordPolicyDescription = description
data.MinLength = policy.MinLength
@ -127,10 +126,11 @@ func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authR
data.HasNumber = NumberRegex
}
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitPassword], data, nil)
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplInitPassword], data, nil)
}
func (l *Login) renderInitPasswordDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) {
data := l.getUserData(r, authReq, "Password Init Done", "", "")
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitPasswordDone], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplInitPasswordDone], data, nil)
}

View File

@ -104,7 +104,7 @@ func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq *
Code: code,
PasswordSet: passwordSet,
}
policy, description, _ := l.getPasswordComplexityPolicyByUserID(r, userID)
policy, description, _ := l.getPasswordComplexityPolicyByUserID(r, nil, userID)
if policy != nil {
data.PasswordPolicyDescription = description
data.MinLength = policy.MinLength
@ -121,10 +121,11 @@ func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq *
data.HasNumber = NumberRegex
}
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitUser], data, nil)
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplInitUser], data, nil)
}
func (l *Login) renderInitUserDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) {
data := l.getUserData(r, authReq, "User Init Done", "", "")
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitUserDone], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplInitUserDone], data, nil)
}

View File

@ -19,5 +19,5 @@ func (l *Login) linkUsers(w http.ResponseWriter, r *http.Request, authReq *domai
func (l *Login) renderLinkUsersDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
var errType, errMessage string
data := l.getUserData(r, authReq, "Linking Users Done", errType, errMessage)
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplLinkUsersDone], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplLinkUsersDone], data, nil)
}

View File

@ -77,5 +77,5 @@ func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *dom
return authReq.LoginPolicy != nil && authReq.LoginPolicy.AllowExternalIDP && authReq.AllowedExternalIDPs != nil && len(authReq.AllowedExternalIDPs) > 0
},
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplLogin], data, funcs)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplLogin], data, funcs)
}

View File

@ -41,5 +41,5 @@ func (l *Login) renderSuccessAndCallback(w http.ResponseWriter, r *http.Request,
if authReq != nil {
data.RedirectURI = l.oidcAuthCallbackURL
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplLoginSuccess], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplLoginSuccess], data, nil)
}

View File

@ -14,5 +14,5 @@ func (l *Login) handleLogoutDone(w http.ResponseWriter, r *http.Request) {
func (l *Login) renderLogoutDone(w http.ResponseWriter, r *http.Request) {
data := l.getUserData(r, nil, "Logout Done", "", "")
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplLogoutDone], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(nil), l.renderer.Templates[tmplLogoutDone], data, nil)
}

View File

@ -81,7 +81,8 @@ func (l *Login) renderMailVerification(w http.ResponseWriter, r *http.Request, a
UserID: userID,
profileData: l.getProfileData(authReq),
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMailVerification], data, nil)
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplMailVerification], data, nil)
}
func (l *Login) renderMailVerified(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) {
@ -89,5 +90,6 @@ func (l *Login) renderMailVerified(w http.ResponseWriter, r *http.Request, authR
baseData: l.getBaseData(r, authReq, "Mail Verified", "", ""),
profileData: l.getProfileData(authReq),
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMailVerified], data, nil)
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplMailVerified], data, nil)
}

View File

@ -16,5 +16,6 @@ func (l *Login) renderMFAInitDone(w http.ResponseWriter, r *http.Request, authRe
var errType, errMessage string
data.baseData = l.getBaseData(r, authReq, "MFA Init Done", errType, errMessage)
data.profileData = l.getProfileData(authReq)
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAInitDone], data, nil)
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplMFAInitDone], data, nil)
}

View File

@ -37,7 +37,7 @@ func (l *Login) renderRegisterU2F(w http.ResponseWriter, r *http.Request, authRe
},
MFAType: model.MFATypeU2F,
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAU2FInit], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplMFAU2FInit], data, nil)
}
func (l *Login) handleRegisterU2F(w http.ResponseWriter, r *http.Request) {

View File

@ -78,7 +78,8 @@ func (l *Login) renderMFAInitVerify(w http.ResponseWriter, r *http.Request, auth
}
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAInitVerify], data, nil)
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplMFAInitVerify], data, nil)
}
func generateQrCode(url string) (string, error) {

View File

@ -73,7 +73,8 @@ func (l *Login) renderMFAPrompt(w http.ResponseWriter, r *http.Request, authReq
l.handleMFACreation(w, r, authReq, data)
return
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAPrompt], data, nil)
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplMFAPrompt], data, nil)
}
func (l *Login) handleMFACreation(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *mfaVerifyData) {

View File

@ -73,7 +73,7 @@ func (l *Login) renderMFAVerifySelected(w http.ResponseWriter, r *http.Request,
l.renderError(w, r, authReq, err)
return
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAVerify], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplMFAVerify], data, nil)
}
func removeSelectedProviderFromList(providers []domain.MFAType, selected domain.MFAType) []domain.MFAType {

View File

@ -44,7 +44,7 @@ func (l *Login) renderU2FVerification(w http.ResponseWriter, r *http.Request, au
MFAProviders: providers,
SelectedProvider: -1,
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplU2FVerification], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplU2FVerification], data, nil)
}
func (l *Login) handleU2FVerification(w http.ResponseWriter, r *http.Request) {

View File

@ -6,6 +6,7 @@ import (
"strconv"
"github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
)
@ -24,16 +25,16 @@ var (
hasSymbol = regexp.MustCompile(SymbolRegex).MatchString
)
func (l *Login) getPasswordComplexityPolicy(r *http.Request, orgID string) (*iam_model.PasswordComplexityPolicyView, string, error) {
func (l *Login) getPasswordComplexityPolicy(r *http.Request, authReq *domain.AuthRequest, orgID string) (*iam_model.PasswordComplexityPolicyView, string, error) {
policy, err := l.authRepo.GetMyPasswordComplexityPolicy(setContext(r.Context(), orgID))
if err != nil {
return nil, err.Error(), err
}
description, err := l.generatePolicyDescription(r, policy)
description, err := l.generatePolicyDescription(r, authReq, policy)
return policy, description, nil
}
func (l *Login) getPasswordComplexityPolicyByUserID(r *http.Request, userID string) (*iam_model.PasswordComplexityPolicyView, string, error) {
func (l *Login) getPasswordComplexityPolicyByUserID(r *http.Request, authReq *domain.AuthRequest, userID string) (*iam_model.PasswordComplexityPolicyView, string, error) {
user, err := l.authRepo.UserByID(r.Context(), userID)
if err != nil {
return nil, "", nil
@ -42,31 +43,32 @@ func (l *Login) getPasswordComplexityPolicyByUserID(r *http.Request, userID stri
if err != nil {
return nil, err.Error(), err
}
description, err := l.generatePolicyDescription(r, policy)
description, err := l.generatePolicyDescription(r, authReq, policy)
return policy, description, nil
}
func (l *Login) generatePolicyDescription(r *http.Request, policy *iam_model.PasswordComplexityPolicyView) (string, error) {
func (l *Login) generatePolicyDescription(r *http.Request, authReq *domain.AuthRequest, policy *iam_model.PasswordComplexityPolicyView) (string, error) {
description := "<ul class=\"lgn-no-dots lgn-policy\" id=\"passwordcomplexity\">"
minLength := l.renderer.LocalizeFromRequest(r, "Password.MinLength", nil)
translator := l.getTranslator(authReq)
minLength := l.renderer.LocalizeFromRequest(translator, r, "Password.MinLength", nil)
description += "<li id=\"minlength\" class=\"invalid\"><i class=\"lgn-icon-times-solid lgn-warn\"></i><span>" + minLength + " " + strconv.Itoa(int(policy.MinLength)) + "</span></li>"
if policy.HasUppercase {
uppercase := l.renderer.LocalizeFromRequest(r, "Password.HasUppercase", nil)
uppercase := l.renderer.LocalizeFromRequest(translator, r, "Password.HasUppercase", nil)
description += "<li id=\"uppercase\" class=\"invalid\"><i class=\"lgn-icon-times-solid lgn-warn\"></i><span>" + uppercase + "</span></li>"
}
if policy.HasLowercase {
lowercase := l.renderer.LocalizeFromRequest(r, "Password.HasLowercase", nil)
lowercase := l.renderer.LocalizeFromRequest(translator, r, "Password.HasLowercase", nil)
description += "<li id=\"lowercase\" class=\"invalid\"><i class=\"lgn-icon-times-solid lgn-warn\"></i><span>" + lowercase + "</span></li>"
}
if policy.HasNumber {
hasnumber := l.renderer.LocalizeFromRequest(r, "Password.HasNumber", nil)
hasnumber := l.renderer.LocalizeFromRequest(translator, r, "Password.HasNumber", nil)
description += "<li id=\"number\" class=\"invalid\"><i class=\"lgn-icon-times-solid lgn-warn\"></i><span>" + hasnumber + "</span></li>"
}
if policy.HasSymbol {
hassymbol := l.renderer.LocalizeFromRequest(r, "Password.HasSymbol", nil)
hassymbol := l.renderer.LocalizeFromRequest(translator, r, "Password.HasSymbol", nil)
description += "<li id=\"symbol\" class=\"invalid\"><i class=\"lgn-icon-times-solid lgn-warn\"></i><span>" + hassymbol + "</span></li>"
}
confirmation := l.renderer.LocalizeFromRequest(r, "Password.Confirmation", nil)
confirmation := l.renderer.LocalizeFromRequest(translator, r, "Password.Confirmation", nil)
description += "<li id=\"confirmation\" class=\"invalid\"><i class=\"lgn-icon-times-solid lgn-warn\"></i><span>" + confirmation + "</span></li>"
description += "</ul>"

View File

@ -29,7 +29,7 @@ func (l *Login) renderPassword(w http.ResponseWriter, r *http.Request, authReq *
return true
},
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPassword], data, funcs)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplPassword], data, funcs)
}
func (l *Login) handlePasswordCheck(w http.ResponseWriter, r *http.Request) {

View File

@ -30,5 +30,5 @@ func (l *Login) renderPasswordResetDone(w http.ResponseWriter, r *http.Request,
errID, errMessage = l.getErrorMessage(r, err)
}
data := l.getUserData(r, authReq, "Password Reset Done", errID, errMessage)
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPasswordResetDone], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplPasswordResetDone], data, nil)
}

View File

@ -46,7 +46,7 @@ func (l *Login) renderPasswordlessVerification(w http.ResponseWriter, r *http.Re
},
passwordLogin,
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPasswordlessVerification], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplPasswordlessVerification], data, nil)
}
func (l *Login) handlePasswordlessVerification(w http.ResponseWriter, r *http.Request) {

View File

@ -36,6 +36,7 @@ type registerData struct {
HasNumber string
HasSymbol string
ShowUsername bool
OrgRegister bool
}
func (l *Login) handleRegister(w http.ResponseWriter, r *http.Request) {
@ -96,11 +97,12 @@ func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authReque
if err != nil {
errID, errMessage = l.getErrorMessage(r, err)
}
translator := l.getTranslator(authRequest)
if formData == nil {
formData = new(registerFormData)
}
if formData.Language == "" {
formData.Language = l.renderer.Lang(r).String()
formData.Language = l.renderer.ReqLang(translator, r).String()
}
data := registerData{
baseData: l.getBaseData(r, authRequest, "Register", errID, errMessage),
@ -118,7 +120,7 @@ func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authReque
resourceOwner = iam.GlobalOrgID
}
pwPolicy, description, _ := l.getPasswordComplexityPolicy(r, resourceOwner)
pwPolicy, description, _ := l.getPasswordComplexityPolicy(r, authRequest, resourceOwner)
if pwPolicy != nil {
data.PasswordPolicyDescription = description
data.MinLength = pwPolicy.MinLength
@ -142,6 +144,7 @@ func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authReque
return
}
data.ShowUsername = orgIAMPolicy.UserLoginMustBeDomain
data.OrgRegister = orgIAMPolicy.UserLoginMustBeDomain
funcs := map[string]interface{}{
"selectedLanguage": func(l string) bool {
@ -157,7 +160,7 @@ func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authReque
return formData.Gender == g
},
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplRegister], data, funcs)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplRegister], data, funcs)
}
func (d registerFormData) toHumanDomain() *domain.Human {

View File

@ -40,7 +40,8 @@ func (l *Login) renderRegisterOption(w http.ResponseWriter, r *http.Request, aut
return authReq.LoginPolicy.AllowExternalIDP && authReq.AllowedExternalIDPs != nil && len(authReq.AllowedExternalIDPs) > 0
},
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplRegisterOption], data, funcs)
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplRegisterOption], data, funcs)
}
func (l *Login) handleRegisterOptionCheck(w http.ResponseWriter, r *http.Request) {

View File

@ -85,12 +85,11 @@ func (l *Login) renderRegisterOrg(w http.ResponseWriter, r *http.Request, authRe
if formData == nil {
formData = new(registerOrgFormData)
}
data := registerOrgData{
baseData: l.getBaseData(r, authRequest, "Register", errID, errMessage),
registerOrgFormData: *formData,
}
pwPolicy, description, _ := l.getPasswordComplexityPolicy(r, "0")
pwPolicy, description, _ := l.getPasswordComplexityPolicy(r, authRequest, "0")
if pwPolicy != nil {
data.PasswordPolicyDescription = description
data.MinLength = pwPolicy.MinLength
@ -113,7 +112,8 @@ func (l *Login) renderRegisterOrg(w http.ResponseWriter, r *http.Request, authRe
data.IamDomain = orgPolicy.IAMDomain
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplRegisterOrg], data, nil)
translator := l.getTranslator(authRequest)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplRegisterOrg], data, nil)
}
func (d registerOrgFormData) toUserDomain() *domain.Human {

View File

@ -284,7 +284,7 @@ func (l *Login) renderInternalError(w http.ResponseWriter, r *http.Request, auth
msg = err.Error()
}
data := l.getBaseData(r, authReq, "Error", "Internal", msg)
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplError], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplError], data, nil)
}
func (l *Login) getUserData(r *http.Request, authReq *domain.AuthRequest, title string, errType, errMessage string) userData {
@ -304,7 +304,7 @@ func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, title
ErrID: errType,
ErrMessage: errMessage,
},
Lang: l.renderer.Lang(r).String(),
Lang: l.renderer.ReqLang(l.getTranslator(authReq), r).String(),
Title: title,
Theme: l.getTheme(r),
ThemeMode: l.getThemeMode(r),
@ -338,6 +338,15 @@ func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, title
return baseData
}
func (l *Login) getTranslator(authReq *domain.AuthRequest) *i18n.Translator {
translator, _ := l.renderer.NewTranslator()
if authReq != nil {
l.addLoginTranslations(translator, authReq.DefaultTranslations)
l.addLoginTranslations(translator, authReq.OrgTranslations)
}
return translator
}
func (l *Login) getProfileData(authReq *domain.AuthRequest) profileData {
var userName, loginName, displayName, avatar string
if authReq != nil {
@ -357,7 +366,7 @@ func (l *Login) getProfileData(authReq *domain.AuthRequest) profileData {
func (l *Login) getErrorMessage(r *http.Request, err error) (errID, errMsg string) {
caosErr := new(caos_errs.CaosError)
if errors.As(err, &caosErr) {
localized := l.renderer.LocalizeFromRequest(r, caosErr.Message, nil)
localized := l.renderer.LocalizeFromRequest(l.getTranslator(nil), r, caosErr.Message, nil)
return caosErr.ID, localized
}
@ -416,6 +425,18 @@ func (l *Login) isDisplayLoginNameSuffix(authReq *domain.AuthRequest) bool {
}
return authReq.LabelPolicy != nil && !authReq.LabelPolicy.HideLoginNameSuffix
}
func (l *Login) addLoginTranslations(translator *i18n.Translator, customTexts []*domain.CustomText) {
for _, text := range customTexts {
msg := i18n.Message{
ID: text.Key,
Text: text.Text,
}
err := l.renderer.AddMessages(translator, text.Language, msg)
logging.Log("HANDLE-GD3g2").OnError(err).Warn("could no add message to translator")
}
}
func getRequestID(authReq *domain.AuthRequest, r *http.Request) string {
if authReq != nil {
return authReq.ID
@ -455,6 +476,7 @@ type baseData struct {
LoginPolicy *domain.LoginPolicy
IDPProviders []*domain.IDPProvider
LabelPolicy *domain.LabelPolicy
LoginTexts []*domain.CustomLoginText
}
type errorData struct {

View File

@ -21,7 +21,8 @@ func (l *Login) renderUserSelection(w http.ResponseWriter, r *http.Request, auth
Users: selectionData.Users,
Linking: len(authReq.LinkingUsers) > 0,
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplUserSelection], data, nil)
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplUserSelection], data, nil)
}
func (l *Login) handleSelectUser(w http.ResponseWriter, r *http.Request) {

View File

@ -20,7 +20,7 @@ func (l *Login) renderChangeUsername(w http.ResponseWriter, r *http.Request, aut
errID, errMessage = l.getErrorMessage(r, err)
}
data := l.getUserData(r, authReq, "Change Username", errID, errMessage)
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangeUsername], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplChangeUsername], data, nil)
}
func (l *Login) handleChangeUsername(w http.ResponseWriter, r *http.Request) {
@ -41,5 +41,5 @@ func (l *Login) handleChangeUsername(w http.ResponseWriter, r *http.Request) {
func (l *Login) renderChangeUsernameDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) {
var errType, errMessage string
data := l.getUserData(r, authReq, "Username Change Done", errType, errMessage)
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangeUsernameDone], data, nil)
l.renderer.RenderTemplate(w, r, l.getTranslator(authReq), l.renderer.Templates[tmplChangeUsernameDone], data, nil)
}

View File

@ -3,13 +3,15 @@ Login:
Description: Mit ZITADEL-Konto anmelden.
TitleLinking: Anmeldung für Benutzer Linking
DescriptionLinking: Gib deine Benutzerdaten ein um den externen Benutzer mit einem ZITADEL Benutzer zu linken.
Loginname: Loginname
LoginNameLabel: Loginname
UsernamePlaceHolder: username
LoginnamePlaceHolder: username@domain
ExternalLogin: Melde dich mit einem externen Benutzer an
ExternalUserDescription: Melde dich mit einem externen Benutzer an
MustBeMemberOfOrg: Der Benutzer muss der Organisation {{.OrgName}} angehören.
RegisterButtonText: registrieren
NextButtonText: weiter
UserSelection:
SelectAccount:
Title: Account auswählen
Description: Wähle deinen Account aus.
TitleLinking: Account auswählen um zu verlinken
@ -22,210 +24,228 @@ UserSelection:
Password:
Title: Willkommen zurück!
Description: Gib deine Benutzerdaten ein.
Password: Passwort
PasswordLabel: Passwort
MinLength: Mindestlänge
HasUppercase: Grossbuchstaben
HasLowercase: Kleinbuchstaben
HasNumber: Nummer
HasSymbol: Symbol
Confirmation: Bestätigung stimmt überein
ResetLinkText: Password zurücksetzen
BackButtonText: zurück
NextButtonText: weiter
UsernameChange:
Title: Usernamen ändern
Description: Wähle deinen neuen Benutzernamen
Username: Benutzernamen
UsernameLabel: Benutzernamen
CancelButtonText: abbrechen
NextButtonText: weiter
UsernameChangeDone:
Title: Username geändert
Description: Der Username wurde erfolgreich geändert.
NextButtonText: next
MFAVerify:
Title: Multifaktor verifizieren
Description: Verifiziere deinen Multifaktor
OTP: OTP (One Time Password)
Code: Code
InitPassword:
InitPassword:
Title: Passwort setzen
Description: Du hast einen Code erhalten, welcher im untenstehenden Formular eingegeben werden muss um ein neues Passwort zu setzen.
Code: Code
NewPassword: Neues Passwort
NewPasswordConfirm: Passwort bestätigen
CodeLabel: Code
NewPasswordLabel: Neues Passwort
NewPasswordConfirmLabel: Passwort bestätigen
ResendButtonText: erneut senden
NextButtonText: weiter
InitPasswordDone:
Title: Passwort gesetzt
Description: Passwort erfolgreich gesetzt
NextButtonText: weiter
CancelButtonText: abbrechen
InitUser:
Title: User aktivieren
Description: Du hast einen Code erhalten, welcher im untenstehenden Formular eingegeben werden muss um deine EMail zu verifizieren und ein neues Passwort zu setzen.
Code: Code
NewPassword: Neues Passwort
NewPasswordConfirm: Passwort bestätigen
CodeLabel: Code
NewPasswordLabel: Neues Passwort
NewPasswordConfirmLabel: Passwort bestätigen
NextButtonText: weiter
ResendButtonText: erneut senden
InitUserDone:
Title: User aktiviert
Description: EMail verifiziert und Passwort erfolgreich gesetzt
NextButtonText: weiter
CancelButtonText: abbrechen
MFA:
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
ChooseOther: oder wähle eine andere Option aus
MFAPrompt:
InitMFAPrompt:
Title: Multifaktor hinzufügen
Description: Möchtest du einen Mulitfaktor hinzufügen?
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
NextButtonText: weiter
SkipButtonText: überspringen
MFAInitVerify:
InitMFAOTP:
Title: Multifaktor Verifizierung
Description: Verifiziere deinen Multifaktor
OTPDescription: Scanne den Code mit einem Authentifizierungs-App (z.B Google Authenticator) oder kopiere das Secret und gib anschliessend den Code ein.
Secret: Secret
Code: Code
SecretLabel: Secret
CodeLabel: Code
NextButtonText: weiter
CancelButtonText: abbrechen
MFAInitDone:
Title: Multifaktor Verifizierung erstellt
Description: Multifikator Verifizierung erfolgreich abgeschlossen. Der Multifaktor muss bei jeder Anmeldung eingegeben werden.
MFAInitU2F:
InitMFAU2F:
Title: Multifaktor U2F / WebAuthN hinzufügen
Description: Füge dein Token hinzu, indem du einen Namen eingibst und den 'Token registrieren' Button drückst.
TokenNameLabel: Name des Tokens / Geräts
NotSupported: WebAuthN wird durch deinen Browser nicht unterstützt. Stelle sicher, dass du die aktuelle Version installiert hast oder nutze einen anderen (z.B. Chrome, Safari, Firefox)
RegisterTokenButtonText: Token registrieren
ErrorRetry: Versuche es erneut, erstelle eine neue Abfrage oder wähle einen andere Methode.
MFAVerifyU2F:
InitMFADone:
Title: Multifaktor Verifizierung erstellt
Description: Multifikator Verifizierung erfolgreich abgeschlossen. Der Multifaktor muss bei jeder Anmeldung eingegeben werden.
NextButtonText: weiter
CancelButtonText: abbrechen
MFAProvider:
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
ChooseOther: oder wähle eine andere Option aus
VerifyMFAOTP:
Title: Multifaktor verifizieren
Description: Verifiziere deinen Multifaktor
CodeLabel: Code
NextButtonText: next
VerifyMFAU2F:
Title: Multifaktor Verifizierung
Description: Verifiziere deinen Multifaktor U2F / WebAuthN Token
WebAuthN:
Name: Name des Tokens / Geräts
NotSupported: WebAuthN wird durch deinen Browser nicht unterstützt. Stelle sicher, dass du die aktuelle Version installiert hast oder nutze einen anderen (z.B. Chrome, Safari, Firefox)
Error:
Retry: Versuche es erneut, erstelle eine neue Abfrage oder wähle einen andere Methode.
ErrorRetry: Versuche es erneut, erstelle eine neue Abfrage oder wähle einen andere Methode.
ValidateTokenButtonText: Token validieren
Passwordless:
Title: Passwortlos einloggen
Description: Verifiziere dein Token
NotSupported: WebAuthN wird durch deinen Browser nicht unterstützt. Stelle sicher, dass du die aktuelle Version installiert hast oder nutze einen anderen (z.B. Chrome, Safari, Firefox)
ErrorRetry: Versuche es erneut, erstelle eine neue Abfrage oder wähle einen andere Methode.
LoginWithPwButtonText: Mit Passwort anmelden
ValidateTokenButtonText: Token validieren
PasswordChange:
Title: Passwort ändern
Description: Ändere dein Password in dem du dein altes und dann dein neuen Passwort eingibst.
OldPassword: Altes Passwort
NewPassword: Neues Passwort
NewPasswordConfirmation: Passwort Bestätigung
OldPasswordLabel: Altes Passwort
NewPasswordLabel: Neues Passwort
NewPasswordConfirmationLabel: Passwort Bestätigung
CancelButtonText: abbrechen
NextButtonText: weiter
PasswordChangeDone:
Title: Passwort ändern
Description: Das Passwort wurde erfolgreich geändert.
NextButtonText: weiter
PasswordResetDone:
Title: Resetlink versendet
Description: Prüfe dein E-Mail Postfach, um ein neues Passwort zu setzen.
PasswordSetDone:
Title: Passwort gesetzt
Description: Das Passwort wurde erfolgreich gesetzt.
NextButtonText: weiter
EmailVerification:
Title: E-Mail Verifizierung
Description: Du hast ein E-Mail zur Verifizierung deiner E-Mail Adresse bekommen. Gib den Code im untenstehenden Formular ein. Mit erneut versenden, wird dir ein neues E-Mail zugestellt.
Code: Code
CodeLabel: Code
NextButtonText: weiter
ResendButtonText: erneut sende
EmailVerificationDone:
Title: E-Mail Verifizierung
Description: Deine E-Mail Adresse wurde erfolgreich verifiziert.
NextButtonText: weiter
CancelButtonText: abbrechen
LoginButtonText: anmelden
RegisterOption:
Title: Registrations Möglichkeiten
Description: Wähle aus wie du dich registrieren möchtest.
RegisterUsernamePassword: Mit Benutzername Passwort
RegisterUsernamePasswordButtonText: Mit Benutzername Passwort
ExternalLoginDescription: oder registriere dich mit einem externen Benutzer
Registration:
RegistrationUser:
Title: Registration
Description: Gib deine Benutzerangaben an. Die E-Mail Adresse wird als Benutzernamen verwendet.
Email: E-Mail
Username: Benutzername
Firstname: Vorname
Lastname: Nachname
Language: Sprache
DescriptionOrgRegister: Gib deine Benutzerangaben an.
EmailLabel: E-Mail
UsernameLabel: Benutzername
FirstnameLabel: Vorname
LastnameLabel: Nachname
LanguageLabel: Sprache
German: Deutsch
English: English
Gender: Geschlecht
GenderLabel: Geschlecht
Female: weiblich
Male: männlich
Diverse: diverse
Password: Passwort
Password2: Passwort wiederholen
TosAndPrivacy: Allgemeine Geschäftsbedingungen und Datenschutz
PasswordLabel: Passwort
PasswordConfirmLabel: Passwort wiederholen
TosAndPrivacyLabel: Allgemeine Geschäftsbedingungen und Datenschutz
TosConfirm: Ich akzeptiere die
TosLinkText: AGBs
TosConfirmAnd: und die
PrivacyLinkText: Datenschutzerklärung
ExternalLogin: oder registriere dich mit einem externen Benutzer
BackButtonText: zurück
NextButtonText: weiter
RegistrationOrg:
Title: Organisations Registration
Description: Gib deinen Organisationsnamen und deine Benutzerangaben an.
OrgName: Organisationsname
OrgDomain: Domäne
Email: E-Mail
Username: Benutzername
Firstname: Vorname
Lastname: Nachname
Language: Sprache
German: Deutsch
English: English
Gender: Geschlecht
Female: weiblich
Male: männlich
Diverse: diverse
Password: Passwort
Password2: Passwort wiederholen
TosAndPrivacy: Allgemeine Geschäftsbedingungen und Datenschutz
OrgNameLabel: Organisationsname
EmailLabel: E-Mail
UsernameLabel: Benutzername
FirstnameLabel: Vorname
LastnameLabel: Nachname
PasswordLabel: Passwort
PasswordConfirmLabel: Passwort wiederholen
TosAndPrivacyLabel: Allgemeine Geschäftsbedingungen und Datenschutz
TosConfirm: Ich akzeptiere die
TosLinkText: AGBs
TosConfirmAnd: und die
PrivacyLinkText: Datenschutzerklärung
SaveButtonText: speichern
LinkingUsersDone:
Title: Benutzerlinking
Description: Benuzterlinking erledigt.
CancelButtonText: abbrechen
NextButtonText: weiter
ExternalNotFoundOption:
Title: Externer Benutzer
Description: Externer Benutzer konnte nicht gefunden werden. Willst du deinen Benutzer mit einem bestehenden verlinken oder diesen als neuen Benutzer registrieren.
Link: Verlinken
AutoRegister: Automatisches registrieren
LinkButtonText: Verlinken
AutoRegisterButtonText: Automatisches registrieren
LoginSuccess:
Title: Erfolgreich eingeloggt
AutoRedirect: Du wirst automatisch zurück in die Applikation geleitet. Danach kannst du diese Fenster schliessen.
Redirected: Du kannst diese Fenster nun schliessen.
AutoRedirectDescription: Du wirst automatisch zurück in die Applikation geleitet. Danach kannst du diese Fenster schliessen.
RedirectedDescription: Du kannst diese Fenster nun schliessen.
NextButtonText: weiter
LogoutDone:
Title: Ausgeloggt
Description: Du wurdest erfolgreich ausgeloggt.
Actions:
Login: anmelden
Next: weiter
Back: zurück
Resend: erneut senden
Skip: überspringen
Register: registrieren
ForgotPassword: Password zurücksetzen
Cancel: Abbrechen
Save: speichern
RegisterToken: Token registrieren
ValidateToken: Token validieren
Recreate: erneut erstellen
PasswordLogin: Mit Passwort anmelden
LoginButtonText: anmelden
Footer:
PoweredBy: Powered By
Tos: AGB
Privacy: Datenschutzerklärung
Help: Hilfe
HelpLink: https://docs.zitadel.ch/docs/manuals/user-login
Errors:
Internal: Es ist ein interner Fehler aufgetreten

View File

@ -3,13 +3,15 @@ Login:
Description: Enter your logindata.
TitleLinking: Login for userlinking
DescriptionLinking: Enter your login data to link your external user with a ZITADEL user.
Loginname: Loginname
LoginNameLabel: Loginname
UsernamePlaceHolder: username
LoginnamePlaceHolder: username@domain
ExternalLogin: Login with an external user.
ExternalUserDescription: Login with an external user.
MustBeMemberOfOrg: The user must be member of the {{.OrgName}} organisation.
RegisterButtonText: register
NextButtonText: next
UserSelection:
SelectAccount:
Title: Select account
Description: Use your ZITADEL-Account
TitleLinking: Select account for userlinking
@ -22,210 +24,227 @@ UserSelection:
Password:
Title: Password
Description: Enter your logindata.
Password: Password
PasswordLabel: Password
MinLength: Minimumlength
HasUppercase: Uppercase letter
HasLowercase: Lowercase letter
HasNumber: Number
HasSymbol: Symbol
Confirmation: Confirmation match
ResetLinkText: reset password
BackButtonText: back
NextButtonText: next
UsernameChange:
Title: Change Username
Description: Set your new username
Username: Username
UsernameLabel: Username
CancelButtonText: cancel
NextButtonText: next
UsernameChangeDone:
Title: Username changed
Description: Your username was changed successfully.
MFAVerify:
Title: Verify Multificator
Description: Verify your multifactor
OTP: OTP (One Time Password)
Code: Code
NextButtonText: next
InitPassword:
Title: Set Password
Description: You have received a code, which you have to enter in the form below, to set your new password.
Code: Code
NewPassword: New Password
NewPasswordConfirm: Confirm Password
CodeLabel: Code
NewPasswordLabel: New Password
NewPasswordConfirmLabel: Confirm Password
ResendButtonText: resend
NextButtonText: next
InitPasswordDone:
Title: Password set
Description: Password successfully set
NextButtonText: next
CancelButtonText: cancel
InitUser:
Title: Activate User
Description: You have received a code, which you have to enter in the form below, to verify your email and set your new password.
Code: Code
NewPassword: New Password
NewPasswordConfirm: Confirm Password
CodeLabel: Code
NewPasswordLabel: New Password
NewPasswordConfirmLabel: Confirm Password
NextButtonText: next
ResendButtonText: resend
InitUserDone:
Title: User activated
Description: Email verified and Password successfully set
NextButtonText: next
CancelButtonText: cancel
MFA:
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
ChooseOther: or choose an other option
MFAPrompt:
InitMFAPrompt:
Title: Multifactor Setup
Description: Would you like to setup multifactor authentication?
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
NextButtonText: weiter
SkipButtonText: überspringen
MFAInitVerify:
InitMFAOTP:
Title: Multifactor Verification
Description: Verify your multifactor.
OTPDescription: Scan the code with your authenticator app (e.g Google Authenticator) or copy the secret and insert the generated code below.
Secret: Secret
Code: Code
SecretLabel: Secret
CodeLabel: Code
NextButtonText: next
CancelButtonText: cancel
MFAInitDone:
Title: Multifcator Verification done
Description: Multifactor verification successfully done. The multifactor has to be entered on each login.
MFAInitU2F:
InitMFAU2F:
Title: Multifactor Setup U2F / WebAuthN
Description: Add your Token by providing a name and then clicking on the 'Register Token' button below.
TokenNameLabel: Name of the tokens / machine
NotSupported: WebAuthN is not supported by your browser. Please ensure it is up to date or use a different one (e.g. Chrome, Safari, Firefox)
RegisterTokenButtonText: Register Token
ErrorRetry: Retry, create a new challenge or choose a different method.
MFAVerifyU2F:
InitMFADone:
Title: Multifcator Verification done
Description: Multifactor verification successfully done. The multifactor has to be entered on each login.
NextButtonText: next
CancelButtonText: cancel
MFAProvider:
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
ChooseOther: or choose an other option
VerifyMFAOTP:
Title: Verify Multificator
Description: Verify your multifactor
CodeLabel: Code
NextButtonText: next
VerifyMFAU2F:
Title: Multifactor Verification
Description: Verify your multifactor U2F / WebAuthN token
WebAuthN:
Name: Name of the tokens / machine
NotSupported: WebAuthN is not supported by your browser. Please ensure it is up to date or use a different one (e.g. Chrome, Safari, Firefox)
Error:
Retry: Retry, create a new challenge or choose a different method.
NotSupported: WebAuthN wird durch deinen Browser nicht unterstützt. Stelle sicher, dass du die aktuelle Version installiert hast oder nutze einen anderen (z.B. Chrome, Safari, Firefox)
ErrorRetry: Versuche es erneut, erstelle eine neue Abfrage oder wähle einen andere Methode.
ValidateTokenButtonText: Validate Token
Passwordless:
Title: Login passwordless
Description: Verify your token
NotSupported: WebAuthN is not supported by your browser. Please ensure it is up to date or use a different one (e.g. Chrome, Safari, Firefox)
ErrorRetry: Retry, create a new challenge or choose a different method.
LoginWithPwButtonText: Login with password
ValidateTokenButtonText: Token validieren
PasswordChange:
Title: Change Password
Description: Change your password. Enter your old and new password.
OldPassword: Old Password
NewPassword: New Password
NewPasswordConfirmation: Password confirmation
OldPasswordLabel: Old Password
NewPasswordLabel: New Password
NewPasswordConfirmationLabel: Password confirmation
CancelButtonText: cancel
NextButtonText: next
PasswordChangeDone:
Title: Change Password
Description: Your password was changed successfully.
NextButtonText: next
PasswordResetDone:
Title: Reset link set
Description: Check your email to to reset your password.
PasswordSetDone:
Title: Password set
Description: Your password was set successfully.
NextButtonText: next
EmailVerification:
Title: E-Mail Verification
Description: We have sent you an email to verify your address. Please enter the code in the form below.
Code: Code
CodeLabel: Code
NextButtonText: next
ResendButtonText: resend
EmailVerificationDone:
Title: E-Mail Verification
Description: Your email address has been successfully verified.
NextButtonText: next
CancelButtonText: cancel
LoginButtonText: login
RegisterOption:
Title: Registration Options
Description: Choose how you'd like to register
RegisterUsernamePassword: With username password
RegisterUsernamePasswordButtonText: With username password
ExternalLoginDescription: or register with an external user
Registration:
RegistrationUser:
Title: Registration
Description: Enter your Userdata. Your email address will be used as loginname.
Email: E-Mail
Username: Username
Firstname: Firstname
Lastname: Lastname
Language: Language
DescriptionOrgRegister: Enter your Userdata.
EmailLabel: E-Mail
UsernameLabel: Username
FirstnameLabel: Firstname
LastnameLabel: Lastname
LanguageLabel: Language
German: Deutsch
English: English
Gender: Gender
GenderLabel: Gender
Female: Female
Male: Male
Diverse: diverse / X
Password: Password
Password2: Password confirmation
TosAndPrivacy: Terms and conditions
PasswordLabel: Password
PasswordConfirmLabel: Password confirmation
TosAndPrivacyLabel: Terms and conditions
TosConfirm: I accept the
TosLinkText: TOS
TosConfirmAnd: and the
PrivacyLinkText: privacy policy
ExternalLogin: or register with an external user
BackButtonText: back
NextButtonText: next
RegistrationOrg:
Title: Organisation Registration
Description: Enter your organisationname and userdata.
OrgName: Organisationname
OrgDomain: Domäne
Email: E-Mail
Username: Username
Firstname: Firstname
Lastname: Lastname
Language: Language
German: Deutsch
English: English
Gender: Gender
Female: Female
Male: Male
Diverse: diverse / X
Password: Password
Password2: Password confirmation
TosAndPrivacy: Terms and conditions
OrgNameLabel: Organisationname
EmailLabel: E-Mail
UsernameLabel: Username
FirstnameLabel: Firstname
LastnameLabel: Lastname
PasswordLabel: Password
PasswordConfirmLabel: Password confirmation
TosAndPrivacyLabel: Terms and conditions
TosConfirm: I accept the
TosLinkText: TOS
TosConfirmAnd: and the
PrivacyLinkText: privacy policy
SaveButtonText: save
LoginSuccess:
Title: Login successful
AutoRedirect: You will be directed back to your application automatically. If not, click on the button below. You can close the window afterwards.
Redirected: You can now close this window.
AutoRedirectDescription: You will be directed back to your application automatically. If not, click on the button below. You can close the window afterwards.
RedirectedDescription: You can now close this window.
NextButtonText: next
LogoutDone:
Title: Logged out
Description: You have logged out successfully.
LoginButtonText: login
LinkingUsersDone:
Title: Userlinking
Description: Userlinking done.
CancelButtonText: cancel
NextButtonText: next
ExternalNotFoundOption:
Title: External User
Description: External user not found. Do you want to link your user or auto register a new one.
Link: Link
AutoRegister: Auto register
Actions:
Login: login
Next: next
Back: back
Resend: resend
Skip: skip
Register: register
ForgotPassword: reset password
Cancel: cancel
Save: save
RegisterToken: Register Token
ValidateToken: Validate Token
Recreate: recreate
PasswordLogin: Login with password
LinkButtonText: Link
AutoRegisterButtonText: Auto register
Footer:
PoweredBy: Powered By
Tos: TOS
Privacy: Privacy policy
Help: Help
HelpLink: https://docs.zitadel.ch/docs/manuals/user-login
Errors:
Internal: An internal error occured

View File

@ -1,6 +1,7 @@
{{template "main-top" .}}
<div class="lgn-head">
<h1>{{t "PasswordChange.Title"}}</h1>
{{ template "user-profile" . }}
<p>{{t "PasswordChange.Description"}}</p>
@ -14,13 +15,13 @@
<div class="fields">
<div class="field">
<label class="lgn-label" for="change-old-password">{{t "PasswordChange.OldPassword"}}</label>
<label class="lgn-label" for="change-old-password">{{t "PasswordChange.OldPasswordLabel"}}</label>
<input class="lgn-input" type="password" id="change-old-password" name="change-old-password"
autocomplete="current-password" autofocus required>
</div>
<div class="field">
<label class="lgn-label" for="change-new-password">{{t "PasswordChange.NewPassword"}}</label>
<label class="lgn-label" for="change-new-password">{{t "PasswordChange.NewPasswordLabel"}}</label>
<input data-minlength="{{ .MinLength }}" data-has-uppercase="{{ .HasUppercase }}"
data-has-lowercase="{{ .HasLowercase }}" data-has-number="{{ .HasNumber }}"
data-has-symbol="{{ .HasSymbol }}" class="lgn-input" type="password" id="change-new-password"
@ -30,7 +31,7 @@
<div class="field">
<label class="lgn-label"
for="change-password-confirmation">{{t "PasswordChange.NewPasswordConfirmation"}}</label>
for="change-password-confirmation">{{t "PasswordChange.NewPasswordConfirmationLabel"}}</label>
<input class="lgn-input" type="password" id="change-password-confirmation"
name="change-password-confirmation" autocomplete="new-password" required>
</div>
@ -40,11 +41,11 @@
<div class="lgn-actions">
<a class="lgn-stroked-button lgn-primary" href="{{ loginUrl }}">
{{t "Actions.Cancel"}}
{{t "PasswordChange.CancelButtonText"}}
</a>
<span class="fill-space"></span>
<button type="submit" id="change-password-button" name="resend" value="false"
class="lgn-raised-button lgn-primary">{{t "Actions.Next"}}</button>
class="lgn-raised-button lgn-primary">{{t "PasswordChange.NextButtonText"}}</button>
</div>
</form>

View File

@ -1,6 +1,7 @@
{{template "main-top" .}}
<div class="lgn-head">
<h1>{{t "PasswordChangeDone.Title"}}</h1>
{{ template "user-profile" . }}
<p>{{t "PasswordChangeDone.Description"}}</p>
@ -13,11 +14,8 @@
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
<div class="lgn-actions">
<!-- <a class="lgn-stroked-button lgn-primary" href="{{ loginUrl }}">
{{t "Actions.Cancel"}}
</a> -->
<span class="fill-space"></span>
<button class="lgn-raised-button lgn-primary" type="submit">{{t "Actions.Next"}}</button>
<button class="lgn-raised-button lgn-primary" type="submit">{{t "PasswordChangeDone.NextButtonText"}}</button>
</div>
</form>

View File

@ -1,6 +1,8 @@
{{template "main-top" .}}
<div class="lgn-head">
<h1>{{t "UsernameChange.Title"}}</h1>
{{ template "user-profile" . }}
<p>{{t "UsernameChange.Description"}}</p>
@ -13,7 +15,7 @@
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
<div class="field">
<label class="lgn-label" for="username">{{t "UsernameChange.Username"}}</label>
<label class="lgn-label" for="username">{{t "UsernameChange.UsernameLabel"}}</label>
<input class="lgn-input" type="text" id="username" name="username" autocomplete="username" autofocus required>
</div>
@ -21,11 +23,11 @@
<div class="lgn-actions">
<a class="lgn-stroked-button lgn-primary" href="{{ loginUrl }}">
{{t "Actions.Cancel"}}
{{t "UsernameChange.CancelButtonText"}}
</a>
<span class="fill-space"></span>
<button type="submit" id="submit-button" value="false"
class="lgn-raised-button lgn-primary">{{t "Actions.Next"}}</button>
class="lgn-raised-button lgn-primary">{{t "UsernameChange.NextButtonText"}}</button>
</div>
</form>

View File

@ -1,6 +1,8 @@
{{template "main-top" .}}
<div class="lgn-head">
<h1>{{t "UsernameChangeDone.Title"}}</h1>
{{ template "user-profile" . }}
<p>{{t "UsernameChangeDone.Description"}}</p>
@ -15,7 +17,7 @@
<div class="lgn-actions">
<span class="fill-space"></span>
<button class="lgn-raised-button lgn-primary" type="submit">{{t "Actions.Next"}}</button>
<button class="lgn-raised-button lgn-primary" type="submit">{{t "UsernameChangeDone.NextButtonText"}}</button>
</div>
</form>

View File

@ -18,10 +18,10 @@
</button>
<button class="lgn-raised-button lgn-primary" name="link" value="true"
formnovalidate>{{t "ExternalNotFoundOption.Link"}}</button>
formnovalidate>{{t "ExternalNotFoundOption.LinkButtonText"}}</button>
<span class="fill-space"></span>
<button class="lgn-raised-button lgn-primary" name="autoregister" value="true"
formnovalidate>{{t "ExternalNotFoundOption.AutoRegister"}}</button>
formnovalidate>{{t "ExternalNotFoundOption.AutoRegisterButtonText"}}</button>
</div>
{{template "error-message" .}}

View File

@ -1,4 +1,3 @@
{{define "footer"}}
<footer>
{{ if hasWatermark .LabelPolicy }}
@ -14,6 +13,6 @@
{{ if .PrivacyLink }}
<a href="{{.PrivacyLink}}" rel="noopener noreferrer" target="_blank" alt="Privacy Policy">{{t "Footer.Privacy"}}</a>
{{end}}
<a href="https://docs.zitadel.ch/docs/manuals/user-login" target="_black" alt="Help">{{t "Footer.Help"}}</a>
<a href="{{t "Footer.HelpLink"}}" target="_black" alt="Help">{{t "Footer.Help"}}</a>
</footer>
{{end}}

View File

@ -1,6 +1,7 @@
{{template "main-top" .}}
<div class="lgn-head">
<h1>{{t "InitPassword.Title" }}</h1>
{{ template "user-profile" . }}
<p>{{t "InitPassword.Description" }}</p>
@ -15,12 +16,12 @@
<div class="fields">
<div class="field">
<label class="lgn-label" for="code">{{t "InitPassword.Code"}}</label>
<label class="lgn-label" for="code">{{t "InitPassword.CodeLabel"}}</label>
<input class="lgn-input" type="text" id="code" name="code" value="{{.Code}}" autocomplete="off" autofocus
required>
</div>
<div class="field">
<label class="lgn-label" for="password">{{t "InitPassword.NewPassword"}}</label>
<label class="lgn-label" for="password">{{t "InitPassword.NewPasswordLabel"}}</label>
<input data-minlength="{{ .MinLength }}" data-has-uppercase="{{ .HasUppercase }}"
data-has-lowercase="{{ .HasLowercase }}" data-has-number="{{ .HasNumber }}"
data-has-symbol="{{ .HasSymbol }}" class="lgn-input" type="password" id="password" name="password"
@ -28,7 +29,7 @@
{{ .PasswordPolicyDescription }}
</div>
<div class="field">
<label class="lgn-label" for="passwordconfirm">{{t "InitPassword.NewPasswordConfirm"}}</label>
<label class="lgn-label" for="passwordconfirm">{{t "InitPassword.NewPasswordConfirmLabel"}}</label>
<input class="lgn-input" type="password" id="passwordconfirm" name="passwordconfirm"
autocomplete="new-password" autofocus required>
</div>
@ -42,11 +43,11 @@
<i class="lgn-icon-arrow-left-solid"></i>
</a>
<button type="submit" id="init-button" name="resend" value="false"
class="lgn-raised-button lgn-primary">{{t "Actions.Next"}}</button>
class="lgn-raised-button lgn-primary">{{t "InitPassword.NextButtonText"}}</button>
<span class="fill-space"></span>
<button type="submit" name="resend" value="true" class="lgn-stroked-button" formnovalidate>{{t "Actions.Resend" }}</button>
<button type="submit" name="resend" value="true" class="lgn-stroked-button" formnovalidate>{{t "InitPassword.ResendButtonText" }}</button>
</div>
</form>

View File

@ -1,9 +1,10 @@
{{template "main-top" .}}
<div class="lgn-head">
<h1>{{t "InitPasswordDone.Title"}}</h1>
{{ template "user-profile" . }}
<p>{{t "PasswordSetDone.Description"}}</p>
<p>{{t "InitPasswordDone.Description"}}</p>
</div>
<form action="{{ loginUrl }}" method="POST">
@ -14,10 +15,10 @@
<div class="lgnactions">
<a class="lgn-stroked-button lgn-primary" href="{{ loginUrl }}">
{{t "Actions.Cancel"}}
{{t "InitPasswordDone.CancelButtonText"}}
</a>
<span class="fill-space"></span>
<button class="lgn-raised-button lgn-primary" type="submit">{{t "Actions.Next"}}</button>
<button class="lgn-raised-button lgn-primary" type="submit">{{t "InitPasswordDone.NextButtonText"}}</button>
</div>
</form>

View File

@ -1,6 +1,8 @@
{{template "main-top" .}}
<div class="lgn-head">
<h1>{{t "InitUser.Title" }}</h1>
{{ template "user-profile" . }}
<p>{{t "InitUser.Description" }}</p>
@ -16,14 +18,14 @@
<div class="fields">
<div class="field">
<label class="lgn-label" for="code">{{t "InitUser.Code"}}</label>
<label class="lgn-label" for="code">{{t "InitUser.CodeLabel"}}</label>
<input class="lgn-input" {{if .ErrMessage}}shake {{end}} type="text" id="code" name="code" value="{{.Code}}" autocomplete="off" autofocus
required>
</div>
{{ if not .PasswordSet }}
<div class="field">
<label class="lgn-label" for="password">{{t "InitUser.NewPassword"}}</label>
<label class="lgn-label" for="password">{{t "InitUser.NewPasswordLabel"}}</label>
<input data-minlength="{{ .MinLength }}" data-has-uppercase="{{ .HasUppercase }}"
data-has-lowercase="{{ .HasLowercase }}" data-has-number="{{ .HasNumber }}"
data-has-symbol="{{ .HasSymbol }}" class="lgn-input" type="password" id="password" name="password"
@ -31,7 +33,7 @@
{{ .PasswordPolicyDescription }}
</div>
<div class="field">
<label class="lgn-label" for="passwordconfirm">{{t "InitUser.NewPasswordConfirm"}}</label>
<label class="lgn-label" for="passwordconfirm">{{t "InitUser.NewPasswordConfirmLabel"}}</label>
<input class="lgn-input" type="password" id="passwordconfirm" name="passwordconfirm"
autocomplete="new-password" autofocus required>
</div>
@ -47,11 +49,11 @@
</a>
<button type="submit" id="init-button" name="resend" value="false"
class="lgn-primary lgn-raised-button">{{t "Actions.Next"}}</button>
class="lgn-primary lgn-raised-button">{{t "InitUser.NextButtonText"}}</button>
<span class="fill-space"></span>
<button type="submit" name="resend" value="true" class="lgn-stroked-button" formnovalidate>{{t "Actions.Resend" }}</button>
<button type="submit" name="resend" value="true" class="lgn-stroked-button" formnovalidate>{{t "InitUser.ResendButtonText" }}</button>
</div>
</form>

View File

@ -1,7 +1,7 @@
{{template "main-top" .}}
<div class="lgn-head">
<p>{{t "InitUserDone.Title"}}</p>
<h1>{{t "InitUserDone.Title"}}</h1>
{{ template "user-profile" . }}
@ -15,10 +15,10 @@
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
<div class="lgn-actions lgn-reverse-order">
<button class="lgn-raised-button lgn-primary" type="submit">{{t "Actions.Next"}}</button>
<button class="lgn-raised-button lgn-primary" type="submit">{{t "InitUserDone.NextButtonText"}}</button>
<span class="fill-space"></span>
<a class="lgn-stroked-button lgn-primary" href="{{ loginUrl }}">
{{t "Actions.Cancel"}}
{{t "InitUserDone.CancelButtonText"}}
</a>
</div>
</form>

View File

@ -1,6 +1,7 @@
{{template "main-top" .}}
<div class="lgn-head">
<h1>{{t "LinkingUsersDone.Title"}}</h1>
{{ template "user-profile" . }}
<p>{{t "LinkingUsersDone.Description"}}</p>
@ -14,10 +15,10 @@
<div class="lgn-actions">
<a class="lgn-stroked-button lgn-primary" href="{{ loginUrl }}">
{{t "Actions.Cancel"}}
{{t "LinkingUsersDone.CancelButtonText"}}
</a>
<span class="fill-space"></span>
<button class="lgn-raised-button lgn-primary" type="submit">{{t "Actions.Next"}}</button>
<button class="lgn-raised-button lgn-primary" type="submit">{{t "LinkingUsersDone.NextButtonText"}}</button>
</div>
</form>

Some files were not shown because too many files have changed in this diff Show More