Merge pull request #262 from trheyi/main

[add] form widget download API & process
This commit is contained in:
Max 2022-11-16 16:23:32 +08:00 committed by GitHub
commit 3075c03e8a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 128 additions and 12 deletions

View file

@ -121,7 +121,13 @@ func Upload(args ...interface{}) (interface{}, error) {
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{}
for _, file := range files {
file = strings.TrimSpace(file)
@ -195,6 +201,12 @@ func Download(args ...interface{}) (interface{}, error) {
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{}
for _, file := range files {
@ -204,7 +216,7 @@ func Download(args ...interface{}) (interface{}, error) {
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)
}

View file

@ -27,6 +27,12 @@ var processActionDefaults = map[string]*action.Process{
Guard: "bearer-jwt",
Default: []interface{}{nil, nil, nil},
},
"Download": {
Name: "yao.form.Download",
Guard: "-",
Process: "fs.system.Download",
Default: []interface{}{nil},
},
"Find": {
Name: "yao.form.Find",
Guard: "bearer-jwt",
@ -69,6 +75,10 @@ func (act *ActionDSL) SetDefaultProcess() {
Merge(processActionDefaults["Upload"]).
SetHandler(processHandler)
act.Download = action.ProcessOf(act.Download).
Merge(processActionDefaults["Download"]).
SetHandler(processHandler)
act.Find = action.ProcessOf(act.Find).
WithBefore(act.BeforeFind).WithAfter(act.AfterFind).
Merge(processActionDefaults["Find"]).

View file

@ -53,6 +53,8 @@ func (form *DSL) getAction(path string) (*action.Process, error) {
return form.Action.Component, nil
case "/api/__yao/form/:id/upload/:xpath/:method":
return form.Action.Upload, nil
case "/api/__yao/form/:id/download/:field":
return form.Action.Download, nil
case "/api/__yao/form/:id/find/:primary":
return form.Action.Find, nil
case "/api/__yao/form/:id/save":
@ -128,6 +130,22 @@ func exportAPI() error {
}
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
path = gou.Path{
Label: "Save",

View file

@ -11,9 +11,9 @@ func (dsl *DSL) getField() func(string) (*field.ColumnDSL, string, string, error
return func(name string) (*field.ColumnDSL, string, string, error) {
field, has := dsl.Fields.Form[name]
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
}
}

View file

@ -2,9 +2,13 @@ package form
import (
"fmt"
"strings"
"github.com/yaoapp/gou"
"github.com/yaoapp/gou/fs"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/helper"
)
// Export process
@ -13,6 +17,7 @@ func exportProcess() {
gou.RegisterProcessHandler("yao.form.xgen", processXgen)
gou.RegisterProcessHandler("yao.form.component", processComponent)
gou.RegisterProcessHandler("yao.form.upload", processUpload)
gou.RegisterProcessHandler("yao.form.download", processDownload)
gou.RegisterProcessHandler("yao.form.find", processFind)
gou.RegisterProcessHandler("yao.form.save", processSave)
gou.RegisterProcessHandler("yao.form.create", processCreate)
@ -60,6 +65,50 @@ func processComponent(process *gou.Process) interface{} {
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{} {
process.ValidateArgNums(4)

View file

@ -8,9 +8,11 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou"
"github.com/yaoapp/gou/fs"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/helper"
q "github.com/yaoapp/yao/query"
)
@ -157,6 +159,20 @@ func TestProcessComponent(t *testing.T) {
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) {
load(t)
clear(t)
@ -178,18 +194,28 @@ func TestProcessUpload(t *testing.T) {
assert.NotEmpty(t, file)
}
func TestProcessComponentError(t *testing.T) {
func TestProcessDownload(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},
jwt := helper.JwtMake(1, map[string]interface{}{"id": 1}, map[string]interface{}{"sid": 1})
fs := fs.MustGet("system")
_, err := fs.WriteFile("/text.txt", []byte("Hello"), uint32(os.ModePerm))
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) {

View file

@ -27,6 +27,7 @@ type ActionDSL struct {
Setting *action.Process `json:"setting,omitempty"`
Component *action.Process `json:"component,omitempty"`
Upload *action.Process `json:"upload,omitempty"`
Download *action.Process `json:"download,omitempty"`
Find *action.Process `json:"find,omitempty"`
Save *action.Process `json:"save,omitempty"`
Update *action.Process `json:"update,omitempty"`