Merge pull request #258 from trheyi/main
[add] table widget upload api & process
This commit is contained in:
commit
238951d9db
11 changed files with 149 additions and 7 deletions
|
|
@ -11,8 +11,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// CloudProps parse CloudProps
|
// CloudProps parse CloudProps
|
||||||
func (p PropsDSL) CloudProps(xpath string) (map[string]CloudPropsDSL, error) {
|
func (p PropsDSL) CloudProps(xpath, component string) (map[string]CloudPropsDSL, error) {
|
||||||
return p.parseCloudProps(xpath, p)
|
return p.parseCloudProps(xpath, component, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path api path
|
// Path api path
|
||||||
|
|
@ -20,6 +20,43 @@ func (cProp CloudPropsDSL) Path() string {
|
||||||
return fmt.Sprintf("/component/%s/%s", url.QueryEscape(cProp.Xpath), url.QueryEscape(cProp.Name))
|
return fmt.Sprintf("/component/%s/%s", url.QueryEscape(cProp.Xpath), url.QueryEscape(cProp.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UploadPath api UploadPath
|
||||||
|
func (cProp CloudPropsDSL) UploadPath() string {
|
||||||
|
return fmt.Sprintf("/upload/%s/%s", url.QueryEscape(cProp.Xpath), url.QueryEscape(cProp.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecUpload execute upload
|
||||||
|
func (cProp CloudPropsDSL) ExecUpload(process *gou.Process, upload gou.UploadFile) (interface{}, error) {
|
||||||
|
|
||||||
|
if upload.TempFile == "" {
|
||||||
|
log.Error("[component] %s.$%s upload file is required", cProp.Xpath, cProp.Name)
|
||||||
|
return nil, fmt.Errorf("[component] %s.$%s upload file is required", cProp.Xpath, cProp.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process
|
||||||
|
name := cProp.Process
|
||||||
|
if name == "" {
|
||||||
|
log.Error("[component] %s.$%s process is required", cProp.Xpath, cProp.Name)
|
||||||
|
return nil, fmt.Errorf("[component] %s.$%s process is required", cProp.Xpath, cProp.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create process
|
||||||
|
p, err := gou.ProcessOf(name, upload)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
|
||||||
|
return nil, fmt.Errorf("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Excute process
|
||||||
|
res, err := p.WithGlobal(process.Global).WithSID(process.Sid).Exec()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
|
||||||
|
return nil, fmt.Errorf("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ExecQuery execute query
|
// ExecQuery execute query
|
||||||
func (cProp CloudPropsDSL) ExecQuery(process *gou.Process, query map[string]interface{}) (interface{}, error) {
|
func (cProp CloudPropsDSL) ExecQuery(process *gou.Process, query map[string]interface{}) (interface{}, error) {
|
||||||
|
|
||||||
|
|
@ -95,7 +132,7 @@ func (cProp CloudPropsDSL) replaceMap(data map[string]interface{}, root string,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p PropsDSL) parseCloudProps(xpath string, props map[string]interface{}) (map[string]CloudPropsDSL, error) {
|
func (p PropsDSL) parseCloudProps(xpath string, component string, props map[string]interface{}) (map[string]CloudPropsDSL, error) {
|
||||||
|
|
||||||
res := map[string]CloudPropsDSL{}
|
res := map[string]CloudPropsDSL{}
|
||||||
|
|
||||||
|
|
@ -103,7 +140,7 @@ func (p PropsDSL) parseCloudProps(xpath string, props map[string]interface{}) (m
|
||||||
|
|
||||||
fullname := fmt.Sprintf("%s.%s", xpath, name)
|
fullname := fmt.Sprintf("%s.%s", xpath, name)
|
||||||
if sub, ok := prop.(map[string]interface{}); ok {
|
if sub, ok := prop.(map[string]interface{}); ok {
|
||||||
cProps, err := p.parseCloudProps(fullname, sub)
|
cProps, err := p.parseCloudProps(fullname, component, sub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -118,6 +155,7 @@ func (p PropsDSL) parseCloudProps(xpath string, props map[string]interface{}) (m
|
||||||
|
|
||||||
cProp := &CloudPropsDSL{
|
cProp := &CloudPropsDSL{
|
||||||
Name: strings.TrimPrefix(name, "$"),
|
Name: strings.TrimPrefix(name, "$"),
|
||||||
|
Type: component,
|
||||||
Xpath: xpath,
|
Xpath: xpath,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ type ComputeHanlder func(args ...interface{}) (interface{}, error)
|
||||||
// CloudPropsDSL the cloud props
|
// CloudPropsDSL the cloud props
|
||||||
type CloudPropsDSL struct {
|
type CloudPropsDSL struct {
|
||||||
Xpath string `json:"xpath,omitempty"`
|
Xpath string `json:"xpath,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Process string `json:"process,omitempty"`
|
Process string `json:"process,omitempty"`
|
||||||
Query map[string]interface{} `json:"query,omitempty"`
|
Query map[string]interface{} `json:"query,omitempty"`
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ func (columns Columns) CPropsMerge(cloudProps map[string]component.CloudPropsDSL
|
||||||
|
|
||||||
if column.Edit != nil && column.Edit.Props != nil {
|
if column.Edit != nil && column.Edit.Props != nil {
|
||||||
xpath := getXpath(name, "edit", column)
|
xpath := getXpath(name, "edit", column)
|
||||||
cProps, err := column.Edit.Props.CloudProps(xpath)
|
cProps, err := column.Edit.Props.CloudProps(xpath, column.Edit.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +105,7 @@ func (columns Columns) CPropsMerge(cloudProps map[string]component.CloudPropsDSL
|
||||||
|
|
||||||
if column.View != nil && column.View.Props != nil {
|
if column.View != nil && column.View.Props != nil {
|
||||||
xpath := getXpath(name, "view", column)
|
xpath := getXpath(name, "view", column)
|
||||||
cProps, err := column.View.Props.CloudProps(xpath)
|
cProps, err := column.View.Props.CloudProps(xpath, column.View.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ func (filters Filters) CPropsMerge(cloudProps map[string]component.CloudPropsDSL
|
||||||
for name, filter := range filters {
|
for name, filter := range filters {
|
||||||
if filter.Edit != nil && filter.Edit.Props != nil {
|
if filter.Edit != nil && filter.Edit.Props != nil {
|
||||||
xpath := getXpath(name, filter)
|
xpath := getXpath(name, filter)
|
||||||
cProps, err := filter.Edit.Props.CloudProps(xpath)
|
cProps, err := filter.Edit.Props.CloudProps(xpath, filter.Edit.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,11 @@ var processActionDefaults = map[string]*action.Process{
|
||||||
Guard: "bearer-jwt",
|
Guard: "bearer-jwt",
|
||||||
Default: []interface{}{nil, nil, nil},
|
Default: []interface{}{nil, nil, nil},
|
||||||
},
|
},
|
||||||
|
"Upload": {
|
||||||
|
Name: "yao.table.Upload",
|
||||||
|
Guard: "bearer-jwt",
|
||||||
|
Default: []interface{}{nil, nil, nil},
|
||||||
|
},
|
||||||
"Search": {
|
"Search": {
|
||||||
Name: "yao.table.Search",
|
Name: "yao.table.Search",
|
||||||
Guard: "bearer-jwt",
|
Guard: "bearer-jwt",
|
||||||
|
|
@ -94,6 +99,10 @@ func (act *ActionDSL) SetDefaultProcess() {
|
||||||
Merge(processActionDefaults["Component"]).
|
Merge(processActionDefaults["Component"]).
|
||||||
SetHandler(processHandler)
|
SetHandler(processHandler)
|
||||||
|
|
||||||
|
act.Upload = action.ProcessOf(act.Upload).
|
||||||
|
Merge(processActionDefaults["Upload"]).
|
||||||
|
SetHandler(processHandler)
|
||||||
|
|
||||||
act.Search = action.ProcessOf(act.Search).
|
act.Search = action.ProcessOf(act.Search).
|
||||||
WithBefore(act.BeforeSearch).WithAfter(act.AfterSearch).
|
WithBefore(act.BeforeSearch).WithAfter(act.AfterSearch).
|
||||||
Merge(processActionDefaults["Search"]).
|
Merge(processActionDefaults["Search"]).
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ func (table *DSL) getAction(path string) (*action.Process, error) {
|
||||||
return table.Action.Setting, nil
|
return table.Action.Setting, nil
|
||||||
case "/api/__yao/table/:id/component/:xpath/:method":
|
case "/api/__yao/table/:id/component/:xpath/:method":
|
||||||
return table.Action.Component, nil
|
return table.Action.Component, nil
|
||||||
|
case "/api/__yao/table/:id/upload/:xpath/:method":
|
||||||
|
return table.Action.Upload, nil
|
||||||
case "/api/__yao/table/:id/search":
|
case "/api/__yao/table/:id/search":
|
||||||
return table.Action.Search, nil
|
return table.Action.Search, nil
|
||||||
case "/api/__yao/table/:id/get":
|
case "/api/__yao/table/:id/get":
|
||||||
|
|
@ -152,6 +154,18 @@ func exportAPI() error {
|
||||||
}
|
}
|
||||||
http.Paths = append(http.Paths, path)
|
http.Paths = append(http.Paths, path)
|
||||||
|
|
||||||
|
// POST /api/__yao/table/:id/upload/:xpath/:method -> Default process: yao.table.Component $param.id $param.xpath $param.method $file.file
|
||||||
|
path = gou.Path{
|
||||||
|
Label: "Upload",
|
||||||
|
Description: "Component",
|
||||||
|
Path: "/:id/upload/:xpath/:method",
|
||||||
|
Method: "POST",
|
||||||
|
Process: "yao.table.Upload",
|
||||||
|
In: []string{"$param.id", "$param.xpath", "$param.method", "$file.file"},
|
||||||
|
Out: gou.Out{Status: 200, Type: "application/json"},
|
||||||
|
}
|
||||||
|
http.Paths = append(http.Paths, path)
|
||||||
|
|
||||||
// POST /api/__yao/table/:id/save -> Default process: yao.table.Save $param.id :payload
|
// POST /api/__yao/table/:id/save -> Default process: yao.table.Save $param.id :payload
|
||||||
path = gou.Path{
|
path = gou.Path{
|
||||||
Label: "Save",
|
Label: "Save",
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ func exportProcess() {
|
||||||
gou.RegisterProcessHandler("yao.table.setting", processSetting)
|
gou.RegisterProcessHandler("yao.table.setting", processSetting)
|
||||||
gou.RegisterProcessHandler("yao.table.xgen", processXgen)
|
gou.RegisterProcessHandler("yao.table.xgen", processXgen)
|
||||||
gou.RegisterProcessHandler("yao.table.component", processComponent)
|
gou.RegisterProcessHandler("yao.table.component", processComponent)
|
||||||
|
gou.RegisterProcessHandler("yao.table.upload", processUpload)
|
||||||
gou.RegisterProcessHandler("yao.table.search", processSearch)
|
gou.RegisterProcessHandler("yao.table.search", processSearch)
|
||||||
gou.RegisterProcessHandler("yao.table.get", processGet)
|
gou.RegisterProcessHandler("yao.table.get", processGet)
|
||||||
gou.RegisterProcessHandler("yao.table.find", processFind)
|
gou.RegisterProcessHandler("yao.table.find", processFind)
|
||||||
|
|
@ -39,6 +40,35 @@ func processXgen(process *gou.Process) interface{} {
|
||||||
return setting
|
return setting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func processUpload(process *gou.Process) interface{} {
|
||||||
|
|
||||||
|
process.ValidateArgNums(4)
|
||||||
|
tab := MustGet(process)
|
||||||
|
xpath := process.ArgsString(1)
|
||||||
|
method := process.ArgsString(2)
|
||||||
|
key := fmt.Sprintf("%s.$%s", xpath, method)
|
||||||
|
|
||||||
|
// get cloud props
|
||||||
|
cProp, has := tab.CProps[key]
|
||||||
|
if !has {
|
||||||
|
exception.New("%s does not exist", 400, key).Throw()
|
||||||
|
}
|
||||||
|
|
||||||
|
// $file.file
|
||||||
|
tmpfile, ok := process.Args[3].(gou.UploadFile)
|
||||||
|
if !ok {
|
||||||
|
exception.New("parameters error: %v", 400, process.Args[3]).Throw()
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute upload
|
||||||
|
res, err := cProp.ExecUpload(process, tmpfile)
|
||||||
|
if err != nil {
|
||||||
|
exception.New(err.Error(), 500).Throw()
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func processComponent(process *gou.Process) interface{} {
|
func processComponent(process *gou.Process) interface{} {
|
||||||
|
|
||||||
process.ValidateArgNums(3)
|
process.ValidateArgNums(3)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package table
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
@ -331,6 +332,27 @@ func TestProcessComponent(t *testing.T) {
|
||||||
assert.Equal(t, "checked", pets[1]["value"])
|
assert.Equal(t, "checked", pets[1]["value"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProcessUpload(t *testing.T) {
|
||||||
|
load(t)
|
||||||
|
clear(t)
|
||||||
|
testData(t)
|
||||||
|
args := []interface{}{
|
||||||
|
"pet",
|
||||||
|
"fields.table.相关图片.edit.props",
|
||||||
|
"api",
|
||||||
|
gou.UploadFile{TempFile: tempFile(t)},
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := gou.NewProcess("yao.table.Upload", args...).Exec()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, ok := res.(string)
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.NotEmpty(t, file)
|
||||||
|
}
|
||||||
|
|
||||||
func TestProcessComponentError(t *testing.T) {
|
func TestProcessComponentError(t *testing.T) {
|
||||||
load(t)
|
load(t)
|
||||||
clear(t)
|
clear(t)
|
||||||
|
|
@ -405,6 +427,21 @@ func testData(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tempFile(t *testing.T) string {
|
||||||
|
file, err := os.CreateTemp("", "unit-test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
_, err = file.Write([]byte("HELLO"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return file.Name()
|
||||||
|
}
|
||||||
|
|
||||||
func clear(t *testing.T) {
|
func clear(t *testing.T) {
|
||||||
for _, m := range gou.Models {
|
for _, m := range gou.Models {
|
||||||
err := m.DropTable()
|
err := m.DropTable()
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,11 @@ func (dsl *DSL) Xgen() (map[string]interface{}, error) {
|
||||||
setting["config"] = dsl.Config
|
setting["config"] = dsl.Config
|
||||||
for _, cProp := range dsl.CProps {
|
for _, cProp := range dsl.CProps {
|
||||||
err := cProp.Replace(setting, func(cProp component.CloudPropsDSL) interface{} {
|
err := cProp.Replace(setting, func(cProp component.CloudPropsDSL) interface{} {
|
||||||
|
|
||||||
|
if cProp.Type == "Upload" {
|
||||||
|
return fmt.Sprintf("/api/__yao/table/%s%s", dsl.ID, cProp.UploadPath())
|
||||||
|
}
|
||||||
|
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"api": fmt.Sprintf("/api/__yao/table/%s%s", dsl.ID, cProp.Path()),
|
"api": fmt.Sprintf("/api/__yao/table/%s%s", dsl.ID, cProp.Path()),
|
||||||
"params": cProp.Query,
|
"params": cProp.Query,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
"github.com/yaoapp/yao/flow"
|
"github.com/yaoapp/yao/flow"
|
||||||
|
"github.com/yaoapp/yao/fs"
|
||||||
"github.com/yaoapp/yao/model"
|
"github.com/yaoapp/yao/model"
|
||||||
"github.com/yaoapp/yao/runtime"
|
"github.com/yaoapp/yao/runtime"
|
||||||
"github.com/yaoapp/yao/script"
|
"github.com/yaoapp/yao/script"
|
||||||
|
|
@ -41,6 +42,12 @@ func prepare(t *testing.T, language ...string) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load fs
|
||||||
|
err = fs.Load(config.Conf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// load scripts
|
// load scripts
|
||||||
err = script.Load(config.Conf)
|
err = script.Load(config.Conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ type ActionDSL struct {
|
||||||
Bind *BindActionDSL `json:"bind,omitempty"`
|
Bind *BindActionDSL `json:"bind,omitempty"`
|
||||||
Setting *action.Process `json:"setting,omitempty"`
|
Setting *action.Process `json:"setting,omitempty"`
|
||||||
Component *action.Process `json:"component,omitempty"`
|
Component *action.Process `json:"component,omitempty"`
|
||||||
|
Upload *action.Process `json:"upload,omitempty"`
|
||||||
Search *action.Process `json:"search,omitempty"`
|
Search *action.Process `json:"search,omitempty"`
|
||||||
Get *action.Process `json:"get,omitempty"`
|
Get *action.Process `json:"get,omitempty"`
|
||||||
Find *action.Process `json:"find,omitempty"`
|
Find *action.Process `json:"find,omitempty"`
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue