Merge pull request #262 from trheyi/main
[add] form widget download API & process
This commit is contained in:
commit
3075c03e8a
7 changed files with 128 additions and 12 deletions
|
|
@ -121,7 +121,13 @@ func Upload(args ...interface{}) (interface{}, error) {
|
||||||
return nil, fmt.Errorf("Upload args[4] is not string")
|
return nil, fmt.Errorf("Upload args[4] is not string")
|
||||||
}
|
}
|
||||||
|
|
||||||
preifx := fmt.Sprintf("/api/__yao/table/%s/download/%s?name=", id, url.QueryEscape(path))
|
widget := "table"
|
||||||
|
pinfo := strings.Split(path, ".")
|
||||||
|
if len(pinfo) >= 2 {
|
||||||
|
widget = pinfo[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
preifx := fmt.Sprintf("/api/__yao/%s/%s/download/%s?name=", widget, id, url.QueryEscape(path))
|
||||||
res := []string{}
|
res := []string{}
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
file = strings.TrimSpace(file)
|
file = strings.TrimSpace(file)
|
||||||
|
|
@ -195,6 +201,12 @@ func Download(args ...interface{}) (interface{}, error) {
|
||||||
return nil, fmt.Errorf("Download args[4] is not string")
|
return nil, fmt.Errorf("Download args[4] is not string")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
widget := "table"
|
||||||
|
pinfo := strings.Split(path, ".")
|
||||||
|
if len(pinfo) >= 2 {
|
||||||
|
widget = pinfo[1]
|
||||||
|
}
|
||||||
|
|
||||||
res := []string{}
|
res := []string{}
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
|
|
||||||
|
|
@ -204,7 +216,7 @@ func Download(args ...interface{}) (interface{}, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
file = fmt.Sprintf("/api/__yao/table/%s/download/%s?name=%s", id, url.QueryEscape(path), file)
|
file = fmt.Sprintf("/api/__yao/%s/%s/download/%s?name=%s", widget, id, url.QueryEscape(path), file)
|
||||||
res = append(res, file)
|
res = append(res, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,12 @@ var processActionDefaults = map[string]*action.Process{
|
||||||
Guard: "bearer-jwt",
|
Guard: "bearer-jwt",
|
||||||
Default: []interface{}{nil, nil, nil},
|
Default: []interface{}{nil, nil, nil},
|
||||||
},
|
},
|
||||||
|
"Download": {
|
||||||
|
Name: "yao.form.Download",
|
||||||
|
Guard: "-",
|
||||||
|
Process: "fs.system.Download",
|
||||||
|
Default: []interface{}{nil},
|
||||||
|
},
|
||||||
"Find": {
|
"Find": {
|
||||||
Name: "yao.form.Find",
|
Name: "yao.form.Find",
|
||||||
Guard: "bearer-jwt",
|
Guard: "bearer-jwt",
|
||||||
|
|
@ -69,6 +75,10 @@ func (act *ActionDSL) SetDefaultProcess() {
|
||||||
Merge(processActionDefaults["Upload"]).
|
Merge(processActionDefaults["Upload"]).
|
||||||
SetHandler(processHandler)
|
SetHandler(processHandler)
|
||||||
|
|
||||||
|
act.Download = action.ProcessOf(act.Download).
|
||||||
|
Merge(processActionDefaults["Download"]).
|
||||||
|
SetHandler(processHandler)
|
||||||
|
|
||||||
act.Find = action.ProcessOf(act.Find).
|
act.Find = action.ProcessOf(act.Find).
|
||||||
WithBefore(act.BeforeFind).WithAfter(act.AfterFind).
|
WithBefore(act.BeforeFind).WithAfter(act.AfterFind).
|
||||||
Merge(processActionDefaults["Find"]).
|
Merge(processActionDefaults["Find"]).
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ func (form *DSL) getAction(path string) (*action.Process, error) {
|
||||||
return form.Action.Component, nil
|
return form.Action.Component, nil
|
||||||
case "/api/__yao/form/:id/upload/:xpath/:method":
|
case "/api/__yao/form/:id/upload/:xpath/:method":
|
||||||
return form.Action.Upload, nil
|
return form.Action.Upload, nil
|
||||||
|
case "/api/__yao/form/:id/download/:field":
|
||||||
|
return form.Action.Download, nil
|
||||||
case "/api/__yao/form/:id/find/:primary":
|
case "/api/__yao/form/:id/find/:primary":
|
||||||
return form.Action.Find, nil
|
return form.Action.Find, nil
|
||||||
case "/api/__yao/form/:id/save":
|
case "/api/__yao/form/:id/save":
|
||||||
|
|
@ -128,6 +130,22 @@ func exportAPI() error {
|
||||||
}
|
}
|
||||||
http.Paths = append(http.Paths, path)
|
http.Paths = append(http.Paths, path)
|
||||||
|
|
||||||
|
// GET /api/__yao/form/:id/download/:field -> Default process: yao.form.Download $param.id $param.xpath $param.field $query.name $query.token
|
||||||
|
path = gou.Path{
|
||||||
|
Label: "Download",
|
||||||
|
Description: "Download",
|
||||||
|
Path: "/:id/download/:field",
|
||||||
|
Method: "GET",
|
||||||
|
Process: "yao.form.Download",
|
||||||
|
In: []string{"$param.id", "$param.field", "$query.name", "$query.token"},
|
||||||
|
Out: gou.Out{
|
||||||
|
Status: 200,
|
||||||
|
Body: "{{content}}",
|
||||||
|
Headers: map[string]string{"Content-Type": "{{type}}"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
http.Paths = append(http.Paths, path)
|
||||||
|
|
||||||
// POST /api/__yao/form/:id/save -> Default process: yao.form.Save $param.id :payload
|
// POST /api/__yao/form/:id/save -> Default process: yao.form.Save $param.id :payload
|
||||||
path = gou.Path{
|
path = gou.Path{
|
||||||
Label: "Save",
|
Label: "Save",
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ func (dsl *DSL) getField() func(string) (*field.ColumnDSL, string, string, error
|
||||||
return func(name string) (*field.ColumnDSL, string, string, error) {
|
return func(name string) (*field.ColumnDSL, string, string, error) {
|
||||||
field, has := dsl.Fields.Form[name]
|
field, has := dsl.Fields.Form[name]
|
||||||
if !has {
|
if !has {
|
||||||
return nil, "fields.table", dsl.ID, fmt.Errorf("fields.table.%s does not exist", name)
|
return nil, "fields.form", dsl.ID, fmt.Errorf("fields.form.%s does not exist", name)
|
||||||
}
|
}
|
||||||
return &field, "fields.table", dsl.ID, nil
|
return &field, "fields.form", dsl.ID, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,13 @@ package form
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/gou/fs"
|
||||||
"github.com/yaoapp/kun/exception"
|
"github.com/yaoapp/kun/exception"
|
||||||
|
"github.com/yaoapp/kun/log"
|
||||||
|
"github.com/yaoapp/yao/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Export process
|
// Export process
|
||||||
|
|
@ -13,6 +17,7 @@ func exportProcess() {
|
||||||
gou.RegisterProcessHandler("yao.form.xgen", processXgen)
|
gou.RegisterProcessHandler("yao.form.xgen", processXgen)
|
||||||
gou.RegisterProcessHandler("yao.form.component", processComponent)
|
gou.RegisterProcessHandler("yao.form.component", processComponent)
|
||||||
gou.RegisterProcessHandler("yao.form.upload", processUpload)
|
gou.RegisterProcessHandler("yao.form.upload", processUpload)
|
||||||
|
gou.RegisterProcessHandler("yao.form.download", processDownload)
|
||||||
gou.RegisterProcessHandler("yao.form.find", processFind)
|
gou.RegisterProcessHandler("yao.form.find", processFind)
|
||||||
gou.RegisterProcessHandler("yao.form.save", processSave)
|
gou.RegisterProcessHandler("yao.form.save", processSave)
|
||||||
gou.RegisterProcessHandler("yao.form.create", processCreate)
|
gou.RegisterProcessHandler("yao.form.create", processCreate)
|
||||||
|
|
@ -60,6 +65,50 @@ func processComponent(process *gou.Process) interface{} {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func processDownload(process *gou.Process) interface{} {
|
||||||
|
|
||||||
|
process.ValidateArgNums(4)
|
||||||
|
form := MustGet(process)
|
||||||
|
field := process.ArgsString(1)
|
||||||
|
file := process.ArgsString(2)
|
||||||
|
tokenString := process.ArgsString(3)
|
||||||
|
|
||||||
|
// checking
|
||||||
|
ext := fs.ExtName(file)
|
||||||
|
if _, has := fs.DownloadWhitelist[ext]; !has {
|
||||||
|
exception.New("%s.%s .%s file does not allow", 403, form.ID, field, ext).Throw()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auth
|
||||||
|
tokenString = strings.TrimSpace(strings.TrimPrefix(tokenString, "Bearer "))
|
||||||
|
if tokenString == "" {
|
||||||
|
exception.New("%s.%s No permission", 403, form.ID, field).Throw()
|
||||||
|
}
|
||||||
|
claims := helper.JwtValidate(tokenString)
|
||||||
|
|
||||||
|
// Get Process name
|
||||||
|
name := "fs.system.Download"
|
||||||
|
if form.Action.Download.Process != "" {
|
||||||
|
name = form.Action.Download.Process
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create process
|
||||||
|
p, err := gou.ProcessOf(name, file)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[downalod] %s.%s %s", form.ID, field, err.Error())
|
||||||
|
exception.New("[downalod] %s.%s %s", 400, form.ID, field, err.Error()).Throw()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Excute process
|
||||||
|
res, err := p.WithGlobal(process.Global).WithSID(claims.SID).Exec()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[downalod] %s.%s %s", form.ID, field, err.Error())
|
||||||
|
exception.New("[downalod] %s.%s %s", 500, form.ID, field, err.Error()).Throw()
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func processUpload(process *gou.Process) interface{} {
|
func processUpload(process *gou.Process) interface{} {
|
||||||
|
|
||||||
process.ValidateArgNums(4)
|
process.ValidateArgNums(4)
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,11 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/gou/fs"
|
||||||
"github.com/yaoapp/kun/any"
|
"github.com/yaoapp/kun/any"
|
||||||
"github.com/yaoapp/kun/maps"
|
"github.com/yaoapp/kun/maps"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
|
"github.com/yaoapp/yao/helper"
|
||||||
q "github.com/yaoapp/yao/query"
|
q "github.com/yaoapp/yao/query"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -157,6 +159,20 @@ func TestProcessComponent(t *testing.T) {
|
||||||
assert.Equal(t, "checked", pets[1]["status"])
|
assert.Equal(t, "checked", pets[1]["status"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProcessComponentError(t *testing.T) {
|
||||||
|
load(t)
|
||||||
|
clear(t)
|
||||||
|
testData(t)
|
||||||
|
args := []interface{}{
|
||||||
|
"pet",
|
||||||
|
"fields.filter.edit.props.状态.::not-exist",
|
||||||
|
"remote",
|
||||||
|
map[string]interface{}{"select": []string{"name", "status"}, "limit": 2},
|
||||||
|
}
|
||||||
|
_, err := gou.NewProcess("yao.form.Component", args...).Exec()
|
||||||
|
assert.Contains(t, err.Error(), "fields.filter.edit.props.状态.::not-exist")
|
||||||
|
}
|
||||||
|
|
||||||
func TestProcessUpload(t *testing.T) {
|
func TestProcessUpload(t *testing.T) {
|
||||||
load(t)
|
load(t)
|
||||||
clear(t)
|
clear(t)
|
||||||
|
|
@ -178,18 +194,28 @@ func TestProcessUpload(t *testing.T) {
|
||||||
assert.NotEmpty(t, file)
|
assert.NotEmpty(t, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessComponentError(t *testing.T) {
|
func TestProcessDownload(t *testing.T) {
|
||||||
load(t)
|
load(t)
|
||||||
clear(t)
|
clear(t)
|
||||||
testData(t)
|
testData(t)
|
||||||
args := []interface{}{
|
|
||||||
"pet",
|
jwt := helper.JwtMake(1, map[string]interface{}{"id": 1}, map[string]interface{}{"sid": 1})
|
||||||
"fields.filter.edit.props.状态.::not-exist",
|
fs := fs.MustGet("system")
|
||||||
"remote",
|
_, err := fs.WriteFile("/text.txt", []byte("Hello"), uint32(os.ModePerm))
|
||||||
map[string]interface{}{"select": []string{"name", "status"}, "limit": 2},
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
_, err := gou.NewProcess("yao.form.Component", args...).Exec()
|
|
||||||
assert.Contains(t, err.Error(), "fields.filter.edit.props.状态.::not-exist")
|
args := []interface{}{"pet", "images", "/text.txt", jwt.Token}
|
||||||
|
res, err := gou.NewProcess("yao.form.Download", args...).Exec()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, ok := res.(map[string]interface{})
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, []byte("Hello"), body["content"])
|
||||||
|
assert.Equal(t, "text/plain; charset=utf-8", body["type"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessSetting(t *testing.T) {
|
func TestProcessSetting(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ type ActionDSL struct {
|
||||||
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"`
|
Upload *action.Process `json:"upload,omitempty"`
|
||||||
|
Download *action.Process `json:"download,omitempty"`
|
||||||
Find *action.Process `json:"find,omitempty"`
|
Find *action.Process `json:"find,omitempty"`
|
||||||
Save *action.Process `json:"save,omitempty"`
|
Save *action.Process `json:"save,omitempty"`
|
||||||
Update *action.Process `json:"update,omitempty"`
|
Update *action.Process `json:"update,omitempty"`
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue