Skip to content
Snippets Groups Projects
Commit cfe4ccb9 authored by Semyon Krestyaninov's avatar Semyon Krestyaninov :dog2:
Browse files

wip

parent 076fdd0b
No related branches found
No related tags found
No related merge requests found
...@@ -2,9 +2,11 @@ package references ...@@ -2,9 +2,11 @@ package references
import ( import (
"context" "context"
"fmt"
"testing" "testing"
"git.perx.ru/perxis/perxis-go/pkg/expr" "git.perx.ru/perxis/perxis-go/pkg/expr"
"github.com/mitchellh/mapstructure"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
...@@ -39,3 +41,18 @@ func TestReference_InExpr(t *testing.T) { ...@@ -39,3 +41,18 @@ func TestReference_InExpr(t *testing.T) {
}) })
} }
} }
func TestReference_encode(t *testing.T) {
var result map[string]any
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{TagName: "json", Result: &result})
require.NoError(t, err)
err = dec.Decode(&Reference{
ID: "ref_id",
CollectionID: "coll_id",
Disabled: false,
})
require.NoError(t, err)
fmt.Println(result)
}
...@@ -3,7 +3,9 @@ package template ...@@ -3,7 +3,9 @@ package template
import ( import (
"bytes" "bytes"
"context" "context"
"text/template" templhtml "html/template"
"io"
templtext "text/template"
"git.perx.ru/perxis/perxis-go/pkg/collections" "git.perx.ru/perxis/perxis-go/pkg/collections"
"git.perx.ru/perxis/perxis-go/pkg/content" "git.perx.ru/perxis/perxis-go/pkg/content"
...@@ -11,13 +13,20 @@ import ( ...@@ -11,13 +13,20 @@ import (
"git.perx.ru/perxis/perxis-go/pkg/spaces" "git.perx.ru/perxis/perxis-go/pkg/spaces"
) )
type Builder struct { type Executor[T any] interface {
Parse(text string) (T, error)
Execute(w io.Writer, data any) error
}
type Builder[T Executor[T]] struct {
template func(string) T
ctx context.Context ctx context.Context
cnt *content.Content cnt *content.Content
SpaceID string SpaceID string
EnvID string EnvID string
CollID string CollID string
data map[string]interface{} data map[string]any
// Для кеширования запросов // Для кеширования запросов
space *spaces.Space space *spaces.Space
...@@ -25,30 +34,48 @@ type Builder struct { ...@@ -25,30 +34,48 @@ type Builder struct {
collection *collections.Collection collection *collections.Collection
} }
func NewBuilder(cnt *content.Content, space, env, col string) *Builder { func NewBuilder(cnt *content.Content, space, env, col string) Builder[*templtext.Template] {
return &Builder{ b := Builder[*templtext.Template]{
ctx: context.Background(), ctx: context.Background(),
cnt: cnt, cnt: cnt,
SpaceID: space, SpaceID: space,
EnvID: env, EnvID: env,
CollID: col, CollID: col,
} }
b.template = func(name string) *templtext.Template {
return templtext.New(name).Funcs(b.getFuncs())
}
return b
} }
func (b *Builder) getFuncs() template.FuncMap { func NewHTMLBuilder(cnt *content.Content, space, env, col string) Builder[*templhtml.Template] {
return template.FuncMap{ b := Builder[*templhtml.Template]{
ctx: context.Background(),
cnt: cnt,
SpaceID: space,
EnvID: env,
CollID: col,
}
b.template = func(name string) *templhtml.Template {
return templhtml.New(name).Funcs(b.getFuncs())
}
return b
}
func (b *Builder[T]) getFuncs() map[string]any {
return map[string]any{
"lookup": getLookup(b), "lookup": getLookup(b),
"system": getSystem(b), "system": getSystem(b),
} }
} }
func (b *Builder) WithData(data map[string]interface{}) *Builder { func (b *Builder[T]) WithData(data map[string]interface{}) *Builder[T] {
bld := *b bld := *b
bld.data = data bld.data = data
return &bld return &bld
} }
func (b *Builder) WithKV(kv ...any) *Builder { func (b *Builder[T]) WithKV(kv ...any) *Builder[T] {
bld := *b bld := *b
if bld.data == nil { if bld.data == nil {
bld.data = make(map[string]interface{}, 10) bld.data = make(map[string]interface{}, 10)
...@@ -63,33 +90,29 @@ func (b *Builder) WithKV(kv ...any) *Builder { ...@@ -63,33 +90,29 @@ func (b *Builder) WithKV(kv ...any) *Builder {
return &bld return &bld
} }
func (b *Builder) GetData() map[string]interface{} { func (b *Builder[T]) GetData() map[string]interface{} {
return b.data return b.data
} }
func (b *Builder) WithSpace(space, env string) *Builder { func (b *Builder[T]) WithSpace(space, env string) *Builder[T] {
bld := *b bld := *b
bld.SpaceID = space bld.SpaceID = space
bld.EnvID = env bld.EnvID = env
return &bld return &bld
} }
func (b *Builder) WithContext(ctx context.Context) *Builder { func (b *Builder[T]) WithContext(ctx context.Context) *Builder[T] {
bld := *b bld := *b
bld.ctx = ctx bld.ctx = ctx
return &bld return &bld
} }
func (b *Builder) Context() context.Context { func (b *Builder[T]) Context() context.Context {
return b.ctx return b.ctx
} }
func (b *Builder) Template() *template.Template { func (b *Builder[T]) Execute(str string, data ...any) (string, error) {
return template.New("main").Funcs(b.getFuncs()) t := b.template("main")
}
func (b *Builder) Execute(str string, data ...any) (string, error) {
t := b.Template()
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
t, err := t.Parse(str) t, err := t.Parse(str)
if err != nil { if err != nil {
...@@ -101,8 +124,8 @@ func (b *Builder) Execute(str string, data ...any) (string, error) { ...@@ -101,8 +124,8 @@ func (b *Builder) Execute(str string, data ...any) (string, error) {
return buf.String(), nil return buf.String(), nil
} }
func (b *Builder) ExecuteList(str []string, data ...any) ([]string, error) { func (b *Builder[T]) ExecuteList(str []string, data ...any) ([]string, error) {
t := b.Template() t := b.template("main")
result := make([]string, len(str)) result := make([]string, len(str))
buffer := new(bytes.Buffer) buffer := new(bytes.Buffer)
for i, tmpl := range str { for i, tmpl := range str {
...@@ -122,7 +145,7 @@ func (b *Builder) ExecuteList(str []string, data ...any) ([]string, error) { ...@@ -122,7 +145,7 @@ func (b *Builder) ExecuteList(str []string, data ...any) ([]string, error) {
return result, nil return result, nil
} }
func (b *Builder) ExecuteMap(str map[string]interface{}, data ...any) (map[string]interface{}, error) { func (b *Builder[T]) ExecuteMap(str map[string]interface{}, data ...any) (map[string]interface{}, error) {
result := make(map[string]interface{}, len(str)) result := make(map[string]interface{}, len(str))
for k, v := range str { for k, v := range str {
switch t := v.(type) { switch t := v.(type) {
...@@ -150,7 +173,7 @@ func (b *Builder) ExecuteMap(str map[string]interface{}, data ...any) (map[strin ...@@ -150,7 +173,7 @@ func (b *Builder) ExecuteMap(str map[string]interface{}, data ...any) (map[strin
return result, nil return result, nil
} }
func (b *Builder) getData(data ...any) any { func (b *Builder[T]) getData(data ...any) any {
if len(data) == 0 { if len(data) == 0 {
return b.data return b.data
} }
......
...@@ -26,6 +26,7 @@ func TestBuilder_Execute(t *testing.T) { ...@@ -26,6 +26,7 @@ func TestBuilder_Execute(t *testing.T) {
str string str string
data any data any
want any want any
htmlBuilder bool
wantErr bool wantErr bool
getCnt func() (cnt *content.Content, assertExpectations func(t *testing.T)) getCnt func() (cnt *content.Content, assertExpectations func(t *testing.T))
...@@ -112,6 +113,7 @@ func TestBuilder_Execute(t *testing.T) { ...@@ -112,6 +113,7 @@ func TestBuilder_Execute(t *testing.T) {
return &content.Content{Collections: collsSvc}, func(t *testing.T) { collsSvc.AssertExpectations(t) } return &content.Content{Collections: collsSvc}, func(t *testing.T) { collsSvc.AssertExpectations(t) }
}, str: "{{ system.Collection.Name }}", want: "cars", wantErr: false}, }, str: "{{ system.Collection.Name }}", want: "cars", wantErr: false},
{name: "system without account", SpaceID: "space", str: "hello {{ system.Organization.Name }}", want: "", wantErr: true}, {name: "system without account", SpaceID: "space", str: "hello {{ system.Organization.Name }}", want: "", wantErr: true},
{name: "with html builder", str: "{{ . }}", data: "<script>alert(localStorage.secret)</script>", want: "&lt;script&gt;alert(localStorage.secret)&lt;/script&gt;", htmlBuilder: true, wantErr: false},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
...@@ -122,15 +124,18 @@ func TestBuilder_Execute(t *testing.T) { ...@@ -122,15 +124,18 @@ func TestBuilder_Execute(t *testing.T) {
defer checkFn(t) defer checkFn(t)
} }
b := &Builder{ var (
ctx: context.Background(), got string
cnt: cnt, err error
SpaceID: tt.SpaceID, )
EnvID: tt.EnvID, if tt.htmlBuilder {
CollID: tt.CollID, b := NewHTMLBuilder(cnt, tt.SpaceID, tt.EnvID, tt.CollID)
got, err = b.Execute(tt.str, tt.data)
} else {
b := NewBuilder(cnt, tt.SpaceID, tt.EnvID, tt.CollID)
got, err = b.Execute(tt.str, tt.data)
} }
got, err := b.Execute(tt.str, tt.data)
if tt.wantErr == true { if tt.wantErr == true {
assert.Error(t, err) assert.Error(t, err)
} else { } else {
...@@ -191,12 +196,7 @@ func TestBuilder_ExecuteList(t *testing.T) { ...@@ -191,12 +196,7 @@ func TestBuilder_ExecuteList(t *testing.T) {
if tt.itemsCall != nil { if tt.itemsCall != nil {
tt.itemsCall(itemsSvc) tt.itemsCall(itemsSvc)
} }
b := &Builder{ b := NewBuilder(&content.Content{Items: itemsSvc}, tt.SpaceID, tt.EnvID, "")
ctx: context.Background(),
cnt: &content.Content{Items: itemsSvc},
SpaceID: tt.SpaceID,
EnvID: tt.EnvID,
}
got, err := b.ExecuteList(tt.str, tt.data) got, err := b.ExecuteList(tt.str, tt.data)
if tt.wantErr == true { if tt.wantErr == true {
...@@ -260,12 +260,7 @@ func TestBuilder_ExecuteMap(t *testing.T) { ...@@ -260,12 +260,7 @@ func TestBuilder_ExecuteMap(t *testing.T) {
if tt.itemsCall != nil { if tt.itemsCall != nil {
tt.itemsCall(itemsSvc) tt.itemsCall(itemsSvc)
} }
b := &Builder{ b := NewBuilder(&content.Content{Items: itemsSvc}, tt.SpaceID, tt.EnvID, "")
ctx: context.Background(),
cnt: &content.Content{Items: itemsSvc},
SpaceID: tt.SpaceID,
EnvID: tt.EnvID,
}
got, err := b.ExecuteMap(tt.str, tt.data) got, err := b.ExecuteMap(tt.str, tt.data)
if tt.wantErr == true { if tt.wantErr == true {
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
// getLookup возвращает функцию для шаблонизатора для получения значений из записи коллекции // getLookup возвращает функцию для шаблонизатора для получения значений из записи коллекции
// name указывается в виде "<collection id>.<item id>.<field>" // name указывается в виде "<collection id>.<item id>.<field>"
// Использование в шаблонах: {{ lookup "secrets.key.value" }} // Использование в шаблонах: {{ lookup "secrets.key.value" }}
func getLookup(b *Builder) any { func getLookup[T Executor[T]](b *Builder[T]) any {
return func(name string) (any, error) { return func(name string) (any, error) {
parsedName := strings.Split(name, ".") parsedName := strings.Split(name, ".")
if len(parsedName) < 3 { if len(parsedName) < 3 {
...@@ -36,8 +36,8 @@ func getLookup(b *Builder) any { ...@@ -36,8 +36,8 @@ func getLookup(b *Builder) any {
// getSys возвращает функцию получения System // getSys возвращает функцию получения System
// Использование в шаблонах: {{ system.SpaceID }} // Использование в шаблонах: {{ system.SpaceID }}
func getSystem(b *Builder) any { func getSystem[T Executor[T]](b *Builder[T]) any {
return func() *System { return func() *System[T] {
return &System{builder: b} return &System[T]{builder: b}
} }
} }
...@@ -6,23 +6,23 @@ import ( ...@@ -6,23 +6,23 @@ import (
"git.perx.ru/perxis/perxis-go/pkg/spaces" "git.perx.ru/perxis/perxis-go/pkg/spaces"
) )
type System struct { type System[T Executor[T]] struct {
builder *Builder builder *Builder[T]
} }
func (s *System) SpaceID() string { func (s *System[T]) SpaceID() string {
return s.builder.SpaceID return s.builder.SpaceID
} }
func (s *System) EnvID() string { func (s *System[T]) EnvID() string {
return s.builder.EnvID return s.builder.EnvID
} }
func (s *System) CollectionID() string { func (s *System[T]) CollectionID() string {
return s.builder.CollID return s.builder.CollID
} }
func (s *System) Space() (*spaces.Space, error) { func (s *System[T]) Space() (*spaces.Space, error) {
if s.builder.space != nil { if s.builder.space != nil {
return s.builder.space, nil return s.builder.space, nil
} }
...@@ -32,7 +32,7 @@ func (s *System) Space() (*spaces.Space, error) { ...@@ -32,7 +32,7 @@ func (s *System) Space() (*spaces.Space, error) {
return s.builder.space, err return s.builder.space, err
} }
func (s *System) Environment() (*environments.Environment, error) { func (s *System[T]) Environment() (*environments.Environment, error) {
if s.builder.environment != nil { if s.builder.environment != nil {
return s.builder.environment, nil return s.builder.environment, nil
} }
...@@ -42,7 +42,7 @@ func (s *System) Environment() (*environments.Environment, error) { ...@@ -42,7 +42,7 @@ func (s *System) Environment() (*environments.Environment, error) {
return s.builder.environment, err return s.builder.environment, err
} }
func (s *System) Collection() (*collections.Collection, error) { func (s *System[T]) Collection() (*collections.Collection, error) {
if s.builder.collection != nil { if s.builder.collection != nil {
return s.builder.collection, nil return s.builder.collection, nil
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment