mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 19:07:30 +00:00
feat: Custom message files (#1992)
* feat: add get custom message text to admin api * feat: read custom message texts from files * feat: get languages in apis * feat: get languages in apis * feat: get languages in apis * feat: pr feedback * feat: docs * feat: merge main
This commit is contained in:
@@ -10,10 +10,12 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/caos/zitadel/internal/i18n"
|
||||
iam_view "github.com/caos/zitadel/internal/iam/repository/view"
|
||||
"github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
|
||||
@@ -30,15 +32,30 @@ import (
|
||||
)
|
||||
|
||||
type IAMRepository struct {
|
||||
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
|
||||
Eventstore v1.Eventstore
|
||||
SearchLimit uint64
|
||||
View *admin_view.View
|
||||
SystemDefaults systemdefaults.SystemDefaults
|
||||
Roles []string
|
||||
PrefixAvatarURL string
|
||||
LoginDir http.FileSystem
|
||||
NotificationDir http.FileSystem
|
||||
LoginTranslationFileContents map[string][]byte
|
||||
NotificationTranslationFileContents map[string][]byte
|
||||
mutex sync.Mutex
|
||||
supportedLangs []language.Tag
|
||||
}
|
||||
|
||||
func (repo *IAMRepository) Languages(ctx context.Context) ([]language.Tag, error) {
|
||||
if len(repo.supportedLangs) == 0 {
|
||||
langs, err := i18n.SupportedLanguages(repo.LoginDir)
|
||||
if err != nil {
|
||||
logging.Log("ADMIN-tiMWs").WithError(err).Debug("unable to parse language")
|
||||
return nil, err
|
||||
}
|
||||
repo.supportedLangs = langs
|
||||
}
|
||||
return repo.supportedLangs, nil
|
||||
}
|
||||
|
||||
func (repo *IAMRepository) IAMMemberByID(ctx context.Context, iamID, userID string) (*iam_model.IAMMemberView, error) {
|
||||
@@ -365,21 +382,36 @@ func (repo *IAMRepository) SearchIAMMembersx(ctx context.Context, request *iam_m
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (repo *IAMRepository) GetDefaultMessageTexts(ctx context.Context) (*iam_model.MessageTextsView, error) {
|
||||
text, err := repo.View.MessageTexts(repo.SystemDefaults.IamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (repo *IAMRepository) GetDefaultMessageText(ctx context.Context, textType, lang string) (*domain.CustomMessageText, error) {
|
||||
repo.mutex.Lock()
|
||||
defer repo.mutex.Unlock()
|
||||
var err error
|
||||
contents, ok := repo.NotificationTranslationFileContents[lang]
|
||||
if !ok {
|
||||
contents, err = repo.readTranslationFile(repo.NotificationDir, fmt.Sprintf("/i18n/%s.yaml", lang))
|
||||
if caos_errs.IsNotFound(err) {
|
||||
contents, err = repo.readTranslationFile(repo.NotificationDir, fmt.Sprintf("/i18n/%s.yaml", repo.SystemDefaults.DefaultLanguage.String()))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repo.NotificationTranslationFileContents[lang] = contents
|
||||
}
|
||||
return iam_es_model.MessageTextsViewToModel(text, true), err
|
||||
messageTexts := new(domain.MessageTexts)
|
||||
if err := yaml.Unmarshal(contents, messageTexts); err != nil {
|
||||
return nil, caos_errs.ThrowInternal(err, "TEXT-3N9fs", "Errors.TranslationFile.ReadError")
|
||||
}
|
||||
return messageTexts.GetMessageTextByType(textType), nil
|
||||
}
|
||||
|
||||
func (repo *IAMRepository) GetDefaultMessageText(ctx context.Context, textType, lang string) (*iam_model.MessageTextView, error) {
|
||||
text, err := repo.View.MessageTextByIDs(repo.SystemDefaults.IamID, textType, lang)
|
||||
func (repo *IAMRepository) GetCustomMessageText(ctx context.Context, textType, lang string) (*domain.CustomMessageText, error) {
|
||||
texts, err := repo.View.CustomTextsByAggregateIDAndTemplateAndLand(repo.SystemDefaults.IamID, textType, lang)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
text.Default = true
|
||||
return iam_es_model.MessageTextViewToModel(text), err
|
||||
result := iam_es_model.CustomTextViewsToMessageDomain(repo.SystemDefaults.IamID, lang, texts)
|
||||
result.Default = true
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (repo *IAMRepository) GetDefaultPrivacyPolicy(ctx context.Context) (*iam_model.PrivacyPolicyView, error) {
|
||||
@@ -412,17 +444,17 @@ func (repo *IAMRepository) GetDefaultPrivacyPolicy(ctx context.Context) (*iam_mo
|
||||
func (repo *IAMRepository) GetDefaultLoginTexts(ctx context.Context, lang string) (*domain.CustomLoginText, error) {
|
||||
repo.mutex.Lock()
|
||||
defer repo.mutex.Unlock()
|
||||
contents, ok := repo.TranslationFileContents[lang]
|
||||
contents, ok := repo.LoginTranslationFileContents[lang]
|
||||
var err error
|
||||
if !ok {
|
||||
contents, err = repo.readTranslationFile(fmt.Sprintf("/i18n/%s.yaml", lang))
|
||||
contents, err = repo.readTranslationFile(repo.LoginDir, fmt.Sprintf("/i18n/%s.yaml", lang))
|
||||
if caos_errs.IsNotFound(err) {
|
||||
contents, err = repo.readTranslationFile(fmt.Sprintf("/i18n/%s.yaml", repo.SystemDefaults.DefaultLanguage.String()))
|
||||
contents, err = repo.readTranslationFile(repo.LoginDir, fmt.Sprintf("/i18n/%s.yaml", repo.SystemDefaults.DefaultLanguage.String()))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repo.TranslationFileContents[lang] = contents
|
||||
repo.LoginTranslationFileContents[lang] = contents
|
||||
}
|
||||
loginText := new(domain.CustomLoginText)
|
||||
if err := yaml.Unmarshal(contents, loginText); err != nil {
|
||||
@@ -447,8 +479,8 @@ 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)
|
||||
func (repo *IAMRepository) readTranslationFile(dir http.FileSystem, filename string) ([]byte, error) {
|
||||
r, err := dir.Open(filename)
|
||||
if os.IsNotExist(err) {
|
||||
return nil, caos_errs.ThrowNotFound(err, "TEXT-3n9fs", "Errors.TranslationFile.NotFound")
|
||||
}
|
||||
|
@@ -54,6 +54,9 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, s
|
||||
statikLoginFS, err := fs.NewWithNamespace("login")
|
||||
logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start login statik dir")
|
||||
|
||||
statikNotificationFS, err := fs.NewWithNamespace("notification")
|
||||
logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start notification statik dir")
|
||||
|
||||
return &EsRepository{
|
||||
spooler: spool,
|
||||
OrgRepo: eventstore.OrgRepo{
|
||||
@@ -63,14 +66,16 @@ 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,
|
||||
LoginDir: statikLoginFS,
|
||||
TranslationFileContents: make(map[string][]byte),
|
||||
Eventstore: es,
|
||||
View: view,
|
||||
SystemDefaults: systemDefaults,
|
||||
SearchLimit: conf.SearchLimit,
|
||||
Roles: roles,
|
||||
PrefixAvatarURL: assetsAPI,
|
||||
LoginDir: statikLoginFS,
|
||||
NotificationDir: statikNotificationFS,
|
||||
LoginTranslationFileContents: make(map[string][]byte),
|
||||
NotificationTranslationFileContents: make(map[string][]byte),
|
||||
},
|
||||
AdministratorRepo: eventstore.AdministratorRepo{
|
||||
View: view,
|
||||
|
@@ -2,6 +2,9 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||
|
||||
@@ -9,6 +12,8 @@ import (
|
||||
)
|
||||
|
||||
type IAMRepository interface {
|
||||
Languages(ctx context.Context) ([]language.Tag, error)
|
||||
|
||||
SearchIAMMembers(ctx context.Context, request *iam_model.IAMMemberSearchRequest) (*iam_model.IAMMemberSearchResponse, error)
|
||||
|
||||
GetIAMMemberRoles() []string
|
||||
@@ -29,8 +34,8 @@ type IAMRepository interface {
|
||||
|
||||
GetDefaultMailTemplate(ctx context.Context) (*iam_model.MailTemplateView, error)
|
||||
|
||||
GetDefaultMessageTexts(ctx context.Context) (*iam_model.MessageTextsView, error)
|
||||
GetDefaultMessageText(ctx context.Context, textType string, language string) (*iam_model.MessageTextView, error)
|
||||
GetDefaultMessageText(ctx context.Context, textType, language string) (*domain.CustomMessageText, error)
|
||||
GetCustomMessageText(ctx context.Context, textType string, language string) (*domain.CustomMessageText, error)
|
||||
GetDefaultLoginTexts(ctx context.Context, lang string) (*domain.CustomLoginText, error)
|
||||
GetCustomLoginTexts(ctx context.Context, lang string) (*domain.CustomLoginText, error)
|
||||
|
||||
|
Reference in New Issue
Block a user