add rule and deparment user_id
This commit is contained in:
parent
c5eade1523
commit
bcd8545930
33 changed files with 574 additions and 39 deletions
55
.vscode/launch.json
vendored
Normal file
55
.vscode/launch.json
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Execute Designated process",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${workspaceFolder}/main.go",
|
||||
"cwd": "/Users/juzhongsun/Works/yao-project",
|
||||
"args": [
|
||||
"run",
|
||||
"yao.app.menu",
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Launch Yao Project",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${workspaceFolder}/main.go",
|
||||
"cwd": "/Users/juzhongsun/Works/yao-project",
|
||||
"args": [
|
||||
"start"
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Launch Fabric Project",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${workspaceFolder}/main.go",
|
||||
"cwd": "/Users/juzhongsun/Works/yao-fabric",
|
||||
"args": [
|
||||
"start"
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Launch Fabric Process",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${workspaceFolder}/main.go",
|
||||
"cwd": "/Users/juzhongsun/Works/yao-fabric",
|
||||
"args": [
|
||||
"run",
|
||||
"models.crm.person.Get",
|
||||
"::{\"withs\": {\"company\": { \"query\": { \"select\": [\"name\"] }}}, \"wheres\": [{\"rel\": \"company\", \"column\":\"name\", \"value\": \"绍兴市金桥纺织有限公司\"}]}"
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
32
Makefile
32
Makefile
|
|
@ -283,7 +283,7 @@ release: clean
|
|||
# ** XGEN will be renamed to DUI in the feature. and move to the new repository. **
|
||||
# ** new repository: https://github.com/YaoApp/dui.git **
|
||||
export NODE_ENV=production
|
||||
git clone https://github.com/YaoApp/xgen.git .tmp/xgen/v1.0
|
||||
git clone https://github.com/sjzsdu/xgen.git .tmp/xgen/v1.0
|
||||
# cd .tmp/xgen/v1.0 && git checkout 5002c3fded585aaa69a4366135b415ea3234964e
|
||||
echo "BASE=__yao_admin_root" > .tmp/xgen/v1.0/packages/xgen/.env
|
||||
cd .tmp/xgen/v1.0 && pnpm install --no-frozen-lockfile && pnpm run build
|
||||
|
|
@ -347,7 +347,7 @@ linux-release: clean
|
|||
# ** XGEN will be renamed to DUI in the feature. and move to the new repository. **
|
||||
# ** new repository: https://github.com/YaoApp/dui.git **
|
||||
export NODE_ENV=production
|
||||
git clone https://github.com/YaoApp/xgen.git .tmp/xgen/v1.0
|
||||
git clone https://github.com/sjzsdu/xgen.git .tmp/xgen/v1.0
|
||||
rm -f .tmp/xgen/v1.0/pnpm-lock.yaml
|
||||
echo "BASE=__yao_admin_root" > .tmp/xgen/v1.0/packages/xgen/.env
|
||||
cd .tmp/xgen/v1.0 && pnpm install --no-frozen-lockfile && pnpm run build
|
||||
|
|
@ -387,6 +387,34 @@ linux-release: clean
|
|||
CGO_ENABLED=1 CGO_LDFLAGS="-static" go build -v -o dist/release/yao
|
||||
chmod +x dist/release/yao
|
||||
|
||||
|
||||
.PHONY: ubutu-release
|
||||
ubutu-release: clean
|
||||
mkdir -p dist/release
|
||||
mkdir .tmp
|
||||
# Checkout init
|
||||
git clone https://github.com/YaoApp/yao-init.git .tmp/yao-init
|
||||
rm -rf .tmp/yao-init/.git
|
||||
rm -rf .tmp/yao-init/.gitignore
|
||||
rm -rf .tmp/yao-init/LICENSE
|
||||
rm -rf .tmp/yao-init/README.md
|
||||
|
||||
# Packing
|
||||
mkdir -p .tmp/data/xgen
|
||||
cp -r ./ui .tmp/data/ui
|
||||
cp -r ./yao .tmp/data/yao
|
||||
cp -r xgenDist .tmp/data/xgen/v1.0
|
||||
cp -r .tmp/yao-init .tmp/data/init
|
||||
go-bindata -fs -pkg data -o data/bindata.go -prefix ".tmp/data/" .tmp/data/...
|
||||
rm -rf .tmp/data
|
||||
rm -rf .tmp/xgen
|
||||
|
||||
# Making artifacts
|
||||
mkdir -p dist
|
||||
CGO_ENABLED=1 CGO_LDFLAGS="-static" go build -v -o dist/release/yao
|
||||
chmod +x dist/release/yao
|
||||
|
||||
|
||||
# make clean
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/yaoapp/yao/pipe"
|
||||
"github.com/yaoapp/yao/plugin"
|
||||
"github.com/yaoapp/yao/query"
|
||||
"github.com/yaoapp/yao/rules"
|
||||
"github.com/yaoapp/yao/runtime"
|
||||
"github.com/yaoapp/yao/schedule"
|
||||
"github.com/yaoapp/yao/script"
|
||||
|
|
@ -153,6 +154,12 @@ func Load(cfg config.Config, options LoadOption) (err error) {
|
|||
printErr(cfg.Mode, "Plugin", err)
|
||||
}
|
||||
|
||||
// Load Rules
|
||||
err = rules.Load(cfg)
|
||||
if err != nil {
|
||||
printErr(cfg.Mode, "Rules", err)
|
||||
}
|
||||
|
||||
// Load WASM Application (experimental)
|
||||
|
||||
// Load build-in widgets (table / form / chart / ...)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
|
|
@ -191,59 +192,80 @@ func NewArrayTreeOption(option map[string]interface{}) ArrayTreeOption {
|
|||
// ArrayTree []map[string]interface{} 转树形结构
|
||||
func ArrayTree(records []map[string]interface{}, setting map[string]interface{}) []map[string]interface{} {
|
||||
opt := NewArrayTreeOption(setting)
|
||||
return opt.Tree(records)
|
||||
res, err := opt.Tree(records)
|
||||
if err == nil {
|
||||
return res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tree Array 转换为 Tree
|
||||
func (opt ArrayTreeOption) Tree(records []map[string]interface{}) []map[string]interface{} {
|
||||
|
||||
func (opt ArrayTreeOption) Tree(records []map[string]interface{}) ([]map[string]interface{}, error) {
|
||||
mapping := map[string]map[string]interface{}{}
|
||||
for i := range records {
|
||||
if key, has := records[i][opt.Key]; has {
|
||||
primary := fmt.Sprintf("%v", key)
|
||||
mapping[primary] = map[string]interface{}{}
|
||||
mapping[primary][opt.Children] = []map[string]interface{}{}
|
||||
for k, v := range records[i] {
|
||||
mapping[primary][k] = v
|
||||
}
|
||||
recordOrder := []string{}
|
||||
|
||||
for _, record := range records {
|
||||
key, hasKey := record[opt.Key]
|
||||
if !hasKey {
|
||||
return nil, errors.New("missing key field")
|
||||
}
|
||||
|
||||
primary := fmt.Sprintf("%v", key)
|
||||
mapping[primary] = make(map[string]interface{})
|
||||
mapping[primary][opt.Children] = []map[string]interface{}{}
|
||||
|
||||
for k, v := range record {
|
||||
mapping[primary][k] = v
|
||||
}
|
||||
|
||||
recordOrder = append(recordOrder, primary)
|
||||
}
|
||||
|
||||
// 向上归集
|
||||
for key, record := range mapping {
|
||||
for _, key := range recordOrder {
|
||||
record := mapping[key]
|
||||
|
||||
parent := fmt.Sprintf("%v", record[opt.Parent])
|
||||
empty := fmt.Sprintf("%v", opt.Empty)
|
||||
if parent == empty { // 第一级
|
||||
continue
|
||||
}
|
||||
|
||||
pKey := fmt.Sprintf("%v", parent)
|
||||
if _, has := mapping[pKey]; !has {
|
||||
parentRecord, hasParent := mapping[pKey]
|
||||
if !hasParent {
|
||||
continue
|
||||
}
|
||||
children, ok := mapping[pKey][opt.Children].([]map[string]interface{})
|
||||
|
||||
children, ok := parentRecord[opt.Children].([]map[string]interface{})
|
||||
if !ok {
|
||||
children = []map[string]interface{}{}
|
||||
}
|
||||
children = append(children, mapping[key])
|
||||
mapping[pKey][opt.Children] = children
|
||||
|
||||
children = append(children, record)
|
||||
parentRecord[opt.Children] = children
|
||||
mapping[pKey] = parentRecord
|
||||
}
|
||||
|
||||
res := []map[string]interface{}{}
|
||||
for i := range records {
|
||||
if key, has := records[i][opt.Key]; has {
|
||||
record := mapping[fmt.Sprintf("%v", key)]
|
||||
if pValue, has := record[opt.Parent]; has {
|
||||
parent := fmt.Sprintf("%v", pValue)
|
||||
empty := fmt.Sprintf("%v", opt.Empty)
|
||||
if parent == empty { // 父类为空
|
||||
res = append(res, record)
|
||||
} else if _, has := mapping[parent]; !has { // 或者父类为定义的
|
||||
res = append(res, record)
|
||||
}
|
||||
for _, key := range recordOrder {
|
||||
record := mapping[key]
|
||||
|
||||
// recordKey := fmt.Sprintf("%v", record[opt.Key])
|
||||
recordValue, hasParent := record[opt.Parent]
|
||||
|
||||
if hasParent {
|
||||
parent := fmt.Sprintf("%v", recordValue)
|
||||
empty := fmt.Sprintf("%v", opt.Empty)
|
||||
|
||||
if parent == empty || len(mapping[parent]) == 0 {
|
||||
res = append(res, record)
|
||||
}
|
||||
} else {
|
||||
res = append(res, record)
|
||||
}
|
||||
}
|
||||
return res
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ArrayMapSet []map[string]interface{} 设定数值
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ func JwtMake(id int, data map[string]interface{}, option map[string]interface{},
|
|||
|
||||
now := time.Now().Unix()
|
||||
sid := ""
|
||||
timeout := int64(3600)
|
||||
timeout := int64(36000)
|
||||
uid := fmt.Sprintf("%d", id)
|
||||
subject := "User Token"
|
||||
audience := "Yao Process utils.jwt.Make"
|
||||
|
|
|
|||
11
helper/str.go
Normal file
11
helper/str.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package helper
|
||||
|
||||
// 检查字符串数组中是否包含某个字符
|
||||
func ContainsString(arr []string, char string) bool {
|
||||
for _, str := range arr {
|
||||
if str == char {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
35
rules/api.go
Normal file
35
rules/api.go
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yaoapp/gou/session"
|
||||
"github.com/yaoapp/kun/any"
|
||||
"github.com/yaoapp/yao/helper"
|
||||
)
|
||||
|
||||
// Guard table widget guard
|
||||
func Guard(c *gin.Context, rule string) {
|
||||
sid, exists := c.Get("__sid")
|
||||
if !exists {
|
||||
abort(c, 400, "session id is not found")
|
||||
return
|
||||
}
|
||||
user, err := session.Global().ID(sid.(string)).Get("user")
|
||||
if err != nil {
|
||||
abort(c, 400, "user is not found")
|
||||
return
|
||||
}
|
||||
ruleIds := any.Of(user).MapStr().Get("rule_ids")
|
||||
ruleIds = any.Of(ruleIds).CStrings()
|
||||
if !helper.ContainsString(ruleIds.([]string), rule) && !helper.ContainsString(ruleIds.([]string), "*") {
|
||||
abort(c, 400, fmt.Sprintf("no permission for this action: %s", rule))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func abort(c *gin.Context, code int, message string) {
|
||||
c.JSON(code, gin.H{"code": code, "message": message})
|
||||
c.Abort()
|
||||
}
|
||||
125
rules/load.go
Normal file
125
rules/load.go
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/yaoapp/gou/application"
|
||||
"github.com/yaoapp/yao/config"
|
||||
"github.com/yaoapp/yao/share"
|
||||
)
|
||||
|
||||
var RuleDSLS map[string]*DSL = map[string]*DSL{}
|
||||
|
||||
func Load(cfg config.Config) error {
|
||||
messages := []string{}
|
||||
exts := []string{"*.rul.yao", "*.rul.json", "*.rul.jsonc"}
|
||||
err := application.App.Walk("rules", func(root, file string, isdir bool) error {
|
||||
if isdir {
|
||||
return nil
|
||||
}
|
||||
if err := LoadFile(root, file); err != nil {
|
||||
messages = append(messages, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}, exts...)
|
||||
|
||||
exportProcess()
|
||||
|
||||
if len(messages) > 0 {
|
||||
return fmt.Errorf(strings.Join(messages, ";\n"))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func LoadFile(root string, file string) error {
|
||||
|
||||
id := share.ID(root, file)
|
||||
data, err := application.App.Read(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = load(data, id, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadSource load table dsl by source
|
||||
func load(source []byte, id string, file string) (*DSL, error) {
|
||||
dsl := &DSL{
|
||||
Rule: &Rule{
|
||||
ID: id,
|
||||
Children: []Rule{},
|
||||
},
|
||||
file: file,
|
||||
source: source,
|
||||
}
|
||||
err := dsl.parse()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[%s] %s", id, err.Error())
|
||||
}
|
||||
|
||||
RuleDSLS[id] = dsl
|
||||
return dsl, nil
|
||||
}
|
||||
|
||||
// parse method to parse and generate keys
|
||||
func (dsl *DSL) parse() error {
|
||||
err := application.Parse(dsl.file, dsl.source, dsl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
generateKeys(dsl.Rule, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateKeys recursively generates keys for rules
|
||||
func generateKeys(rule *Rule, parentKey string) {
|
||||
if parentKey == "" {
|
||||
rule.Key = rule.ID
|
||||
} else {
|
||||
rule.Key = fmt.Sprintf("%s_%s", parentKey, rule.ID)
|
||||
}
|
||||
|
||||
for i := range rule.Children {
|
||||
generateKeys(&rule.Children[i], rule.Key)
|
||||
}
|
||||
}
|
||||
|
||||
// GetMainKeys returns a slice of main keys in RuleDSLS
|
||||
func GetMainKeys() []string {
|
||||
keys := []string{}
|
||||
for key := range RuleDSLS {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// GetAllKeys 返回Rule结构及其子结构中的所有Key字段
|
||||
func GetAllKeys() []string {
|
||||
var keys []string
|
||||
var collectKeys func(r Rule)
|
||||
|
||||
// 定义递归函数来收集Key
|
||||
collectKeys = func(r Rule) {
|
||||
if r.Key != "" {
|
||||
keys = append(keys, r.Key)
|
||||
}
|
||||
for _, child := range r.Children {
|
||||
collectKeys(child)
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历RuleDSLS,收集所有Key
|
||||
for _, dsl := range RuleDSLS {
|
||||
if dsl.Rule != nil {
|
||||
collectKeys(*dsl.Rule)
|
||||
}
|
||||
}
|
||||
return keys
|
||||
}
|
||||
32
rules/process.go
Normal file
32
rules/process.go
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package rules
|
||||
|
||||
import (
|
||||
gouProcess "github.com/yaoapp/gou/process"
|
||||
)
|
||||
|
||||
func exportProcess() {
|
||||
gouProcess.Register("yao.rule.menus", processMenu)
|
||||
gouProcess.Register("yao.rule.ruleKeys", processRuleKeys)
|
||||
}
|
||||
|
||||
func processMenu(process *gouProcess.Process) interface{} {
|
||||
argsLen := process.NumOfArgs()
|
||||
menuOnly := false
|
||||
dsls := GetMainKeys()
|
||||
menuKeys := []string{"*"}
|
||||
if argsLen == 1 {
|
||||
dsls = process.ArgsStrings(0)
|
||||
} else if argsLen == 2 {
|
||||
dsls = process.ArgsStrings(0)
|
||||
menuOnly = process.ArgsBool(1)
|
||||
} else if argsLen == 3 {
|
||||
dsls = process.ArgsStrings(0)
|
||||
menuOnly = process.ArgsBool(1)
|
||||
menuKeys = process.ArgsStrings(2)
|
||||
}
|
||||
return GetDSLsMaps(dsls, menuOnly, menuKeys)
|
||||
}
|
||||
|
||||
func processRuleKeys(process *gouProcess.Process) interface{} {
|
||||
return GetAllKeys()
|
||||
}
|
||||
63
rules/rule.go
Normal file
63
rules/rule.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
package rules
|
||||
|
||||
import "github.com/yaoapp/yao/helper"
|
||||
|
||||
// rulesToMaps converts a slice of Rule to a slice of maps
|
||||
func rulesToMaps(rules []Rule, onlyMenu bool, keys []string) []map[string]interface{} {
|
||||
maps := []map[string]interface{}{}
|
||||
for _, rule := range rules {
|
||||
if onlyMenu && rule.Path == "" && len(rule.Children) == 0 {
|
||||
continue
|
||||
}
|
||||
if !helper.ContainsString(keys, rule.Key) && !helper.ContainsString(keys, "*") {
|
||||
continue
|
||||
}
|
||||
maps = append(maps, rule.ToMap(onlyMenu, keys))
|
||||
}
|
||||
return maps
|
||||
}
|
||||
|
||||
// ToMap converts a Rule to a map
|
||||
func (rule *Rule) ToMap(onlyMenu bool, keys []string) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": rule.ID,
|
||||
"name": rule.Name,
|
||||
"title": rule.Name,
|
||||
"icon": rule.Icon,
|
||||
"path": rule.Path,
|
||||
"visible_menu": rule.Visible_menu,
|
||||
"children": rulesToMaps(rule.Children, onlyMenu, keys),
|
||||
"rule": rule.Key,
|
||||
}
|
||||
}
|
||||
|
||||
func (dsl *DSL) HasChildren(onlyMenu bool, keys []string) bool {
|
||||
ruls := []Rule{}
|
||||
for _, rule := range dsl.Children {
|
||||
if onlyMenu && rule.Path == "" && len(rule.Children) == 0 {
|
||||
continue
|
||||
}
|
||||
if !helper.ContainsString(keys, rule.Key) && !helper.ContainsString(keys, "*") {
|
||||
continue
|
||||
}
|
||||
ruls = append(ruls, rule)
|
||||
}
|
||||
return len(ruls) > 0
|
||||
}
|
||||
|
||||
// GetDSLsMaps returns the maps of DSLs corresponding to the given IDs
|
||||
func GetDSLsMaps(ids []string, onlyMenu bool, keys []string) []map[string]interface{} {
|
||||
if keys == nil {
|
||||
keys = []string{"*"}
|
||||
}
|
||||
maps := []map[string]interface{}{}
|
||||
for _, id := range ids {
|
||||
if dsl, ok := RuleDSLS[id]; ok {
|
||||
rule := dsl.ToMap(onlyMenu, keys)
|
||||
if dsl.HasChildren(onlyMenu, keys) {
|
||||
maps = append(maps, rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
return maps
|
||||
}
|
||||
17
rules/type.go
Normal file
17
rules/type.go
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package rules
|
||||
|
||||
type Rule struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Key string `json:"-"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Icon string `json:"icon,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Visible_menu int `json:"visible_menu,omitempty"`
|
||||
Children []Rule `json:"children,omitempty"`
|
||||
}
|
||||
|
||||
type DSL struct {
|
||||
*Rule
|
||||
file string `json:"-"`
|
||||
source []byte `json:"-"`
|
||||
}
|
||||
|
|
@ -74,6 +74,7 @@ func guardBearerJWT(c *gin.Context) {
|
|||
|
||||
claims := helper.JwtValidate(tokenString)
|
||||
c.Set("__sid", claims.SID)
|
||||
return
|
||||
}
|
||||
|
||||
// JWT Bearer JWT
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/gou/api"
|
||||
"github.com/yaoapp/yao/rules"
|
||||
"github.com/yaoapp/yao/share"
|
||||
"github.com/yaoapp/yao/widgets/action"
|
||||
)
|
||||
|
|
@ -37,6 +38,7 @@ func Guard(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
rules.Guard(c, chart.Rule)
|
||||
}
|
||||
|
||||
func abort(c *gin.Context, code int, message string) {
|
||||
|
|
|
|||
|
|
@ -102,6 +102,10 @@ func LoadFile(root string, file string) error {
|
|||
// LoadData load via data
|
||||
func (dsl *DSL) parse(id string, root string) error {
|
||||
|
||||
if dsl.Rule == "" {
|
||||
dsl.Rule = strings.ReplaceAll(id, ".", "_")
|
||||
}
|
||||
|
||||
if dsl.Action == nil {
|
||||
dsl.Action = &ActionDSL{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
type DSL struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Rule string `json:"rule,omitempty"`
|
||||
Action *ActionDSL `json:"action"`
|
||||
Layout *LayoutDSL `json:"layout"`
|
||||
Fields *FieldsDSL `json:"fields"`
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ var hanlders = map[string]ComputeHanlder{
|
|||
"Trim": Trim,
|
||||
"Hide": Hide,
|
||||
"Concat": Concat,
|
||||
"ValueOr": ValueOr,
|
||||
"Download": Download,
|
||||
"Upload": Upload,
|
||||
"QueryString": Trim,
|
||||
|
|
@ -52,6 +53,18 @@ func Concat(args ...interface{}) (interface{}, error) {
|
|||
return res, nil
|
||||
}
|
||||
|
||||
// ValueOr
|
||||
func ValueOr(args ...interface{}) (interface{}, error) {
|
||||
res := ""
|
||||
for _, arg := range args {
|
||||
if arg != nil {
|
||||
res = fmt.Sprintf("%v", arg)
|
||||
break
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Get value
|
||||
func Get(args ...interface{}) (interface{}, error) {
|
||||
if len(args) == 0 {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/gou/api"
|
||||
"github.com/yaoapp/yao/rules"
|
||||
"github.com/yaoapp/yao/share"
|
||||
"github.com/yaoapp/yao/widgets/action"
|
||||
)
|
||||
|
|
@ -37,6 +38,7 @@ func Guard(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
rules.Guard(c, dashboard.Rule)
|
||||
}
|
||||
|
||||
func abort(c *gin.Context, code int, message string) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
type DSL struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Rule string `json:"Rule,omitempty"`
|
||||
Action *ActionDSL `json:"action"`
|
||||
Layout *LayoutDSL `json:"layout"`
|
||||
Fields *FieldsDSL `json:"fields"`
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ import (
|
|||
// Filters the filters DSL
|
||||
type Filters map[string]FilterDSL
|
||||
|
||||
// Batch the batch DSL
|
||||
type Batches map[string]FilterDSL
|
||||
|
||||
// Columns the columns DSL
|
||||
type Columns map[string]ColumnDSL
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,23 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/gou/api"
|
||||
"github.com/yaoapp/yao/helper"
|
||||
"github.com/yaoapp/yao/rules"
|
||||
"github.com/yaoapp/yao/share"
|
||||
"github.com/yaoapp/yao/widgets/action"
|
||||
)
|
||||
|
||||
var editAPIS = []string{
|
||||
"/api/__yao/form/:id/upload/:xpath/:method",
|
||||
"/api/__yao/form/:id/save",
|
||||
"/api/__yao/form/:id/create",
|
||||
"/api/__yao/form/:id/insert",
|
||||
}
|
||||
|
||||
var deleteAPIS = []string{
|
||||
"/api/__yao/form/:id/delete/:primary",
|
||||
}
|
||||
|
||||
// Guard form widget guard
|
||||
func Guard(c *gin.Context) {
|
||||
|
||||
|
|
@ -37,6 +50,15 @@ func Guard(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
rules.Guard(c, form.Rule)
|
||||
if helper.ContainsString(editAPIS, c.FullPath()) {
|
||||
ruleKey := fmt.Sprintf("%s_edit", form.Rule)
|
||||
rules.Guard(c, ruleKey)
|
||||
}
|
||||
if helper.ContainsString(deleteAPIS, c.FullPath()) {
|
||||
ruleKey := fmt.Sprintf("%s_del", form.Rule)
|
||||
rules.Guard(c, ruleKey)
|
||||
}
|
||||
}
|
||||
|
||||
func abort(c *gin.Context, code int, message string) {
|
||||
|
|
|
|||
|
|
@ -180,6 +180,10 @@ func load(source []byte, id string, file string) (*DSL, error) {
|
|||
// LoadData load via data
|
||||
func (dsl *DSL) parse(id string) error {
|
||||
|
||||
if dsl.Rule == "" {
|
||||
dsl.Rule = strings.ReplaceAll(id, ".", "_")
|
||||
}
|
||||
|
||||
if dsl.Action == nil {
|
||||
dsl.Action = &ActionDSL{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
type DSL struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Rule string `json:"rule,omitempty"`
|
||||
Action *ActionDSL `json:"action"`
|
||||
Layout *LayoutDSL `json:"layout"`
|
||||
Fields *FieldsDSL `json:"fields"`
|
||||
|
|
@ -94,6 +95,7 @@ type SectionDSL struct {
|
|||
Icon interface{} `json:"icon,omitempty"`
|
||||
Color string `json:"color,omitempty"`
|
||||
Weight interface{} `json:"weight,omitempty"`
|
||||
Rule string `json:"rule,omitempty"`
|
||||
Columns []Column `json:"columns,omitempty"`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/gou/api"
|
||||
"github.com/yaoapp/yao/rules"
|
||||
"github.com/yaoapp/yao/share"
|
||||
"github.com/yaoapp/yao/widgets/action"
|
||||
)
|
||||
|
|
@ -37,6 +38,7 @@ func Guard(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
rules.Guard(c, list.Rule)
|
||||
}
|
||||
|
||||
func abort(c *gin.Context, code int, message string) {
|
||||
|
|
|
|||
|
|
@ -135,6 +135,9 @@ func LoadID(id string, root string) error {
|
|||
// LoadData load via data
|
||||
func (dsl *DSL) parse(id string, root string) error {
|
||||
|
||||
if dsl.Rule == "" {
|
||||
dsl.Rule = strings.ReplaceAll(id, ".", "_")
|
||||
}
|
||||
if dsl.Action == nil {
|
||||
dsl.Action = &ActionDSL{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
type DSL struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Root string `json:"-"`
|
||||
Rule string `json:"rule,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Action *ActionDSL `json:"action"`
|
||||
Layout *LayoutDSL `json:"layout"`
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ func auth(field string, value string, password string, sid string) maps.Map {
|
|||
Wheres: []model.QueryWhere{
|
||||
{Column: column, Value: value},
|
||||
{Column: "status", Value: "enabled"},
|
||||
{Column: "type", Value: "admin"},
|
||||
},
|
||||
})
|
||||
|
||||
|
|
@ -91,6 +92,9 @@ func auth(field string, value string, password string, sid string) maps.Map {
|
|||
}
|
||||
|
||||
row := rows[0]
|
||||
row["rule_ids"] = []string{"*"}
|
||||
row["role_ids"] = []int{0}
|
||||
row["department_ids"] = []int{0}
|
||||
passwordHash := row.Get("password").(string)
|
||||
row.Del("password")
|
||||
|
||||
|
|
@ -99,7 +103,7 @@ func auth(field string, value string, password string, sid string) maps.Map {
|
|||
exception.New("Login password error (%v)", 403, value).Throw()
|
||||
}
|
||||
|
||||
expiresAt := time.Now().Unix() + 3600*8
|
||||
expiresAt := time.Now().Unix() + 36000
|
||||
|
||||
// token := MakeToken(row, expiresAt)
|
||||
id := any.Of(row.Get("id")).CInt()
|
||||
|
|
@ -128,12 +132,19 @@ func auth(field string, value string, password string, sid string) maps.Map {
|
|||
}
|
||||
|
||||
// Get user menus
|
||||
menus := process.New("yao.app.menu").WithSID(sid).Run()
|
||||
// menus := process.New("yao.app.menu").WithSID(sid).Run()
|
||||
// 读取菜单
|
||||
setting := process.New("yao.rule.menus", []string{"sys"}, true).WithSID(sid).Run()
|
||||
items := process.New("yao.rule.menus", []string{"pro", "crm"}, true).WithSID(sid).Run()
|
||||
|
||||
return maps.Map{
|
||||
"expires_at": token.ExpiresAt,
|
||||
"token": token.Token,
|
||||
"user": row,
|
||||
"menus": menus,
|
||||
"studio": studio,
|
||||
"menus": maps.Map{
|
||||
"setting": setting,
|
||||
"items": items,
|
||||
},
|
||||
"studio": studio,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package mapping
|
|||
|
||||
// Mapping common
|
||||
type Mapping struct {
|
||||
Batches map[string]string
|
||||
Filters map[string]string
|
||||
Columns map[string]string
|
||||
Actions map[string]string
|
||||
|
|
|
|||
|
|
@ -6,10 +6,28 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/gou/api"
|
||||
"github.com/yaoapp/yao/helper"
|
||||
"github.com/yaoapp/yao/rules"
|
||||
"github.com/yaoapp/yao/share"
|
||||
"github.com/yaoapp/yao/widgets/action"
|
||||
)
|
||||
|
||||
var editAPIS = []string{
|
||||
"/api/__yao/table/:id/upload/:xpath/:method",
|
||||
"/api/__yao/table/:id/save",
|
||||
"/api/__yao/table/:id/create",
|
||||
"/api/__yao/table/:id/insert",
|
||||
"/api/__yao/table/:id/update/:primary",
|
||||
"/api/__yao/table/:id/update/in",
|
||||
"/api/__yao/table/:id/update/where",
|
||||
}
|
||||
|
||||
var deleteAPIS = []string{
|
||||
"/api/__yao/table/:id/delete/:primary",
|
||||
"/api/__yao/table/:id/delete/in",
|
||||
"/api/__yao/table/:id/delete/where",
|
||||
}
|
||||
|
||||
// Guard table widget guard
|
||||
func Guard(c *gin.Context) {
|
||||
|
||||
|
|
@ -37,6 +55,15 @@ func Guard(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
rules.Guard(c, tab.Rule)
|
||||
if helper.ContainsString(editAPIS, c.FullPath()) {
|
||||
ruleKey := fmt.Sprintf("%s_edit", tab.Rule)
|
||||
rules.Guard(c, ruleKey)
|
||||
}
|
||||
if helper.ContainsString(deleteAPIS, c.FullPath()) {
|
||||
ruleKey := fmt.Sprintf("%s_del", tab.Rule)
|
||||
rules.Guard(c, ruleKey)
|
||||
}
|
||||
}
|
||||
|
||||
func abort(c *gin.Context, code int, message string) {
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ func (layout *LayoutDSL) Xgen(data map[string]interface{}, excludes map[string]b
|
|||
if clone.Header.Preset.Batch != nil && clone.Header.Preset.Batch.Columns != nil {
|
||||
columns := []component.InstanceDSL{}
|
||||
for _, column := range clone.Header.Preset.Batch.Columns {
|
||||
id, has := mapping.Filters[column.Name]
|
||||
id, has := mapping.Batches[column.Name]
|
||||
if !has {
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,10 @@ func (dsl *DSL) mapping() error {
|
|||
dsl.Mapping.Filters = map[string]string{}
|
||||
}
|
||||
|
||||
if dsl.Mapping.Batches == nil {
|
||||
dsl.Mapping.Batches = map[string]string{}
|
||||
}
|
||||
|
||||
if dsl.Mapping.Columns == nil {
|
||||
dsl.Mapping.Columns = map[string]string{}
|
||||
}
|
||||
|
|
@ -84,6 +88,27 @@ func (dsl *DSL) mapping() error {
|
|||
}
|
||||
}
|
||||
|
||||
if dsl.Fields.Batch != nil && dsl.Layout.Header.Preset.Batch != nil && dsl.Layout.Header.Preset.Batch.Columns != nil {
|
||||
for _, inst := range dsl.Layout.Header.Preset.Batch.Columns {
|
||||
|
||||
if batch, has := dsl.Fields.Batch[inst.Name]; has {
|
||||
|
||||
// Mapping ID
|
||||
dsl.Mapping.Batches[batch.ID] = inst.Name
|
||||
dsl.Mapping.Batches[inst.Name] = batch.ID
|
||||
|
||||
// Mapping Compute
|
||||
if batch.Edit != nil && batch.Edit.Compute != nil {
|
||||
bind := batch.FilterBind()
|
||||
if _, has := dsl.Computes.Filter[bind]; !has {
|
||||
dsl.Computes.Filter[bind] = []compute.Unit{}
|
||||
}
|
||||
dsl.Computes.Filter[bind] = append(dsl.Computes.Filter[bind], compute.Unit{Name: inst.Name, Kind: compute.Filter})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if dsl.Fields.Table != nil && dsl.Layout.Table != nil && dsl.Layout.Table.Columns != nil {
|
||||
for _, inst := range dsl.Layout.Table.Columns {
|
||||
if field, has := dsl.Fields.Table[inst.Name]; has {
|
||||
|
|
|
|||
|
|
@ -260,8 +260,11 @@ func processDeleteIn(process *gouProcess.Process) interface{} {
|
|||
func processExport(process *gouProcess.Process) interface{} {
|
||||
process.ValidateArgNums(1)
|
||||
tab := MustGet(process) // 0
|
||||
|
||||
params := process.ArgsQueryParams(1, types.QueryParam{})
|
||||
pagesize := process.ArgsInt(2, 50)
|
||||
page := process.ArgsInt(2, 1)
|
||||
pagesize := process.ArgsInt(3, 50)
|
||||
|
||||
log.Trace("[table] export %s %v %d", tab.ID, params, pagesize)
|
||||
|
||||
// Filename
|
||||
|
|
@ -276,7 +279,7 @@ func processExport(process *gouProcess.Process) interface{} {
|
|||
}
|
||||
|
||||
// Query
|
||||
page := 1
|
||||
|
||||
for page > 0 {
|
||||
process.Args = []interface{}{tab.ID, params, page, pagesize}
|
||||
data, err := tab.Action.Search.Exec(process)
|
||||
|
|
|
|||
|
|
@ -209,6 +209,10 @@ func load(source []byte, id string, file string) (*DSL, error) {
|
|||
// parse parse table dsl source
|
||||
func (dsl *DSL) parse(id string) error {
|
||||
|
||||
if dsl.Rule == "" {
|
||||
dsl.Rule = strings.ReplaceAll(id, ".", "_")
|
||||
}
|
||||
|
||||
if dsl.Action == nil {
|
||||
dsl.Action = &ActionDSL{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ type DSL struct {
|
|||
// Root string `json:"-"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Rule string `json:"rule,omitempty"`
|
||||
Action *ActionDSL `json:"action"`
|
||||
Layout *LayoutDSL `json:"layout"`
|
||||
Fields *FieldsDSL `json:"fields"`
|
||||
|
|
@ -99,6 +100,12 @@ type HeaderLayoutDSL struct {
|
|||
type PresetHeaderDSL struct {
|
||||
Batch *BatchPresetDSL `json:"batch,omitempty"`
|
||||
Import *ImportPresetDSL `json:"import,omitempty"`
|
||||
Column *ColumnDSL `json:"column,omitempty"`
|
||||
Filter *ColumnDSL `json:"filter,omitempty"`
|
||||
}
|
||||
|
||||
type ColumnDSL struct {
|
||||
Musts []string `json:"musts,omitempty"`
|
||||
}
|
||||
|
||||
// BatchPresetDSL layout.header.preset.batch
|
||||
|
|
@ -137,6 +144,7 @@ type OperationTableDSL struct {
|
|||
// FieldsDSL the table fields DSL
|
||||
type FieldsDSL struct {
|
||||
Filter field.Filters `json:"filter,omitempty"`
|
||||
Batch field.Batches `json:"batch,omitempty"`
|
||||
Table field.Columns `json:"table,omitempty"`
|
||||
filterMap map[string]field.FilterDSL
|
||||
tableMap map[string]field.ColumnDSL
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue