Migrate codegen for locale to CUE
This commit is contained in:
206
codegen/assets/templates/gocode/locale/service.go.tpl
Normal file
206
codegen/assets/templates/gocode/locale/service.go.tpl
Normal file
@@ -0,0 +1,206 @@
|
||||
package {{ .package }}
|
||||
|
||||
{{ template "gocode/header-gentext.tpl" }}
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
{{- range .imports }}
|
||||
{{ . }}
|
||||
{{- end }}
|
||||
"github.com/cortezaproject/corteza-server/pkg/actionlog"
|
||||
intAuth "github.com/cortezaproject/corteza-server/pkg/auth"
|
||||
"github.com/cortezaproject/corteza-server/pkg/errors"
|
||||
"github.com/cortezaproject/corteza-server/pkg/locale"
|
||||
"github.com/cortezaproject/corteza-server/pkg/options"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
systemTypes "github.com/cortezaproject/corteza-server/system/types"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type (
|
||||
localeAccessControl interface {
|
||||
CanManageResourceTranslations(ctx context.Context) bool
|
||||
}
|
||||
|
||||
resourceTranslationsManager struct {
|
||||
actionlog actionlog.Recorder
|
||||
locale locale.Resource
|
||||
store store.Storer
|
||||
ac localeAccessController
|
||||
}
|
||||
|
||||
localeAccessController interface {
|
||||
CanManageResourceTranslations(context.Context) bool
|
||||
}
|
||||
|
||||
ResourceTranslationsManagerService interface {
|
||||
{{- range .resources }}
|
||||
{{ .expIdent }}(ctx context.Context, {{ range .references }}{{ . }} uint64, {{ end }}) (locale.ResourceTranslationSet, error)
|
||||
{{- end }}
|
||||
|
||||
Upsert(context.Context, locale.ResourceTranslationSet) error
|
||||
Locale() locale.Resource
|
||||
}
|
||||
)
|
||||
|
||||
var ErrNotAllowedToManageResourceTranslations = errors.Unauthorized("not allowed to manage resource translations")
|
||||
|
||||
func ResourceTranslationsManager(ls locale.Resource) *resourceTranslationsManager {
|
||||
return &resourceTranslationsManager{
|
||||
actionlog: DefaultActionlog,
|
||||
store: DefaultStore,
|
||||
ac: DefaultAccessControl,
|
||||
locale: ls,
|
||||
}
|
||||
}
|
||||
|
||||
func (svc resourceTranslationsManager) Upsert(ctx context.Context, rr locale.ResourceTranslationSet) (err error) {
|
||||
// User is allowed to manage resource translations when:
|
||||
// - managed resource translation strings are all for default language
|
||||
// or
|
||||
// - user is allowed to manage resource translations
|
||||
if rr.ContainsForeign(svc.Locale().Default().Tag) {
|
||||
if !svc.ac.CanManageResourceTranslations(ctx) {
|
||||
return ErrNotAllowedToManageResourceTranslations
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range rr {
|
||||
r.Msg = locale.SanitizeMessage(r.Msg)
|
||||
}
|
||||
|
||||
// @todo validation
|
||||
|
||||
me := intAuth.GetIdentityFromContext(ctx)
|
||||
|
||||
// - group by resource
|
||||
localeByRes := make(map[string]locale.ResourceTranslationSet)
|
||||
for _, r := range rr {
|
||||
localeByRes[r.Resource] = append(localeByRes[r.Resource], r)
|
||||
}
|
||||
|
||||
// - for each resource, fetch the current state
|
||||
sysLocale := make(systemTypes.ResourceTranslationSet, 0, len(rr))
|
||||
for res, rr := range localeByRes {
|
||||
current, _, err := store.SearchResourceTranslations(ctx, svc.store, systemTypes.ResourceTranslationFilter{
|
||||
Resource: res,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get deltas and prepare upsert accordingly
|
||||
aux := current.New(rr)
|
||||
aux.Walk(func(cc *systemTypes.ResourceTranslation) error {
|
||||
cc.ID = nextID()
|
||||
cc.CreatedAt = *now()
|
||||
cc.CreatedBy = me.Identity()
|
||||
|
||||
return nil
|
||||
})
|
||||
sysLocale = append(sysLocale, aux...)
|
||||
|
||||
aux = current.Old(rr)
|
||||
_ = aux.Walk(func(cc *systemTypes.ResourceTranslation) error {
|
||||
cc.UpdatedAt = now()
|
||||
cc.UpdatedBy = me.Identity()
|
||||
return nil
|
||||
})
|
||||
sysLocale = append(sysLocale, aux...)
|
||||
}
|
||||
|
||||
err = store.UpsertResourceTranslation(ctx, svc.store, sysLocale...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Reload ALL resource translations
|
||||
// @todo we could probably do this more selectively and refresh only updated resources?
|
||||
_ = locale.Global().ReloadResourceTranslations(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc resourceTranslationsManager) Locale() locale.Resource {
|
||||
return svc.locale
|
||||
}
|
||||
|
||||
{{- range .resources }}
|
||||
|
||||
func (svc resourceTranslationsManager) {{ .expIdent }}(ctx context.Context, {{ range .references }}{{ . }} uint64, {{ end }}) (locale.ResourceTranslationSet, error) {
|
||||
var (
|
||||
err error
|
||||
out locale.ResourceTranslationSet
|
||||
res *types.{{ .expIdent }}
|
||||
k types.LocaleKey
|
||||
)
|
||||
|
||||
res, err = svc.load{{ .expIdent }}(ctx, svc.store, {{ range .references }}{{ . }}, {{ end }})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, tag := range svc.locale.Tags() {
|
||||
{{- range .keys}}
|
||||
{{- if not .customHandler }}
|
||||
k = types.{{ .struct }}
|
||||
out = append(out, &locale.ResourceTranslation{
|
||||
Resource: res.ResourceTranslation(),
|
||||
Lang: tag.String(),
|
||||
Key: k.Path,
|
||||
Msg: svc.locale.TResourceFor(tag, res.ResourceTranslation(), k.Path),
|
||||
})
|
||||
{{ end }}
|
||||
{{- end}}
|
||||
}
|
||||
|
||||
{{ if .extended }}
|
||||
tmp, err := svc.{{ .ident }}Extended(ctx, res)
|
||||
return append(out, tmp...), err
|
||||
{{- else }}
|
||||
return out, nil
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
{{- end }}
|
||||
|
||||
func updateTranslations(ctx context.Context, ac localeAccessControl, lsvc ResourceTranslationsManagerService, tt ...*locale.ResourceTranslation) error {
|
||||
if lsvc == nil || lsvc.Locale() == nil || lsvc.Locale().Default() == nil {
|
||||
// gracefully handle partial initializations
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
// assuming options will not change after start
|
||||
contentLang = lsvc.Locale().Default().Tag
|
||||
)
|
||||
|
||||
if options.Locale().ResourceTranslationsEnabled {
|
||||
contentLang = locale.GetContentLanguageFromContext(ctx)
|
||||
// Resource translations enabled
|
||||
if contentLang == language.Und {
|
||||
// If no content-language meta (HTTP header) info was
|
||||
// used, do not run update translations - we do not know
|
||||
// what is the language that we're sending in
|
||||
return nil
|
||||
}
|
||||
|
||||
if !lsvc.Locale().SupportedLang(contentLang) {
|
||||
// unsupported language
|
||||
return errors.InvalidData("unsupported language")
|
||||
}
|
||||
|
||||
if !ac.CanManageResourceTranslations(ctx) {
|
||||
return errors.Unauthorized("not allowed to manage resource translations")
|
||||
}
|
||||
}
|
||||
|
||||
locale.ResourceTranslationSet(tt).SetLanguage(contentLang)
|
||||
if err := lsvc.Upsert(ctx, tt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
120
codegen/assets/templates/gocode/locale/types.go.tpl
Normal file
120
codegen/assets/templates/gocode/locale/types.go.tpl
Normal file
@@ -0,0 +1,120 @@
|
||||
package {{ .package }}
|
||||
|
||||
{{ template "gocode/header-gentext.tpl" }}
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"github.com/cortezaproject/corteza-server/pkg/locale"
|
||||
)
|
||||
|
||||
type (
|
||||
LocaleKey struct {
|
||||
Name string
|
||||
Resource string
|
||||
Path string
|
||||
CustomHandler string
|
||||
}
|
||||
)
|
||||
|
||||
// Types and stuff
|
||||
const (
|
||||
{{- range .resources }}
|
||||
{{ .const }} = "{{ .type }}"
|
||||
{{- end }}
|
||||
)
|
||||
|
||||
var (
|
||||
// @todo can we remove LocaleKey struct for string constant?
|
||||
{{- range .resources }}
|
||||
{{- range .keys }}
|
||||
{{ .struct }} = LocaleKey{ Path: {{ printf "%q" .path }} }
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
)
|
||||
|
||||
{{- range .resources }}
|
||||
|
||||
// ResourceTranslation returns string representation of Locale resource for {{ .expIdent }} by calling {{ .expIdent }}ResourceTranslation fn
|
||||
//
|
||||
// Locale resource is in "{{ .type }}/..." format
|
||||
//
|
||||
// This function is auto-generated
|
||||
func (r {{ .expIdent }}) ResourceTranslation() string {
|
||||
return {{ .expIdent }}ResourceTranslation({{ if .references }}{{ range .references }}r.{{ . }},{{ end }}{{ end }})
|
||||
}
|
||||
|
||||
// {{ .expIdent }}ResourceTranslation returns string representation of Locale resource for {{ .expIdent }}
|
||||
//
|
||||
// Locale resource is in the {{ .type }}/{{- if .references }}...{{ end }} format
|
||||
//
|
||||
// This function is auto-generated
|
||||
func {{ .expIdent }}ResourceTranslation({{ if .references }}{{ range .references }}{{ . }} uint64,{{ end }}{{ end }}) string {
|
||||
{{- if .references }}
|
||||
cpts := []interface{{"{}"}}{
|
||||
{{ .expIdent }}ResourceTranslationType,
|
||||
{{- range .references }}
|
||||
strconv.FormatUint({{ . }}, 10),
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
return fmt.Sprintf({{ .expIdent }}ResourceTranslationTpl(), cpts...)
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
func {{ .expIdent }}ResourceTranslationTpl() string {
|
||||
{{- if .references }}
|
||||
return "%s
|
||||
{{- range .references }}/%s{{- end }}"
|
||||
|
||||
{{- else }}
|
||||
return "%s"
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
func (r *{{ .expIdent }}) DecodeTranslations(tt locale.ResourceTranslationIndex) {
|
||||
var aux *locale.ResourceTranslation
|
||||
|
||||
{{- range .keys }}
|
||||
{{ if .decodeFunc }}
|
||||
{{ if not .extended }}
|
||||
r.{{ .decodeFunc }}(tt)
|
||||
{{- end}}
|
||||
{{ else }}
|
||||
if aux = tt.FindByKey({{ .struct }}.Path); aux != nil {
|
||||
r.{{ .fieldPath }} = aux.Msg
|
||||
}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
|
||||
{{- if .extended }}
|
||||
r.decodeTranslations(tt)
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
func (r *{{ .expIdent }}) EncodeTranslations() (out locale.ResourceTranslationSet) {
|
||||
out = locale.ResourceTranslationSet{}
|
||||
{{- range .keys }}
|
||||
{{ if .encodeFunc }}
|
||||
{{ if not .extended }}
|
||||
out = append(out, r.{{ .encodeFunc }}()...)
|
||||
{{- end}}
|
||||
{{ else }}
|
||||
if r.{{ .fieldPath }} != "" {
|
||||
out = append(out, &locale.ResourceTranslation{
|
||||
Resource: r.ResourceTranslation(),
|
||||
Key: {{ .struct }}.Path,
|
||||
Msg: locale.SanitizeMessage(r.{{ .fieldPath }}),
|
||||
})
|
||||
}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
|
||||
{{- if .extended }}
|
||||
out = append(out, r.encodeTranslations()...)
|
||||
{{- end }}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
{{- end }}
|
||||
Reference in New Issue
Block a user