[add] page config
This commit is contained in:
parent
92a3405f75
commit
71183fa17c
9 changed files with 441 additions and 28 deletions
|
|
@ -542,8 +542,9 @@ func TestEditorRender(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.IsType(t, &core.ResponseEditor{}, res)
|
||||
assert.NotEmpty(t, res.(*core.ResponseEditor).HTML)
|
||||
assert.IsType(t, &core.ResponseEditorRender{}, res)
|
||||
assert.NotEmpty(t, res.(*core.ResponseEditorRender).HTML)
|
||||
assert.NotEmpty(t, res.(*core.ResponseEditorRender).Config)
|
||||
}
|
||||
|
||||
func TestEditorRenderWithQuery(t *testing.T) {
|
||||
|
|
@ -563,8 +564,8 @@ func TestEditorRenderWithQuery(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.IsType(t, &core.ResponseEditor{}, res)
|
||||
assert.NotEmpty(t, res.(*core.ResponseEditor).HTML)
|
||||
assert.IsType(t, &core.ResponseEditorRender{}, res)
|
||||
assert.NotEmpty(t, res.(*core.ResponseEditorRender).HTML)
|
||||
}
|
||||
|
||||
func TestEditorPageSource(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -7,15 +7,16 @@ import (
|
|||
)
|
||||
|
||||
// EditorRender render HTML for the editor
|
||||
func (page *Page) EditorRender(request *Request) (*ResponseEditor, error) {
|
||||
func (page *Page) EditorRender(request *Request) (*ResponseEditorRender, error) {
|
||||
|
||||
html := page.Codes.HTML.Code
|
||||
res := &ResponseEditor{
|
||||
res := &ResponseEditorRender{
|
||||
HTML: "",
|
||||
CSS: page.Codes.CSS.Code,
|
||||
Scripts: []string{},
|
||||
Styles: []string{},
|
||||
Warnings: []string{},
|
||||
Config: page.GetConfig(),
|
||||
Setting: map[string]interface{}{},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,11 +38,12 @@ type IPage interface {
|
|||
Load() error
|
||||
|
||||
Get() *Page
|
||||
GetConfig() *PageConfig
|
||||
Save(request *RequestSource) error
|
||||
SaveTemp(request *RequestSource) error
|
||||
Remove() error
|
||||
|
||||
EditorRender(request *Request) (*ResponseEditor, error)
|
||||
EditorRender(request *Request) (*ResponseEditorRender, error)
|
||||
EditorPageSource() SourceData
|
||||
EditorScriptSource() SourceData
|
||||
EditorStyleSource() SourceData
|
||||
|
|
|
|||
61
sui/core/json.go
Normal file
61
sui/core/json.go
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
// UnmarshalJSON Custom JSON unmarshal function for PageMock
|
||||
func (mock *PageMock) UnmarshalJSON(data []byte) error {
|
||||
|
||||
if mock == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
type Alias struct {
|
||||
Method string `json:"method"`
|
||||
Params map[string]string `json:"params,omitempty"`
|
||||
Query map[string]interface{} `json:"query,omitempty"`
|
||||
Headers map[string]interface{} `json:"headers,omitempty"`
|
||||
Body interface{} `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
aux := &Alias{}
|
||||
if err := jsoniter.Unmarshal(data, &aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
method := aux.Method
|
||||
if method == "" {
|
||||
method = "GET"
|
||||
}
|
||||
mock.Body = aux.Body
|
||||
mock.Method = method
|
||||
mock.Params = aux.Params
|
||||
mock.Query = convertRecordToMap(aux.Query)
|
||||
mock.Headers = convertRecordToMap(aux.Headers)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Helper function to convert TypeScript Record<string, string | string[]> to map[string][]string
|
||||
func convertRecordToMap(record map[string]interface{}) map[string][]string {
|
||||
if record == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make(map[string][]string)
|
||||
for key, value := range record {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
result[key] = []string{v}
|
||||
case []interface{}:
|
||||
strValues := make([]string, len(v))
|
||||
for i, item := range v {
|
||||
if str, ok := item.(string); ok {
|
||||
strValues[i] = str
|
||||
}
|
||||
}
|
||||
result[key] = strValues
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
228
sui/core/json_test.go
Normal file
228
sui/core/json_test.go
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
func TestRequestSourceUnmarshalJSON(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
jsonData string
|
||||
expected *RequestSource
|
||||
shouldFail bool
|
||||
}{
|
||||
{
|
||||
name: "Valid JSON with string query and headers",
|
||||
jsonData: `{
|
||||
"uid": "123",
|
||||
"mock": {
|
||||
"method": "GET",
|
||||
"query": {
|
||||
"q1": "value1",
|
||||
"q2": "value2"
|
||||
},
|
||||
"headers": {
|
||||
"header1": "value1",
|
||||
"header2": "value2"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expected: &RequestSource{
|
||||
UID: "123",
|
||||
Mock: &PageMock{
|
||||
Method: "GET",
|
||||
Query: map[string][]string{
|
||||
"q1": {"value1"},
|
||||
"q2": {"value2"},
|
||||
},
|
||||
Headers: map[string][]string{
|
||||
"header1": {"value1"},
|
||||
"header2": {"value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
name: "Valid JSON with array query and headers",
|
||||
jsonData: `{
|
||||
"uid": "456",
|
||||
"mock": {
|
||||
"method": "POST",
|
||||
"query": {
|
||||
"q1": ["value1", "value2"],
|
||||
"q2": ["value3"]
|
||||
},
|
||||
"headers": {
|
||||
"header1": ["value1", "value2"],
|
||||
"header2": "value3"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expected: &RequestSource{
|
||||
UID: "456",
|
||||
Mock: &PageMock{
|
||||
Method: "POST",
|
||||
Query: map[string][]string{
|
||||
"q1": {"value1", "value2"},
|
||||
"q2": {"value3"},
|
||||
},
|
||||
Headers: map[string][]string{
|
||||
"header1": {"value1", "value2"},
|
||||
"header2": {"value3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
name: "Valid JSON with invalid query",
|
||||
jsonData: `{
|
||||
"uid": "789",
|
||||
"mock": {
|
||||
"method": "PUT",
|
||||
"query":"1203"
|
||||
}
|
||||
}`,
|
||||
expected: nil,
|
||||
shouldFail: true,
|
||||
},
|
||||
// Add more test cases here to cover other scenarios.
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
var requestSource RequestSource
|
||||
err := jsoniter.Unmarshal([]byte(testCase.jsonData), &requestSource)
|
||||
|
||||
if testCase.shouldFail {
|
||||
if err == nil {
|
||||
t.Errorf("%s: Expected unmarshal to fail, but it succeeded", testCase.name)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Unmarshal failed: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(requestSource, *testCase.expected) {
|
||||
t.Errorf("Unmarshaled result does not match expected result")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPageConfigUnmarshalJSON(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
jsonData string
|
||||
expected *PageConfig
|
||||
shouldFail bool
|
||||
}{
|
||||
{
|
||||
name: "Valid JSON with PageSetting and PageMock",
|
||||
jsonData: `{
|
||||
"title": "Page Title",
|
||||
"mock": {
|
||||
"method": "GET",
|
||||
"query": {
|
||||
"q1": "value1",
|
||||
"q2": "value2"
|
||||
},
|
||||
"headers": {
|
||||
"header1": "value1",
|
||||
"header2": "value2"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expected: &PageConfig{
|
||||
PageSetting: PageSetting{
|
||||
Title: "Page Title",
|
||||
},
|
||||
Mock: &PageMock{
|
||||
Method: "GET",
|
||||
Query: map[string][]string{
|
||||
"q1": {"value1"},
|
||||
"q2": {"value2"},
|
||||
},
|
||||
Headers: map[string][]string{
|
||||
"header1": {"value1"},
|
||||
"header2": {"value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
name: "Valid JSON with PageSetting only",
|
||||
jsonData: `{
|
||||
"title": "Page Title"
|
||||
}`,
|
||||
expected: &PageConfig{
|
||||
PageSetting: PageSetting{
|
||||
Title: "Page Title",
|
||||
},
|
||||
Mock: nil,
|
||||
},
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
name: "Valid JSON with PageMock only",
|
||||
jsonData: `{
|
||||
"mock": {
|
||||
"method": "GET",
|
||||
"query": {
|
||||
"q1": "value1",
|
||||
"q2": "value2"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expected: &PageConfig{
|
||||
Mock: &PageMock{
|
||||
Method: "GET",
|
||||
Query: map[string][]string{
|
||||
"q1": {"value1"},
|
||||
"q2": {"value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
name: "Valid JSON with invalid query",
|
||||
jsonData: `{
|
||||
"title": "Page Title",
|
||||
"mock": {
|
||||
"method": "PUT",
|
||||
"query": "invalid query"
|
||||
}
|
||||
}`,
|
||||
expected: nil,
|
||||
shouldFail: true,
|
||||
},
|
||||
// Add more test cases here to cover other scenarios.
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
var pageConfig PageConfig
|
||||
err := jsoniter.Unmarshal([]byte(testCase.jsonData), &pageConfig)
|
||||
|
||||
if testCase.shouldFail {
|
||||
if err == nil {
|
||||
t.Errorf("%s: Expected unmarshal to fail, but it succeeded", testCase.name)
|
||||
}
|
||||
} else {
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unmarshal failed: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(pageConfig, *testCase.expected) {
|
||||
t.Errorf("Unmarshaled result does not match expected result")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +1,20 @@
|
|||
package core
|
||||
|
||||
import jsoniter "github.com/json-iterator/go"
|
||||
|
||||
// Get get the base info
|
||||
func (page *Page) Get() *Page {
|
||||
return page
|
||||
}
|
||||
|
||||
// GetHTML get the html
|
||||
func (page *Page) GetHTML() {}
|
||||
|
||||
// GetScript get the script
|
||||
func (page *Page) GetScript() {}
|
||||
|
||||
// GetStyle get the style
|
||||
func (page *Page) GetStyle() {}
|
||||
|
||||
// GetData get the data
|
||||
func (page *Page) GetData() {}
|
||||
|
||||
// SaveTemp save the temp
|
||||
func (page *Page) SaveTemp() {}
|
||||
|
||||
// Save the page
|
||||
func (page *Page) Save() {}
|
||||
// GetConfig get the config
|
||||
func (page *Page) GetConfig() *PageConfig {
|
||||
if page.Config == nil && page.Codes.CONF.Code != "" {
|
||||
var config PageConfig
|
||||
err := jsoniter.Unmarshal([]byte(page.Codes.CONF.Code), &config)
|
||||
if err == nil {
|
||||
page.Config = &config
|
||||
}
|
||||
}
|
||||
return page.Config
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ type DSL struct {
|
|||
type Page struct {
|
||||
Route string `json:"route"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Config *PageConfig `json:"-"`
|
||||
Path string `json:"-"`
|
||||
Codes SourceCodes `json:"-"`
|
||||
Document []byte `json:"-"`
|
||||
|
|
@ -79,8 +80,8 @@ type Request struct {
|
|||
Payload map[string]interface{} `json:"payload,omitempty"`
|
||||
Query map[string][]string `json:"query,omitempty"`
|
||||
Params map[string]string `json:"params,omitempty"`
|
||||
Headers []string `json:"headers,omitempty"`
|
||||
Body []byte `json:"body,omitempty"`
|
||||
Headers map[string][]string `json:"headers,omitempty"`
|
||||
Body interface{} `json:"body,omitempty"`
|
||||
Theme string `json:"theme,omitempty"`
|
||||
Locale string `json:"locale,omitempty"`
|
||||
}
|
||||
|
|
@ -94,23 +95,28 @@ type RequestSource struct {
|
|||
Script *SourceData `json:"script,omitempty"`
|
||||
Data *SourceData `json:"data,omitempty"`
|
||||
Board *BoardSourceData `json:"board,omitempty"`
|
||||
Mock *PageMock `json:"mock,omitempty"`
|
||||
Setting *PageSetting `json:"setting,omitempty"`
|
||||
NeedToSave struct {
|
||||
Page bool `json:"page,omitempty"`
|
||||
Style bool `json:"style,omitempty"`
|
||||
Script bool `json:"script,omitempty"`
|
||||
Data bool `json:"data,omitempty"`
|
||||
Board bool `json:"board,omitempty"`
|
||||
Mock bool `json:"mock,omitempty"`
|
||||
Setting bool `json:"setting,omitempty"`
|
||||
Validate bool `json:"validate,omitempty"`
|
||||
} `json:"needToSave,omitempty"`
|
||||
}
|
||||
|
||||
// ResponseEditor is the struct for the response
|
||||
type ResponseEditor struct {
|
||||
// ResponseEditorRender is the struct for the response
|
||||
type ResponseEditorRender struct {
|
||||
HTML string `json:"html,omitempty"`
|
||||
CSS string `json:"css,omitempty"`
|
||||
Scripts []string `json:"scripts,omitempty"`
|
||||
Styles []string `json:"styles,omitempty"`
|
||||
Setting map[string]interface{} `json:"setting,omitempty"`
|
||||
Config *PageConfig `json:"config,omitempty"`
|
||||
Warnings []string `json:"warnings,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -126,6 +132,37 @@ type BoardSourceData struct {
|
|||
Style string `json:"style,omitempty"`
|
||||
}
|
||||
|
||||
// PageMock is the struct for the request
|
||||
type PageMock struct {
|
||||
Method string `json:"method,omitempty"`
|
||||
Params map[string]string `json:"params,omitempty"`
|
||||
Query map[string][]string `json:"query,omitempty"`
|
||||
Headers map[string][]string `json:"headers,omitempty"`
|
||||
Body interface{} `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// PageConfig is the struct for the page config
|
||||
type PageConfig struct {
|
||||
PageSetting `json:",omitempty"`
|
||||
Mock *PageMock `json:"mock,omitempty"`
|
||||
}
|
||||
|
||||
// PageSetting is the struct for the page setting
|
||||
type PageSetting struct {
|
||||
Title string `json:"title,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
SEO *PageSEO `json:"seo,omitempty"`
|
||||
}
|
||||
|
||||
// PageSEO is the struct for the page seo
|
||||
type PageSEO struct {
|
||||
Title string `json:"title,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Keywords string `json:"keywords,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// SourceCodes is the struct for the page codes
|
||||
type SourceCodes struct {
|
||||
HTML Source `json:"-"`
|
||||
|
|
@ -134,6 +171,7 @@ type SourceCodes struct {
|
|||
TS Source `json:"-"`
|
||||
LESS Source `json:"-"`
|
||||
DATA Source `json:"-"`
|
||||
CONF Source `json:"-"`
|
||||
}
|
||||
|
||||
// Source is the struct for the source
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/kun/log"
|
||||
"github.com/yaoapp/yao/sui/core"
|
||||
)
|
||||
|
|
@ -221,6 +222,7 @@ func (tmpl *Template) CreatePage(route string) (core.IPage, error) {
|
|||
JS: core.Source{File: fmt.Sprintf("%s.js", name)},
|
||||
TS: core.Source{File: fmt.Sprintf("%s.ts", name)},
|
||||
LESS: core.Source{File: fmt.Sprintf("%s.less", name)},
|
||||
CONF: core.Source{File: fmt.Sprintf("%s.config", name)},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
|
|
@ -272,6 +274,7 @@ func (tmpl *Template) getPage(route, file string) (core.IPage, error) {
|
|||
DATA: core.Source{File: fmt.Sprintf("%s.json", name)},
|
||||
TS: core.Source{File: fmt.Sprintf("%s.ts", name)},
|
||||
LESS: core.Source{File: fmt.Sprintf("%s.less", name)},
|
||||
CONF: core.Source{File: fmt.Sprintf("%s.config", name)},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
|
|
@ -345,6 +348,16 @@ func (page *Page) Load() error {
|
|||
page.Codes.DATA.Code = string(dataCode)
|
||||
}
|
||||
|
||||
// Read the config code
|
||||
confFile := filepath.Join(page.Path, page.Codes.CONF.File)
|
||||
if exist, _ := page.tmpl.local.fs.Exists(confFile); exist {
|
||||
confCode, err := page.tmpl.local.fs.ReadFile(confFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
page.Codes.CONF.Code = string(confCode)
|
||||
}
|
||||
|
||||
// Set the page document
|
||||
page.Document = page.tmpl.Document
|
||||
return nil
|
||||
|
|
@ -422,6 +435,13 @@ func (page *Page) save(path string, request *core.RequestSource) error {
|
|||
}
|
||||
}
|
||||
|
||||
if request.NeedToSave.Setting || request.NeedToSave.Mock {
|
||||
err := page.saveSetting(path, request.Setting, request.Mock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -486,6 +506,34 @@ func (page *Page) saveData(path string, src *core.SourceData) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (page *Page) saveSetting(path string, setting *core.PageSetting, mock *core.PageMock) error {
|
||||
|
||||
config := map[string]interface{}{}
|
||||
if setting != nil {
|
||||
err := jsoniter.Unmarshal([]byte(page.Codes.CONF.Code), &config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if mock != nil {
|
||||
config["mock"] = mock
|
||||
}
|
||||
|
||||
configBytes, err := jsoniter.MarshalIndent(config, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(config) > 0 {
|
||||
dataFile := filepath.Join(path, page.Codes.CONF.File)
|
||||
_, err = page.tmpl.local.fs.WriteFile(dataFile, configBytes, 0644)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssetScript get the script
|
||||
func (page *Page) AssetScript() (*core.Asset, error) {
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ func TestTemplatePages(t *testing.T) {
|
|||
assert.Equal(t, name+".less", page.Codes.LESS.File)
|
||||
assert.Equal(t, name+".ts", page.Codes.TS.File)
|
||||
assert.Equal(t, name+".json", page.Codes.DATA.File)
|
||||
assert.Equal(t, name+".config", page.Codes.CONF.File)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -444,6 +445,44 @@ func TestPageSaveTempData(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestPageSaveTempSetting(t *testing.T) {
|
||||
tests := prepare(t)
|
||||
defer clean()
|
||||
|
||||
tmpl, err := tests.Demo.GetTemplate("tech-blue")
|
||||
if err != nil {
|
||||
t.Fatalf("GetTemplate error: %v", err)
|
||||
}
|
||||
|
||||
const payload = `{
|
||||
"page": null,
|
||||
"style": null,
|
||||
"script": null,
|
||||
"setting": { "title": "Home Page | {{ $global.title }}" },
|
||||
"mock": { "params": { "id": "1" } },
|
||||
"needToSave": {
|
||||
"page": false,
|
||||
"style": false,
|
||||
"script": false,
|
||||
"mock": true,
|
||||
"setting": true,
|
||||
"board": false,
|
||||
"validate": true
|
||||
}
|
||||
}`
|
||||
|
||||
req := &core.RequestSource{UID: "19e09e7e-9e19-44c1-bbab-2a55c51c9df3"}
|
||||
jsoniter.Unmarshal([]byte(payload), &req)
|
||||
|
||||
page, err := tmpl.Page("/index")
|
||||
if err != nil {
|
||||
t.Fatalf("Page error: %v", err)
|
||||
}
|
||||
|
||||
err = page.SaveTemp(req)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestPageSave(t *testing.T) {
|
||||
tests := prepare(t)
|
||||
defer clean()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue