优化代码结构 v0.8.8
This commit is contained in:
parent
7b87f3fee5
commit
d03e1fc2e3
28 changed files with 653 additions and 617 deletions
2
Makefile
2
Makefile
|
|
@ -6,7 +6,7 @@ GOFILES := $(shell find . -name "*.go")
|
|||
VERSION := $(shell grep 'const VERSION =' share/vars.go |awk '{print $$4}' |sed 's/\"//g')
|
||||
|
||||
# ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||
TESTFOLDER := $(shell $(GO) list ./... | grep -E 'xiang$$|global$$|table$$|user$$|xfs$$' | grep -v examples)
|
||||
TESTFOLDER := $(shell $(GO) list ./... | grep -E 'xiang$$|entry$$|table$$|user$$|xfs$$' | grep -v examples)
|
||||
TESTTAGS ?= ""
|
||||
|
||||
# 运行单元测试
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/xiang/config"
|
||||
"github.com/yaoapp/xiang/global"
|
||||
"github.com/yaoapp/xiang/entry"
|
||||
)
|
||||
|
||||
var name string
|
||||
|
|
@ -18,7 +18,7 @@ var migrateCmd = &cobra.Command{
|
|||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Boot()
|
||||
// 加载数据模型
|
||||
global.Load(config.Conf)
|
||||
entry.Load(config.Conf)
|
||||
|
||||
if name != "" {
|
||||
mod, has := gou.Models[name]
|
||||
|
|
|
|||
11
cmd/start.go
11
cmd/start.go
|
|
@ -9,7 +9,8 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/xiang/config"
|
||||
"github.com/yaoapp/xiang/global"
|
||||
"github.com/yaoapp/xiang/entry"
|
||||
"github.com/yaoapp/xiang/service"
|
||||
"github.com/yaoapp/xiang/share"
|
||||
)
|
||||
|
||||
|
|
@ -18,7 +19,7 @@ var startCmd = &cobra.Command{
|
|||
Short: "启动象传应用引擎",
|
||||
Long: `启动象传应用引擎`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
defer global.ServiceStop(func() { fmt.Println("服务已关闭") })
|
||||
defer service.Stop(func() { fmt.Println("服务已关闭") })
|
||||
|
||||
Boot()
|
||||
mode := config.Conf.Mode
|
||||
|
|
@ -31,7 +32,7 @@ var startCmd = &cobra.Command{
|
|||
fmt.Printf(color.GreenString("\n象传应用引擎 v%s %s", share.VERSION, mode))
|
||||
|
||||
// 加载数据模型 API 等
|
||||
global.Load(config.Conf)
|
||||
entry.Load(config.Conf)
|
||||
|
||||
// 打印应用目录信息
|
||||
fmt.Printf(color.WhiteString("\n---------------------------------"))
|
||||
|
|
@ -78,10 +79,10 @@ var startCmd = &cobra.Command{
|
|||
|
||||
// 调试模式
|
||||
if config.Conf.Mode == "debug" {
|
||||
global.WatchChanges()
|
||||
service.WatchChanges()
|
||||
}
|
||||
|
||||
global.ServiceStart()
|
||||
service.Start()
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
3
entry/READE.md
Normal file
3
entry/READE.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# 程序入口
|
||||
|
||||
加载各种文件
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package global
|
||||
package entry
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
package global
|
||||
package entry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
|
|
@ -21,29 +19,6 @@ import (
|
|||
"github.com/yaoapp/xun/capsule"
|
||||
)
|
||||
|
||||
// Conf 配置文件
|
||||
var Conf config.Config
|
||||
|
||||
// Script 脚本文件类型
|
||||
type Script struct {
|
||||
Name string
|
||||
Type string
|
||||
Content []byte
|
||||
File string
|
||||
}
|
||||
|
||||
// AppRoot 应用目录
|
||||
type AppRoot struct {
|
||||
APIs string
|
||||
Flows string
|
||||
Models string
|
||||
Plugins string
|
||||
Tables string
|
||||
Charts string
|
||||
Screens string
|
||||
Data string
|
||||
}
|
||||
|
||||
// Load 根据配置加载 API, FLow, Model, Plugin
|
||||
func Load(cfg config.Config) {
|
||||
|
||||
|
|
@ -51,7 +26,7 @@ func Load(cfg config.Config) {
|
|||
DBConnect(cfg.Database)
|
||||
LoadAppInfo(cfg.Root)
|
||||
LoadEngine(cfg.Path)
|
||||
LoadApp(AppRoot{
|
||||
LoadApp(share.AppRoot{
|
||||
APIs: cfg.RootAPI,
|
||||
Flows: cfg.RootFLow,
|
||||
Models: cfg.RootModel,
|
||||
|
|
@ -65,9 +40,6 @@ func Load(cfg config.Config) {
|
|||
// 加密密钥函数
|
||||
gou.LoadCrypt(fmt.Sprintf(`{"key":"%s"}`, cfg.Database.AESKey), "AES")
|
||||
gou.LoadCrypt(`{}`, "PASSWORD")
|
||||
|
||||
// 设定已加载配置
|
||||
Conf = cfg
|
||||
}
|
||||
|
||||
// LoadAppInfo 读取应用信息
|
||||
|
|
@ -167,13 +139,13 @@ func AppInit(cfg config.Config) {
|
|||
// LoadEngine 加载引擎的 API, Flow, Model 配置
|
||||
func LoadEngine(from string) {
|
||||
|
||||
var scripts []Script
|
||||
var scripts []share.Script
|
||||
if strings.HasPrefix(from, "fs://") || !strings.Contains(from, "://") {
|
||||
root := strings.TrimPrefix(from, "fs://")
|
||||
scripts = getFilesFS(root, ".json")
|
||||
scripts = share.GetFilesFS(root, ".json")
|
||||
} else if strings.HasPrefix(from, "bin://") {
|
||||
root := strings.TrimPrefix(from, "bin://")
|
||||
scripts = getFilesBin(root, ".json")
|
||||
scripts = share.GetFilesBin(root, ".json")
|
||||
}
|
||||
|
||||
if scripts == nil {
|
||||
|
|
@ -210,7 +182,7 @@ func LoadEngine(from string) {
|
|||
}
|
||||
|
||||
// LoadApp 加载应用的 API, Flow, Model 和 Plugin
|
||||
func LoadApp(app AppRoot) {
|
||||
func LoadApp(app share.AppRoot) {
|
||||
|
||||
// api string, flow string, model string, plugin string
|
||||
// 创建应用目录
|
||||
|
|
@ -235,7 +207,7 @@ func LoadApp(app AppRoot) {
|
|||
// 加载API
|
||||
if strings.HasPrefix(app.APIs, "fs://") || !strings.Contains(app.APIs, "://") {
|
||||
root := strings.TrimPrefix(app.APIs, "fs://")
|
||||
scripts := getAppFilesFS(root, ".json")
|
||||
scripts := share.GetAppFilesFS(root, ".json")
|
||||
for _, script := range scripts {
|
||||
// 验证API 加载逻辑
|
||||
gou.LoadAPI(string(script.Content), script.Name)
|
||||
|
|
@ -245,7 +217,7 @@ func LoadApp(app AppRoot) {
|
|||
// 加载Flow
|
||||
if strings.HasPrefix(app.Flows, "fs://") || !strings.Contains(app.Flows, "://") {
|
||||
root := strings.TrimPrefix(app.Flows, "fs://")
|
||||
scripts := getAppFilesFS(root, ".json")
|
||||
scripts := share.GetAppFilesFS(root, ".json")
|
||||
for _, script := range scripts {
|
||||
gou.LoadFlow(string(script.Content), script.Name)
|
||||
}
|
||||
|
|
@ -254,7 +226,7 @@ func LoadApp(app AppRoot) {
|
|||
// 加载Model
|
||||
if strings.HasPrefix(app.Models, "fs://") || !strings.Contains(app.Models, "://") {
|
||||
root := strings.TrimPrefix(app.Models, "fs://")
|
||||
scripts := getAppFilesFS(root, ".json")
|
||||
scripts := share.GetAppFilesFS(root, ".json")
|
||||
for _, script := range scripts {
|
||||
gou.LoadModel(string(script.Content), script.Name)
|
||||
}
|
||||
|
|
@ -263,7 +235,7 @@ func LoadApp(app AppRoot) {
|
|||
// 加载Plugin
|
||||
if strings.HasPrefix(app.Plugins, "fs://") || !strings.Contains(app.Plugins, "://") {
|
||||
root := strings.TrimPrefix(app.Plugins, "fs://")
|
||||
scripts := getAppPlugins(root, ".so")
|
||||
scripts := share.GetAppPlugins(root, ".so")
|
||||
for _, script := range scripts {
|
||||
gou.LoadPlugin(script.File, script.Name)
|
||||
}
|
||||
|
|
@ -272,7 +244,7 @@ func LoadApp(app AppRoot) {
|
|||
// 加载Table
|
||||
if strings.HasPrefix(app.Tables, "fs://") || !strings.Contains(app.Tables, "://") {
|
||||
root := strings.TrimPrefix(app.Tables, "fs://")
|
||||
scripts := getAppFilesFS(root, ".json")
|
||||
scripts := share.GetAppFilesFS(root, ".json")
|
||||
for _, script := range scripts {
|
||||
// 验证API 加载逻辑
|
||||
table.Load(string(script.Content), script.Name)
|
||||
|
|
@ -280,175 +252,3 @@ func LoadApp(app AppRoot) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// / getAppPluins 遍历应用目录,读取文件列表
|
||||
func getAppPlugins(root string, typ string) []Script {
|
||||
files := []Script{}
|
||||
root = path.Join(root, "/")
|
||||
filepath.Walk(root, func(file string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(file, typ) {
|
||||
files = append(files, getAppPluginFile(root, file))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return files
|
||||
}
|
||||
|
||||
// getAppPluginFile 读取文件
|
||||
func getAppPluginFile(root string, file string) Script {
|
||||
name := getAppPluginFileName(root, file)
|
||||
return Script{
|
||||
Name: name,
|
||||
Type: "plugin",
|
||||
File: file,
|
||||
}
|
||||
}
|
||||
|
||||
// getAppFile 读取文件
|
||||
func getAppPluginFileName(root string, file string) string {
|
||||
filename := strings.TrimPrefix(file, root+"/")
|
||||
namer := strings.Split(filename, ".")
|
||||
nametypes := strings.Split(namer[0], "/")
|
||||
name := strings.Join(nametypes, ".")
|
||||
return name
|
||||
}
|
||||
|
||||
// getAppFilesFS 遍历应用目录,读取文件列表
|
||||
func getAppFilesFS(root string, typ string) []Script {
|
||||
files := []Script{}
|
||||
root = path.Join(root, "/")
|
||||
filepath.Walk(root, func(filepath string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(filepath, typ) {
|
||||
files = append(files, getAppFile(root, filepath))
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return files
|
||||
}
|
||||
|
||||
// getAppFile 读取文件
|
||||
func getAppFile(root string, filepath string) Script {
|
||||
name := getAppFileName(root, filepath)
|
||||
file, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
}
|
||||
return Script{
|
||||
Name: name,
|
||||
Type: "app",
|
||||
Content: content,
|
||||
}
|
||||
}
|
||||
|
||||
// getAppFile 读取文件
|
||||
func getAppFileName(root string, file string) string {
|
||||
filename := strings.TrimPrefix(file, root+"/")
|
||||
namer := strings.Split(filename, ".")
|
||||
nametypes := strings.Split(namer[0], "/")
|
||||
name := strings.Join(nametypes, ".")
|
||||
return name
|
||||
}
|
||||
|
||||
// getAppFileBaseName 读取文件base
|
||||
func getAppFileBaseName(root string, file string) string {
|
||||
filename := strings.TrimPrefix(file, root+"/")
|
||||
namer := strings.Split(filename, ".")
|
||||
return filepath.Join(root, namer[0])
|
||||
}
|
||||
|
||||
// getFilesFS 遍历目录,读取文件列表
|
||||
func getFilesFS(root string, typ string) []Script {
|
||||
files := []Script{}
|
||||
root = path.Join(root, "/")
|
||||
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(path, typ) {
|
||||
files = append(files, getFile(root, path))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return files
|
||||
}
|
||||
|
||||
// getFile 读取文件
|
||||
func getFile(root string, path string) Script {
|
||||
filename := strings.TrimPrefix(path, root+"/")
|
||||
name, typ := getTypeName(filename)
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
}
|
||||
return Script{
|
||||
Name: name,
|
||||
Type: typ,
|
||||
Content: content,
|
||||
}
|
||||
}
|
||||
|
||||
// getFileName 读取文件
|
||||
func getFileName(root string, file string) string {
|
||||
filename := strings.TrimPrefix(file, root+"/")
|
||||
name, _ := getTypeName(filename)
|
||||
return name
|
||||
}
|
||||
|
||||
// getFileBaseName 读取文件base
|
||||
func getFileBaseName(root string, file string) string {
|
||||
filename := strings.TrimPrefix(file, root+"/")
|
||||
namer := strings.Split(filename, ".")
|
||||
return filepath.Join(root, namer[0])
|
||||
}
|
||||
|
||||
// getFilesBin 从 bindata 中读取文件列表
|
||||
func getFilesBin(root string, typ string) []Script {
|
||||
files := []Script{}
|
||||
binfiles := data.AssetNames()
|
||||
for _, path := range binfiles {
|
||||
if strings.HasSuffix(path, typ) {
|
||||
file := strings.TrimPrefix(path, root+"/")
|
||||
name, typ := getTypeName(file)
|
||||
content, err := data.Asset(path)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
}
|
||||
files = append(files, Script{
|
||||
Name: name,
|
||||
Type: typ,
|
||||
Content: content,
|
||||
})
|
||||
}
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
||||
func getTypeName(path string) (name string, typ string) {
|
||||
namer := strings.Split(path, ".")
|
||||
nametypes := strings.Split(namer[0], "/")
|
||||
name = strings.Join(nametypes[1:], ".")
|
||||
typ = nametypes[0]
|
||||
return name, typ
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package global
|
||||
package entry
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/yaoapp/xiang/config"
|
||||
"github.com/yaoapp/xiang/share"
|
||||
"github.com/yaoapp/xiang/table"
|
||||
)
|
||||
|
||||
|
|
@ -39,7 +40,7 @@ func TestLoadEngineBin(t *testing.T) {
|
|||
func TestLoadAppFS(t *testing.T) {
|
||||
defer Load(config.Conf)
|
||||
assert.NotPanics(t, func() {
|
||||
LoadApp(AppRoot{
|
||||
LoadApp(share.AppRoot{
|
||||
APIs: config.Conf.RootAPI,
|
||||
Flows: config.Conf.RootFLow,
|
||||
Models: config.Conf.RootModel,
|
||||
|
|
@ -1,18 +1,19 @@
|
|||
package global
|
||||
package entry
|
||||
|
||||
import (
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/xiang/config"
|
||||
"github.com/yaoapp/xiang/share"
|
||||
"github.com/yaoapp/xiang/xfs"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 注册处理器
|
||||
gou.RegisterProcessHandler("xiang.global.Ping", processPing)
|
||||
gou.RegisterProcessHandler("xiang.global.FileContent", processFileContent)
|
||||
gou.RegisterProcessHandler("xiang.global.AppFileContent", processAppFileContent)
|
||||
gou.RegisterProcessHandler("xiang.global.Inspect", processInspect)
|
||||
gou.RegisterProcessHandler("xiang.global.Favicon", processFavicon)
|
||||
gou.RegisterProcessHandler("xiang.main.Ping", processPing)
|
||||
gou.RegisterProcessHandler("xiang.main.FileContent", processFileContent)
|
||||
gou.RegisterProcessHandler("xiang.main.AppFileContent", processAppFileContent)
|
||||
gou.RegisterProcessHandler("xiang.main.Inspect", processInspect)
|
||||
gou.RegisterProcessHandler("xiang.main.Favicon", processFavicon)
|
||||
}
|
||||
|
||||
// processCreate 运行模型 MustCreate
|
||||
|
|
@ -22,7 +23,7 @@ func processPing(process *gou.Process) interface{} {
|
|||
"server": "象传应用引擎",
|
||||
"version": share.VERSION,
|
||||
"domain": share.DOMAIN,
|
||||
"allows": Conf.Service.Allow,
|
||||
"allows": config.Conf.Service.Allow,
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
|
@ -53,7 +54,7 @@ func processFileContent(process *gou.Process) interface{} {
|
|||
// processAppFileContent 返回应用文件内容
|
||||
func processAppFileContent(process *gou.Process) interface{} {
|
||||
process.ValidateArgNums(2)
|
||||
fs := xfs.New(Conf.RootData)
|
||||
fs := xfs.New(config.Conf.RootData)
|
||||
filename := process.ArgsString(0)
|
||||
encode := process.ArgsBool(1, true)
|
||||
content := fs.MustReadFile(filename)
|
||||
16
entry/process_test.go
Normal file
16
entry/process_test.go
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package entry
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/xiang/share"
|
||||
)
|
||||
|
||||
func TestProcessPing(t *testing.T) {
|
||||
process := gou.NewProcess("xiang.main.ping")
|
||||
res, ok := processPing(process).(map[string]interface{})
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, res["version"], share.VERSION)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package global
|
||||
package entry
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
|
@ -7,19 +7,11 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/any"
|
||||
"github.com/yaoapp/xiang/share"
|
||||
"github.com/yaoapp/xiang/table"
|
||||
"github.com/yaoapp/xun/capsule"
|
||||
)
|
||||
|
||||
func TestProcessPing(t *testing.T) {
|
||||
process := gou.NewProcess("xiang.global.ping")
|
||||
res, ok := processPing(process).(map[string]interface{})
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, res["version"], share.VERSION)
|
||||
}
|
||||
|
||||
func TestProcessSearch(t *testing.T) {
|
||||
func TestTableProcessSearch(t *testing.T) {
|
||||
|
||||
args := []interface{}{
|
||||
"service",
|
||||
|
|
@ -47,7 +39,7 @@ func TestProcessSearch(t *testing.T) {
|
|||
assert.Equal(t, 2, res.Get("pagesize"))
|
||||
}
|
||||
|
||||
func TestProcessFind(t *testing.T) {
|
||||
func TestTableProcessFind(t *testing.T) {
|
||||
args := []interface{}{
|
||||
"service",
|
||||
1,
|
||||
|
|
@ -60,7 +52,7 @@ func TestProcessFind(t *testing.T) {
|
|||
assert.Equal(t, any.Of(res.Get("id")).CInt(), 1)
|
||||
}
|
||||
|
||||
func TestProcessSave(t *testing.T) {
|
||||
func TestTableProcessSave(t *testing.T) {
|
||||
args := []interface{}{
|
||||
"service",
|
||||
map[string]interface{}{
|
||||
|
|
@ -82,7 +74,7 @@ func TestProcessSave(t *testing.T) {
|
|||
capsule.Query().Table("service").Where("id", id).Delete()
|
||||
}
|
||||
|
||||
func TestProcessDelete(t *testing.T) {
|
||||
func TestTableProcessDelete(t *testing.T) {
|
||||
args := []interface{}{
|
||||
"service",
|
||||
map[string]interface{}{
|
||||
|
|
@ -111,7 +103,7 @@ func TestProcessDelete(t *testing.T) {
|
|||
capsule.Query().Table("service").Where("id", id).Delete()
|
||||
}
|
||||
|
||||
func TestProcessInsert(t *testing.T) {
|
||||
func TestTableProcessInsert(t *testing.T) {
|
||||
args := []interface{}{
|
||||
"service",
|
||||
[]string{"name", "short_name", "kind_id", "manu_id", "price_options"},
|
||||
|
|
@ -128,7 +120,7 @@ func TestProcessInsert(t *testing.T) {
|
|||
capsule.Query().Table("service").Where("name", "like", "I腾讯云主机I%").Delete()
|
||||
}
|
||||
|
||||
func TestProcessDeleteWhere(t *testing.T) {
|
||||
func TestTableProcessDeleteWhere(t *testing.T) {
|
||||
args := []interface{}{
|
||||
"service",
|
||||
map[string]interface{}{
|
||||
|
|
@ -164,7 +156,7 @@ func TestProcessDeleteWhere(t *testing.T) {
|
|||
capsule.Query().Table("service").Where("id", id).Delete()
|
||||
}
|
||||
|
||||
func TestProcessDeleteIn(t *testing.T) {
|
||||
func TestTableProcessDeleteIn(t *testing.T) {
|
||||
args := []interface{}{
|
||||
"service",
|
||||
map[string]interface{}{
|
||||
|
|
@ -197,7 +189,7 @@ func TestProcessDeleteIn(t *testing.T) {
|
|||
capsule.Query().Table("service").Where("id", id).Delete()
|
||||
}
|
||||
|
||||
func TestProcessUpdateWhere(t *testing.T) {
|
||||
func TestTableProcessUpdateWhere(t *testing.T) {
|
||||
args := []interface{}{
|
||||
"service",
|
||||
map[string]interface{}{
|
||||
|
|
@ -236,7 +228,7 @@ func TestProcessUpdateWhere(t *testing.T) {
|
|||
capsule.Query().Table("service").Where("id", id).Delete()
|
||||
}
|
||||
|
||||
func TestProcessUpdateIn(t *testing.T) {
|
||||
func TestTableProcessUpdateIn(t *testing.T) {
|
||||
args := []interface{}{
|
||||
"service",
|
||||
map[string]interface{}{
|
||||
|
|
@ -272,7 +264,7 @@ func TestProcessUpdateIn(t *testing.T) {
|
|||
capsule.Query().Table("service").Where("id", id).Delete()
|
||||
}
|
||||
|
||||
func TestProcessSetting(t *testing.T) {
|
||||
func TestTableProcessSetting(t *testing.T) {
|
||||
args := []interface{}{"service", ""}
|
||||
process := gou.NewProcess("xiang.table.Setting", args...)
|
||||
response := table.ProcessSetting(process)
|
||||
|
|
@ -288,7 +280,7 @@ func TestProcessSetting(t *testing.T) {
|
|||
assert.True(t, res.Has("view"))
|
||||
assert.True(t, res.Has("insert"))
|
||||
}
|
||||
func TestProcessSettingList(t *testing.T) {
|
||||
func TestTableProcessSettingList(t *testing.T) {
|
||||
args := []interface{}{"service", "list"}
|
||||
process := gou.NewProcess("xiang.table.Setting", args...)
|
||||
response := table.ProcessSetting(process)
|
||||
|
|
@ -299,7 +291,7 @@ func TestProcessSettingList(t *testing.T) {
|
|||
assert.True(t, res.Has("primary"))
|
||||
}
|
||||
|
||||
func TestProcessSettingListEdit(t *testing.T) {
|
||||
func TestTableProcessSettingListEdit(t *testing.T) {
|
||||
args := []interface{}{"service", "list, edit"}
|
||||
process := gou.NewProcess("xiang.table.Setting", args...)
|
||||
response := table.ProcessSetting(process)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package global
|
||||
package entry
|
||||
|
||||
import (
|
||||
"testing"
|
||||
23
entry/watch_test.go
Normal file
23
entry/watch_test.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package entry
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/yaoapp/xiang/config"
|
||||
"github.com/yaoapp/xiang/share"
|
||||
)
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
root := path.Join(config.Conf.Source, "/app/flows")
|
||||
assert.NotPanics(t, func() {
|
||||
go share.Watch(root, func(op string, file string) {
|
||||
log.Println(op, file)
|
||||
})
|
||||
time.Sleep(time.Second * 2)
|
||||
defer share.StopWatch()
|
||||
})
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package global
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
root := path.Join(Conf.Source, "/app/flows")
|
||||
assert.NotPanics(t, func() {
|
||||
go Watch(root, func(op string, file string) {
|
||||
log.Println(op, file)
|
||||
})
|
||||
time.Sleep(time.Second * 2)
|
||||
defer StopWatch()
|
||||
})
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ import (
|
|||
"github.com/yaoapp/kun/maps"
|
||||
"github.com/yaoapp/kun/utils"
|
||||
"github.com/yaoapp/xiang/config"
|
||||
"github.com/yaoapp/xiang/global"
|
||||
"github.com/yaoapp/xiang/service"
|
||||
)
|
||||
|
||||
func TestCommandVersion(t *testing.T) {
|
||||
|
|
@ -42,7 +42,7 @@ func TestCommandStart(t *testing.T) {
|
|||
oldArgs := os.Args
|
||||
defer func() {
|
||||
os.Args = oldArgs
|
||||
global.ServiceStop(func() {})
|
||||
service.Stop(func() {})
|
||||
log.Println("服务已关闭")
|
||||
}()
|
||||
go func() {
|
||||
|
|
@ -126,7 +126,7 @@ func TestCommandStop(t *testing.T) {
|
|||
assert.Equal(t, "管理员", res.Get("name"))
|
||||
|
||||
// 测试关闭
|
||||
global.ServiceStop(func() { log.Println("服务已关闭") })
|
||||
service.Stop(func() { log.Println("服务已关闭") })
|
||||
time.Sleep(time.Second * 2)
|
||||
_, err = request()
|
||||
assert.NotNil(t, err)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package global
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yaoapp/xiang/config"
|
||||
"github.com/yaoapp/xiang/user"
|
||||
"github.com/yaoapp/xiang/xlog"
|
||||
)
|
||||
|
|
@ -25,11 +26,11 @@ func bearerJWT(c *gin.Context) {
|
|||
}
|
||||
|
||||
tokenString = strings.TrimSpace(strings.TrimPrefix(tokenString, "Bearer "))
|
||||
if Conf.Mode == "debug" {
|
||||
xlog.Printf("JWT: %s Secret: %s", tokenString, Conf.JWT.Secret)
|
||||
if config.Conf.Mode == "debug" {
|
||||
xlog.Printf("JWT: %s Secret: %s", tokenString, config.Conf.JWT.Secret)
|
||||
}
|
||||
token, err := jwt.ParseWithClaims(tokenString, &user.JwtClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(Conf.JWT.Secret), nil
|
||||
return []byte(config.Conf.JWT.Secret), nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package global
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package global
|
||||
package service
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
|
@ -6,20 +6,22 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/xiang/config"
|
||||
"github.com/yaoapp/xiang/share"
|
||||
"github.com/yaoapp/xiang/table"
|
||||
)
|
||||
|
||||
var shutdown = make(chan bool)
|
||||
var shutdownComplete = make(chan bool)
|
||||
|
||||
// ServiceStart 启动服务
|
||||
func ServiceStart() {
|
||||
// Start 启动服务
|
||||
func Start() {
|
||||
gou.SetHTTPGuards(Guards)
|
||||
gou.ServeHTTP(
|
||||
gou.Server{
|
||||
Host: Conf.Service.Host,
|
||||
Port: Conf.Service.Port,
|
||||
Allows: Conf.Service.Allow,
|
||||
Host: config.Conf.Service.Host,
|
||||
Port: config.Conf.Service.Port,
|
||||
Allows: config.Conf.Service.Allow,
|
||||
Root: "/api",
|
||||
},
|
||||
&shutdown, func(s gou.Server) {
|
||||
|
|
@ -28,8 +30,8 @@ func ServiceStart() {
|
|||
Middlewares...)
|
||||
}
|
||||
|
||||
// ServiceStop 关闭服务
|
||||
func ServiceStop(onComplete func()) {
|
||||
// Stop 关闭服务
|
||||
func Stop(onComplete func()) {
|
||||
shutdown <- true
|
||||
<-shutdownComplete
|
||||
onComplete()
|
||||
|
|
@ -37,15 +39,15 @@ func ServiceStop(onComplete func()) {
|
|||
|
||||
// WatchChanges 监听配置文件变更
|
||||
func WatchChanges() {
|
||||
watchEngine(Conf.Path)
|
||||
watchApp(AppRoot{
|
||||
APIs: Conf.RootAPI,
|
||||
Flows: Conf.RootFLow,
|
||||
Models: Conf.RootModel,
|
||||
Plugins: Conf.RootPlugin,
|
||||
Tables: Conf.RootTable,
|
||||
Charts: Conf.RootChart,
|
||||
Screens: Conf.RootScreen,
|
||||
watchEngine(config.Conf.Path)
|
||||
watchApp(share.AppRoot{
|
||||
APIs: config.Conf.RootAPI,
|
||||
Flows: config.Conf.RootFLow,
|
||||
Models: config.Conf.RootModel,
|
||||
Plugins: config.Conf.RootPlugin,
|
||||
Tables: config.Conf.RootTable,
|
||||
Charts: config.Conf.RootChart,
|
||||
Screens: config.Conf.RootScreen,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -61,23 +63,23 @@ func watchEngine(from string) {
|
|||
}
|
||||
|
||||
// 监听 flows (这里应该重构)
|
||||
go Watch(filepath.Join(rootAbs, "flows"), func(op string, file string) {
|
||||
go share.Watch(filepath.Join(rootAbs, "flows"), func(op string, file string) {
|
||||
|
||||
if !strings.HasSuffix(file, ".json") {
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasSuffix(file, ".js") {
|
||||
basName := getFileBaseName(root, file)
|
||||
basName := share.GetFileBaseName(root, file)
|
||||
file = basName + ".flow.json"
|
||||
}
|
||||
|
||||
if op == "write" || op == "create" {
|
||||
script := getFile(root, file)
|
||||
script := share.GetFile(root, file)
|
||||
gou.LoadFlow(string(script.Content), "xiang."+script.Name) // Reload
|
||||
log.Printf("Flow %s 已重新加载完毕", "xiang."+script.Name)
|
||||
} else if op == "remove" || op == "rename" {
|
||||
name := "xiang." + getFileName(root, file)
|
||||
name := "xiang." + share.GetFileName(root, file)
|
||||
if _, has := gou.Flows[name]; has {
|
||||
delete(gou.Flows, name)
|
||||
log.Printf("Flow %s 已经移除", name)
|
||||
|
|
@ -86,17 +88,17 @@ func watchEngine(from string) {
|
|||
})
|
||||
|
||||
// 监听 models
|
||||
go Watch(filepath.Join(rootAbs, "models"), func(op string, file string) {
|
||||
go share.Watch(filepath.Join(rootAbs, "models"), func(op string, file string) {
|
||||
|
||||
if !strings.HasSuffix(file, ".json") {
|
||||
return
|
||||
}
|
||||
if op == "write" || op == "create" {
|
||||
script := getFile(root, file)
|
||||
script := share.GetFile(root, file)
|
||||
gou.LoadModel(string(script.Content), "xiang."+script.Name) // Reload
|
||||
log.Printf("Model %s 已重新加载完毕", "xiang."+script.Name)
|
||||
} else if op == "remove" || op == "rename" {
|
||||
name := "xiang." + getFileName(root, file)
|
||||
name := "xiang." + share.GetFileName(root, file)
|
||||
if _, has := gou.Models[name]; has {
|
||||
delete(gou.Models, name)
|
||||
log.Printf("Model %s 已经移除", name)
|
||||
|
|
@ -105,13 +107,13 @@ func watchEngine(from string) {
|
|||
})
|
||||
|
||||
// 监听 apis
|
||||
go Watch(filepath.Join(rootAbs, "apis"), func(op string, file string) {
|
||||
go share.Watch(filepath.Join(rootAbs, "apis"), func(op string, file string) {
|
||||
|
||||
if !strings.HasSuffix(file, ".json") {
|
||||
return
|
||||
}
|
||||
if op == "write" || op == "create" {
|
||||
script := getFile(root, file)
|
||||
script := share.GetFile(root, file)
|
||||
gou.LoadAPI(string(script.Content), "xiang."+script.Name) // Reload
|
||||
log.Printf("API %s 已重新加载完毕", "xiang."+script.Name)
|
||||
|
||||
|
|
@ -123,7 +125,7 @@ func watchEngine(from string) {
|
|||
}
|
||||
|
||||
} else if op == "remove" || op == "rename" {
|
||||
name := "xiang." + getFileName(root, file)
|
||||
name := "xiang." + share.GetFileName(root, file)
|
||||
if _, has := gou.APIs[name]; has {
|
||||
delete(gou.APIs, name)
|
||||
log.Printf("API %s 已经移除", name)
|
||||
|
|
@ -132,21 +134,21 @@ func watchEngine(from string) {
|
|||
|
||||
// 重启服务器
|
||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
||||
ServiceStop(func() {
|
||||
Stop(func() {
|
||||
log.Printf("服务器重启完毕")
|
||||
go ServiceStart()
|
||||
go Start()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 监听 tables
|
||||
go Watch(filepath.Join(rootAbs, "tables"), func(op string, file string) {
|
||||
go share.Watch(filepath.Join(rootAbs, "tables"), func(op string, file string) {
|
||||
|
||||
if !strings.HasSuffix(file, ".json") {
|
||||
return
|
||||
}
|
||||
if op == "write" || op == "create" {
|
||||
script := getFile(root, file)
|
||||
script := share.GetFile(root, file)
|
||||
table.Load(string(script.Content), "xiang."+script.Name) // Reload
|
||||
api, has := gou.APIs["xiang.table"]
|
||||
if has {
|
||||
|
|
@ -156,7 +158,7 @@ func watchEngine(from string) {
|
|||
log.Printf("数据表格 %s 已重新加载完毕", "xiang."+script.Name)
|
||||
|
||||
} else if op == "remove" || op == "rename" {
|
||||
name := "xiang." + getFileName(root, file)
|
||||
name := "xiang." + share.GetFileName(root, file)
|
||||
if _, has := table.Tables[name]; has {
|
||||
delete(table.Tables, name)
|
||||
log.Printf("数据表格 %s 已经移除", name)
|
||||
|
|
@ -165,16 +167,16 @@ func watchEngine(from string) {
|
|||
|
||||
// 重启服务器
|
||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
||||
ServiceStop(func() {
|
||||
Stop(func() {
|
||||
log.Printf("服务器重启完毕")
|
||||
go ServiceStart()
|
||||
go Start()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// watchApp 监听应用目录文件变更
|
||||
func watchApp(app AppRoot) {
|
||||
func watchApp(app share.AppRoot) {
|
||||
watchAppAPI(app.APIs)
|
||||
watchAppFlow(app.Flows)
|
||||
watchAppModel(app.Models)
|
||||
|
|
@ -193,13 +195,13 @@ func watchAppTable(rootTable string) {
|
|||
log.Panicf("路径错误 %s %s", root, err)
|
||||
}
|
||||
|
||||
go Watch(rootAbs, func(op string, file string) {
|
||||
go share.Watch(rootAbs, func(op string, file string) {
|
||||
if !strings.HasSuffix(file, ".json") {
|
||||
return
|
||||
}
|
||||
|
||||
if op == "write" || op == "create" {
|
||||
script := getAppFile(root, file)
|
||||
script := share.GetAppFile(root, file)
|
||||
table.Load(string(script.Content), script.Name) // Reload
|
||||
api, has := gou.APIs["xiang.table"]
|
||||
if has {
|
||||
|
|
@ -209,7 +211,7 @@ func watchAppTable(rootTable string) {
|
|||
log.Printf("数据表格 %s 已重新加载完毕", script.Name)
|
||||
|
||||
} else if op == "remove" || op == "rename" {
|
||||
name := getAppFileName(root, file)
|
||||
name := share.GetAppFileName(root, file)
|
||||
if _, has := gou.APIs[name]; has {
|
||||
delete(table.Tables, name)
|
||||
log.Printf("数据表格 %s 已经移除", name)
|
||||
|
|
@ -218,9 +220,9 @@ func watchAppTable(rootTable string) {
|
|||
|
||||
// 重启服务器
|
||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
||||
ServiceStop(func() {
|
||||
Stop(func() {
|
||||
log.Printf("服务器重启完毕")
|
||||
go ServiceStart()
|
||||
go Start()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
@ -237,18 +239,18 @@ func watchAppAPI(api string) {
|
|||
log.Panicf("路径错误 %s %s", root, err)
|
||||
}
|
||||
|
||||
go Watch(rootAbs, func(op string, file string) {
|
||||
go share.Watch(rootAbs, func(op string, file string) {
|
||||
if !strings.HasSuffix(file, ".json") {
|
||||
return
|
||||
}
|
||||
|
||||
if op == "write" || op == "create" {
|
||||
script := getAppFile(root, file)
|
||||
script := share.GetAppFile(root, file)
|
||||
gou.LoadAPI(string(script.Content), script.Name) // Reload
|
||||
log.Printf("API %s 已重新加载完毕", script.Name)
|
||||
|
||||
} else if op == "remove" || op == "rename" {
|
||||
name := getAppFileName(root, file)
|
||||
name := share.GetAppFileName(root, file)
|
||||
if _, has := gou.APIs[name]; has {
|
||||
delete(gou.APIs, name)
|
||||
log.Printf("API %s 已经移除", name)
|
||||
|
|
@ -257,9 +259,9 @@ func watchAppAPI(api string) {
|
|||
|
||||
// 重启服务器
|
||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
||||
ServiceStop(func() {
|
||||
Stop(func() {
|
||||
log.Printf("服务器重启完毕")
|
||||
go ServiceStart()
|
||||
go Start()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
@ -275,20 +277,20 @@ func watchAppFlow(flow string) {
|
|||
if err != nil {
|
||||
log.Panicf("路径错误 %s %s", root, err)
|
||||
}
|
||||
go Watch(rootAbs, func(op string, file string) {
|
||||
go share.Watch(rootAbs, func(op string, file string) {
|
||||
if !strings.HasSuffix(file, ".json") && !strings.HasSuffix(file, ".js") {
|
||||
return
|
||||
}
|
||||
if strings.HasSuffix(file, ".js") {
|
||||
basName := getAppFileBaseName(root, file)
|
||||
basName := share.GetAppFileBaseName(root, file)
|
||||
file = basName + ".flow.json"
|
||||
}
|
||||
if op == "write" || op == "create" {
|
||||
script := getAppFile(root, file)
|
||||
script := share.GetAppFile(root, file)
|
||||
gou.LoadFlow(string(script.Content), script.Name) // Reload
|
||||
log.Printf("Flow %s 已重新加载完毕", script.Name)
|
||||
} else if op == "remove" || op == "rename" {
|
||||
name := getAppFileName(root, file)
|
||||
name := share.GetAppFileName(root, file)
|
||||
if _, has := gou.Flows[name]; has {
|
||||
delete(gou.Flows, name)
|
||||
log.Printf("Flow %s 已经移除", name)
|
||||
|
|
@ -308,16 +310,16 @@ func watchAppModel(model string) {
|
|||
if err != nil {
|
||||
log.Panicf("路径错误 %s %s", root, err)
|
||||
}
|
||||
go Watch(rootAbs, func(op string, file string) {
|
||||
go share.Watch(rootAbs, func(op string, file string) {
|
||||
if !strings.HasSuffix(file, ".json") {
|
||||
return
|
||||
}
|
||||
if op == "write" || op == "create" {
|
||||
script := getAppFile(root, file)
|
||||
script := share.GetAppFile(root, file)
|
||||
gou.LoadModel(string(script.Content), script.Name) // Reload
|
||||
log.Printf("Model %s 已重新加载完毕", script.Name)
|
||||
} else if op == "remove" || op == "rename" {
|
||||
name := getAppFileName(root, file)
|
||||
name := share.GetAppFileName(root, file)
|
||||
if _, has := gou.Models[name]; has {
|
||||
delete(gou.Models, name)
|
||||
log.Printf("Model %s 已经移除", name)
|
||||
|
|
@ -336,17 +338,17 @@ func watchAppPlugin(plugin string) {
|
|||
if err != nil {
|
||||
log.Panicf("路径错误 %s %s", root, err)
|
||||
}
|
||||
go Watch(rootAbs, func(op string, file string) {
|
||||
go share.Watch(rootAbs, func(op string, file string) {
|
||||
if !strings.HasSuffix(file, ".so") {
|
||||
return
|
||||
}
|
||||
|
||||
if op == "write" || op == "create" {
|
||||
script := getAppPluginFile(root, file)
|
||||
script := share.GetAppPluginFile(root, file)
|
||||
gou.LoadPlugin(script.File, script.Name) // Reload
|
||||
log.Printf("Plugin %s 已重新加载完毕", script.Name)
|
||||
} else if op == "remove" || op == "rename" {
|
||||
name := getAppPluginFileName(root, file)
|
||||
name := share.GetAppPluginFileName(root, file)
|
||||
if _, has := gou.Plugins[name]; has {
|
||||
delete(gou.Plugins, name)
|
||||
log.Printf("Plugin %s 已经移除", name)
|
||||
133
share/api.go
Normal file
133
share/api.go
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
package share
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/any"
|
||||
"github.com/yaoapp/kun/exception"
|
||||
"github.com/yaoapp/kun/utils"
|
||||
)
|
||||
|
||||
// IsAllow 鉴权处理程序
|
||||
func (api API) IsAllow(v interface{}) bool {
|
||||
c, ok := v.(*gin.Context)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
guards := strings.Split(api.Guard, ",")
|
||||
for _, guard := range guards {
|
||||
guard = strings.TrimSpace(guard)
|
||||
handler, has := gou.HTTPGuards[guard]
|
||||
if has {
|
||||
handler(c)
|
||||
fmt.Println(api.Guard, c.IsAborted())
|
||||
return c.IsAborted()
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ValidateLoop 循环引用校验
|
||||
func (api API) ValidateLoop(name string) API {
|
||||
if strings.ToLower(api.Process) == strings.ToLower(name) {
|
||||
exception.New("循环引用 %s", 400, name).Throw()
|
||||
}
|
||||
return api
|
||||
}
|
||||
|
||||
// ProcessIs 检查处理器名称
|
||||
func (api API) ProcessIs(name string) bool {
|
||||
return strings.ToLower(api.Process) == strings.ToLower(name)
|
||||
}
|
||||
|
||||
// DefaultQueryParams 读取参数 QueryParam
|
||||
func (api API) DefaultQueryParams(i int, defaults ...gou.QueryParam) gou.QueryParam {
|
||||
param := gou.QueryParam{}
|
||||
if len(defaults) > 0 {
|
||||
param = defaults[0]
|
||||
}
|
||||
|
||||
if api.Default[i] == nil || len(api.Default) <= i {
|
||||
return param
|
||||
}
|
||||
|
||||
param, ok := api.Default[i].(gou.QueryParam)
|
||||
if !ok {
|
||||
param, ok = gou.AnyToQueryParam(api.Default[i])
|
||||
}
|
||||
|
||||
return param
|
||||
}
|
||||
|
||||
// DefaultInt 读取参数 Int
|
||||
func (api API) DefaultInt(i int, defaults ...int) int {
|
||||
value := 0
|
||||
ok := false
|
||||
if len(defaults) > 0 {
|
||||
value = defaults[0]
|
||||
}
|
||||
|
||||
if api.Default[i] == nil || len(api.Default) <= i {
|
||||
return value
|
||||
}
|
||||
|
||||
value, ok = api.Default[i].(int)
|
||||
if !ok {
|
||||
value = any.Of(api.Default[i]).CInt()
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// DefaultString 读取参数 String
|
||||
func (api API) DefaultString(i int, defaults ...string) string {
|
||||
value := ""
|
||||
ok := false
|
||||
if len(defaults) > 0 {
|
||||
value = defaults[0]
|
||||
}
|
||||
|
||||
if api.Default[i] == nil || len(api.Default) <= i {
|
||||
return value
|
||||
}
|
||||
|
||||
value, ok = api.Default[i].(string)
|
||||
if !ok {
|
||||
value = any.Of(api.Default[i]).CString()
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// MergeDefaultQueryParam 合并默认查询参数
|
||||
func (api API) MergeDefaultQueryParam(param gou.QueryParam, i int) gou.QueryParam {
|
||||
if len(api.Default) > i && api.Default[i] != nil {
|
||||
defaults, ok := gou.AnyToQueryParam(api.Default[i])
|
||||
if !ok {
|
||||
exception.New("参数默认值数据结构错误", 400).Ctx(api.Default[i]).Throw()
|
||||
}
|
||||
if defaults.Withs != nil {
|
||||
param.Withs = defaults.Withs
|
||||
}
|
||||
|
||||
if defaults.Select != nil {
|
||||
param.Select = defaults.Select
|
||||
utils.Dump(param.Select)
|
||||
}
|
||||
|
||||
if defaults.Wheres != nil {
|
||||
if param.Wheres == nil {
|
||||
param.Wheres = []gou.QueryWhere{}
|
||||
}
|
||||
param.Wheres = append(param.Wheres, defaults.Wheres...)
|
||||
}
|
||||
|
||||
if defaults.Orders != nil {
|
||||
param.Orders = append(param.Orders, defaults.Orders...)
|
||||
}
|
||||
}
|
||||
return param
|
||||
}
|
||||
205
share/app.go
205
share/app.go
|
|
@ -1,6 +1,16 @@
|
|||
package share
|
||||
|
||||
import "github.com/yaoapp/kun/maps"
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/yaoapp/kun/exception"
|
||||
"github.com/yaoapp/kun/maps"
|
||||
"github.com/yaoapp/xiang/data"
|
||||
)
|
||||
|
||||
// App 应用信息
|
||||
var App AppInfo
|
||||
|
|
@ -34,6 +44,26 @@ type AppStorageOSS struct {
|
|||
SessionName string `json:"sessionName,omitempty"`
|
||||
}
|
||||
|
||||
// Script 脚本文件类型
|
||||
type Script struct {
|
||||
Name string
|
||||
Type string
|
||||
Content []byte
|
||||
File string
|
||||
}
|
||||
|
||||
// AppRoot 应用目录
|
||||
type AppRoot struct {
|
||||
APIs string
|
||||
Flows string
|
||||
Models string
|
||||
Plugins string
|
||||
Tables string
|
||||
Charts string
|
||||
Screens string
|
||||
Data string
|
||||
}
|
||||
|
||||
// Public 输出公共信息
|
||||
func (app AppInfo) Public() AppInfo {
|
||||
app.Storage.COS = nil
|
||||
|
|
@ -41,3 +71,176 @@ func (app AppInfo) Public() AppInfo {
|
|||
app.Storage.S3 = nil
|
||||
return app
|
||||
}
|
||||
|
||||
// GetAppPlugins 遍历应用目录,读取文件列表
|
||||
func GetAppPlugins(root string, typ string) []Script {
|
||||
files := []Script{}
|
||||
root = path.Join(root, "/")
|
||||
filepath.Walk(root, func(file string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(file, typ) {
|
||||
files = append(files, GetAppPluginFile(root, file))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return files
|
||||
}
|
||||
|
||||
// GetAppPluginFile 读取文件
|
||||
func GetAppPluginFile(root string, file string) Script {
|
||||
name := GetAppPluginFileName(root, file)
|
||||
return Script{
|
||||
Name: name,
|
||||
Type: "plugin",
|
||||
File: file,
|
||||
}
|
||||
}
|
||||
|
||||
// GetAppPluginFileName 读取文件
|
||||
func GetAppPluginFileName(root string, file string) string {
|
||||
filename := strings.TrimPrefix(file, root+"/")
|
||||
namer := strings.Split(filename, ".")
|
||||
nametypes := strings.Split(namer[0], "/")
|
||||
name := strings.Join(nametypes, ".")
|
||||
return name
|
||||
}
|
||||
|
||||
// GetAppFilesFS 遍历应用目录,读取文件列表
|
||||
func GetAppFilesFS(root string, typ string) []Script {
|
||||
files := []Script{}
|
||||
root = path.Join(root, "/")
|
||||
filepath.Walk(root, func(filepath string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(filepath, typ) {
|
||||
files = append(files, GetAppFile(root, filepath))
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return files
|
||||
}
|
||||
|
||||
// GetAppFile 读取文件
|
||||
func GetAppFile(root string, filepath string) Script {
|
||||
name := GetAppFileName(root, filepath)
|
||||
file, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
}
|
||||
return Script{
|
||||
Name: name,
|
||||
Type: "app",
|
||||
Content: content,
|
||||
}
|
||||
}
|
||||
|
||||
// GetAppFileName 读取文件
|
||||
func GetAppFileName(root string, file string) string {
|
||||
filename := strings.TrimPrefix(file, root+"/")
|
||||
namer := strings.Split(filename, ".")
|
||||
nametypes := strings.Split(namer[0], "/")
|
||||
name := strings.Join(nametypes, ".")
|
||||
return name
|
||||
}
|
||||
|
||||
// GetAppFileBaseName 读取文件base
|
||||
func GetAppFileBaseName(root string, file string) string {
|
||||
filename := strings.TrimPrefix(file, root+"/")
|
||||
namer := strings.Split(filename, ".")
|
||||
return filepath.Join(root, namer[0])
|
||||
}
|
||||
|
||||
// GetFilesFS 遍历目录,读取文件列表
|
||||
func GetFilesFS(root string, typ string) []Script {
|
||||
files := []Script{}
|
||||
root = path.Join(root, "/")
|
||||
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(path, typ) {
|
||||
files = append(files, GetFile(root, path))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return files
|
||||
}
|
||||
|
||||
// GetFile 读取文件
|
||||
func GetFile(root string, path string) Script {
|
||||
filename := strings.TrimPrefix(path, root+"/")
|
||||
name, typ := GetTypeName(filename)
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
}
|
||||
return Script{
|
||||
Name: name,
|
||||
Type: typ,
|
||||
Content: content,
|
||||
}
|
||||
}
|
||||
|
||||
// GetFileName 读取文件
|
||||
func GetFileName(root string, file string) string {
|
||||
filename := strings.TrimPrefix(file, root+"/")
|
||||
name, _ := GetTypeName(filename)
|
||||
return name
|
||||
}
|
||||
|
||||
// GetFileBaseName 读取文件base
|
||||
func GetFileBaseName(root string, file string) string {
|
||||
filename := strings.TrimPrefix(file, root+"/")
|
||||
namer := strings.Split(filename, ".")
|
||||
return filepath.Join(root, namer[0])
|
||||
}
|
||||
|
||||
// GetFilesBin 从 bindata 中读取文件列表
|
||||
func GetFilesBin(root string, typ string) []Script {
|
||||
files := []Script{}
|
||||
binfiles := data.AssetNames()
|
||||
for _, path := range binfiles {
|
||||
if strings.HasSuffix(path, typ) {
|
||||
file := strings.TrimPrefix(path, root+"/")
|
||||
name, typ := GetTypeName(file)
|
||||
content, err := data.Asset(path)
|
||||
if err != nil {
|
||||
exception.Err(err, 500).Throw()
|
||||
}
|
||||
files = append(files, Script{
|
||||
Name: name,
|
||||
Type: typ,
|
||||
Content: content,
|
||||
})
|
||||
}
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
||||
// GetTypeName 读取类型
|
||||
func GetTypeName(path string) (name string, typ string) {
|
||||
namer := strings.Split(path, ".")
|
||||
nametypes := strings.Split(namer[0], "/")
|
||||
name = strings.Join(nametypes[1:], ".")
|
||||
typ = nametypes[0]
|
||||
return name, typ
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package table
|
||||
package share
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -52,20 +52,8 @@ var elms = map[string]Column{
|
|||
"year": {View: Render{Type: "label"}, Edit: Render{Type: "datetime"}},
|
||||
}
|
||||
|
||||
// loadColumns 加载字段呈现方式
|
||||
func (table *Table) loadColumns() {
|
||||
if table.Bind.Model == "" {
|
||||
return
|
||||
}
|
||||
defaults := getDefaultColumns(table.Bind.Model)
|
||||
for name, column := range table.Columns {
|
||||
defaults[name] = column
|
||||
}
|
||||
table.Columns = defaults
|
||||
}
|
||||
|
||||
// getDefaultColumns 读取数据模型字段的呈现方式
|
||||
func getDefaultColumns(name string) map[string]Column {
|
||||
// GetDefaultColumns 读取数据模型字段的呈现方式
|
||||
func GetDefaultColumns(name string) map[string]Column {
|
||||
mod := gou.Select(name)
|
||||
cmap := mod.Columns
|
||||
columns := map[string]Column{}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package table
|
||||
package share
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -6,20 +6,8 @@ import (
|
|||
"github.com/yaoapp/gou"
|
||||
)
|
||||
|
||||
// loadFilters 加载查询过滤器
|
||||
func (table *Table) loadFilters() {
|
||||
if table.Bind.Model == "" {
|
||||
return
|
||||
}
|
||||
defaults := getDefaultFilters(table.Bind.Model)
|
||||
for name, filter := range table.Filters {
|
||||
defaults[name] = filter
|
||||
}
|
||||
table.Filters = defaults
|
||||
}
|
||||
|
||||
// getDefaultFilters 读取数据模型索引字段的过滤器
|
||||
func getDefaultFilters(name string) map[string]Filter {
|
||||
// GetDefaultFilters 读取数据模型索引字段的过滤器
|
||||
func GetDefaultFilters(name string) map[string]Filter {
|
||||
|
||||
mod := gou.Select(name)
|
||||
cmap := mod.Columns
|
||||
40
share/types.go
Normal file
40
share/types.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package share
|
||||
|
||||
// API API 配置数据结构
|
||||
type API struct {
|
||||
Name string `json:"-"`
|
||||
Source string `json:"-"`
|
||||
Process string `json:"process,omitempty"`
|
||||
Guard string `json:"guard,omitempty"`
|
||||
Default []interface{} `json:"default,omitempty"`
|
||||
}
|
||||
|
||||
// Column 字段呈现方式
|
||||
type Column struct {
|
||||
Label string `json:"label"`
|
||||
View Render `json:"view,omitempty"`
|
||||
Edit Render `json:"edit,omitempty"`
|
||||
Form Render `json:"form,omitempty"`
|
||||
}
|
||||
|
||||
// Filter 查询过滤器
|
||||
type Filter struct {
|
||||
Label string `json:"label"`
|
||||
Bind string `json:"bind,omitempty"`
|
||||
Input Render `json:"input,omitempty"`
|
||||
}
|
||||
|
||||
// Page 页面
|
||||
type Page struct {
|
||||
Primary string `json:"primary"`
|
||||
Layout map[string]interface{} `json:"layout"`
|
||||
Actions map[string]Render `json:"actions,omitempty"`
|
||||
Option map[string]interface{} `json:"option,omitempty"`
|
||||
}
|
||||
|
||||
// Render 组件渲染方式
|
||||
type Render struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Props map[string]interface{} `json:"props,omitempty"`
|
||||
Components map[string]interface{} `json:"components,omitempty"`
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import (
|
|||
)
|
||||
|
||||
// VERSION 版本号
|
||||
const VERSION = "0.8.7"
|
||||
const VERSION = "0.8.8"
|
||||
|
||||
// DOMAIN 许可域
|
||||
const DOMAIN = "*.iqka.com"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package global
|
||||
package share
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
199
table/api.go
199
table/api.go
|
|
@ -2,69 +2,13 @@ package table
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/any"
|
||||
"github.com/yaoapp/kun/exception"
|
||||
"github.com/yaoapp/kun/utils"
|
||||
"github.com/yaoapp/xiang/share"
|
||||
)
|
||||
|
||||
// loadAPIs 加载数据管理 API
|
||||
func (table *Table) loadAPIs() {
|
||||
if table.Bind.Model == "" {
|
||||
return
|
||||
}
|
||||
defaults := getDefaultAPIs(table.Bind)
|
||||
defaults["setting"] = apiDefaultSetting(table)
|
||||
|
||||
for name := range table.APIs {
|
||||
if _, has := defaults[name]; !has {
|
||||
delete(table.APIs, name)
|
||||
continue
|
||||
}
|
||||
|
||||
api := defaults[name]
|
||||
api.Name = name
|
||||
if table.APIs[name].Process != "" {
|
||||
api.Process = table.APIs[name].Process
|
||||
}
|
||||
|
||||
if table.APIs[name].Guard != "" {
|
||||
api.Guard = table.APIs[name].Guard
|
||||
}
|
||||
|
||||
if table.APIs[name].Default != nil {
|
||||
api.Default = table.APIs[name].Default
|
||||
}
|
||||
defaults[name] = api
|
||||
}
|
||||
|
||||
table.APIs = defaults
|
||||
}
|
||||
|
||||
// getDefaultAPIs 读取数据模型绑定的APIs
|
||||
func getDefaultAPIs(bind Bind) map[string]API {
|
||||
name := bind.Model
|
||||
model := gou.Select(name)
|
||||
apis := map[string]API{
|
||||
"search": apiSearchDefault(model, bind.Withs),
|
||||
"find": apiFindDefault(model, bind.Withs),
|
||||
"save": apiDefault(model, "save", "Save"),
|
||||
"delete": apiDefault(model, "delete", "Delete"),
|
||||
"insert": apiDefault(model, "insert", "Insert"),
|
||||
"delete-in": apiDefault(model, "delete-in", "DeleteWhere"),
|
||||
"delete-where": apiDefaultWhere(model, bind.Withs, "delete-where", "DeleteWhere"),
|
||||
"update-in": apiDefault(model, "update-in", "UpdateWhere"),
|
||||
"update-where": apiDefaultWhere(model, bind.Withs, "update-where", "UpdateWhere"),
|
||||
}
|
||||
|
||||
return apis
|
||||
}
|
||||
|
||||
// apiSearchDefault search 接口默认值
|
||||
func apiSearchDefault(model *gou.Model, withs map[string]gou.With) API {
|
||||
func apiSearchDefault(model *gou.Model, withs map[string]gou.With) share.API {
|
||||
query := gou.QueryParam{}
|
||||
if model.MetaData.Option.Timestamps {
|
||||
query.Orders = []gou.QueryOrder{
|
||||
|
|
@ -76,7 +20,7 @@ func apiSearchDefault(model *gou.Model, withs map[string]gou.With) API {
|
|||
query.Withs = withs
|
||||
}
|
||||
|
||||
return API{
|
||||
return share.API{
|
||||
Name: "search",
|
||||
Guard: "bearer-jwt",
|
||||
Process: fmt.Sprintf("models.%s.Paginate", model.Name),
|
||||
|
|
@ -85,14 +29,14 @@ func apiSearchDefault(model *gou.Model, withs map[string]gou.With) API {
|
|||
}
|
||||
|
||||
// apiFindDefault find 接口默认值
|
||||
func apiFindDefault(model *gou.Model, withs map[string]gou.With) API {
|
||||
func apiFindDefault(model *gou.Model, withs map[string]gou.With) share.API {
|
||||
|
||||
query := gou.QueryParam{}
|
||||
if withs != nil {
|
||||
query.Withs = withs
|
||||
}
|
||||
|
||||
return API{
|
||||
return share.API{
|
||||
Name: "find",
|
||||
Guard: "bearer-jwt",
|
||||
Process: fmt.Sprintf("models.%s.Find", model.Name),
|
||||
|
|
@ -101,8 +45,8 @@ func apiFindDefault(model *gou.Model, withs map[string]gou.With) API {
|
|||
}
|
||||
|
||||
// apiFindDefault 接口默认值
|
||||
func apiDefault(model *gou.Model, name string, process string) API {
|
||||
return API{
|
||||
func apiDefault(model *gou.Model, name string, process string) share.API {
|
||||
return share.API{
|
||||
Name: name,
|
||||
Guard: "bearer-jwt",
|
||||
Process: fmt.Sprintf("models.%s.%s", model.Name, process),
|
||||
|
|
@ -110,14 +54,14 @@ func apiDefault(model *gou.Model, name string, process string) API {
|
|||
}
|
||||
|
||||
// apiFindDefault 接口默认值
|
||||
func apiDefaultWhere(model *gou.Model, withs map[string]gou.With, name string, process string) API {
|
||||
func apiDefaultWhere(model *gou.Model, withs map[string]gou.With, name string, process string) share.API {
|
||||
|
||||
query := gou.QueryParam{}
|
||||
if withs != nil {
|
||||
query.Withs = withs
|
||||
}
|
||||
|
||||
return API{
|
||||
return share.API{
|
||||
Name: name,
|
||||
Guard: "bearer-jwt",
|
||||
Process: fmt.Sprintf("models.%s.%s", model.Name, process),
|
||||
|
|
@ -126,131 +70,10 @@ func apiDefaultWhere(model *gou.Model, withs map[string]gou.With, name string, p
|
|||
}
|
||||
|
||||
// apiDefaultSetting 数据表格配置默认值
|
||||
func apiDefaultSetting(table *Table) API {
|
||||
return API{
|
||||
func apiDefaultSetting(table *Table) share.API {
|
||||
return share.API{
|
||||
Name: "setting",
|
||||
Guard: "bearer-jwt",
|
||||
Process: fmt.Sprintf("xiang.table.setting"),
|
||||
}
|
||||
}
|
||||
|
||||
// IsAllow 鉴权处理程序
|
||||
func (api API) IsAllow(v interface{}) bool {
|
||||
c, ok := v.(*gin.Context)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
guards := strings.Split(api.Guard, ",")
|
||||
for _, guard := range guards {
|
||||
guard = strings.TrimSpace(guard)
|
||||
handler, has := gou.HTTPGuards[guard]
|
||||
if has {
|
||||
handler(c)
|
||||
fmt.Println(api.Guard, c.IsAborted())
|
||||
return c.IsAborted()
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ValidateLoop 循环引用校验
|
||||
func (api API) ValidateLoop(name string) API {
|
||||
if strings.ToLower(api.Process) == strings.ToLower(name) {
|
||||
exception.New("循环引用 %s", 400, name).Throw()
|
||||
}
|
||||
return api
|
||||
}
|
||||
|
||||
// ProcessIs 检查处理器名称
|
||||
func (api API) ProcessIs(name string) bool {
|
||||
return strings.ToLower(api.Process) == strings.ToLower(name)
|
||||
}
|
||||
|
||||
// DefaultQueryParams 读取参数 QueryParam
|
||||
func (api API) DefaultQueryParams(i int, defaults ...gou.QueryParam) gou.QueryParam {
|
||||
param := gou.QueryParam{}
|
||||
if len(defaults) > 0 {
|
||||
param = defaults[0]
|
||||
}
|
||||
|
||||
if api.Default[i] == nil || len(api.Default) <= i {
|
||||
return param
|
||||
}
|
||||
|
||||
param, ok := api.Default[i].(gou.QueryParam)
|
||||
if !ok {
|
||||
param, ok = gou.AnyToQueryParam(api.Default[i])
|
||||
}
|
||||
|
||||
return param
|
||||
}
|
||||
|
||||
// DefaultInt 读取参数 Int
|
||||
func (api API) DefaultInt(i int, defaults ...int) int {
|
||||
value := 0
|
||||
ok := false
|
||||
if len(defaults) > 0 {
|
||||
value = defaults[0]
|
||||
}
|
||||
|
||||
if api.Default[i] == nil || len(api.Default) <= i {
|
||||
return value
|
||||
}
|
||||
|
||||
value, ok = api.Default[i].(int)
|
||||
if !ok {
|
||||
value = any.Of(api.Default[i]).CInt()
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// DefaultString 读取参数 String
|
||||
func (api API) DefaultString(i int, defaults ...string) string {
|
||||
value := ""
|
||||
ok := false
|
||||
if len(defaults) > 0 {
|
||||
value = defaults[0]
|
||||
}
|
||||
|
||||
if api.Default[i] == nil || len(api.Default) <= i {
|
||||
return value
|
||||
}
|
||||
|
||||
value, ok = api.Default[i].(string)
|
||||
if !ok {
|
||||
value = any.Of(api.Default[i]).CString()
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// MergeDefaultQueryParam 合并默认查询参数
|
||||
func (api API) MergeDefaultQueryParam(param gou.QueryParam, i int) gou.QueryParam {
|
||||
if len(api.Default) > i && api.Default[i] != nil {
|
||||
defaults, ok := gou.AnyToQueryParam(api.Default[i])
|
||||
if !ok {
|
||||
exception.New("参数默认值数据结构错误", 400).Ctx(api.Default[i]).Throw()
|
||||
}
|
||||
if defaults.Withs != nil {
|
||||
param.Withs = defaults.Withs
|
||||
}
|
||||
|
||||
if defaults.Select != nil {
|
||||
param.Select = defaults.Select
|
||||
utils.Dump(param.Select)
|
||||
}
|
||||
|
||||
if defaults.Wheres != nil {
|
||||
if param.Wheres == nil {
|
||||
param.Wheres = []gou.QueryWhere{}
|
||||
}
|
||||
param.Wheres = append(param.Wheres, defaults.Wheres...)
|
||||
}
|
||||
|
||||
if defaults.Orders != nil {
|
||||
param.Orders = append(param.Orders, defaults.Orders...)
|
||||
}
|
||||
}
|
||||
return param
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/gou/helper"
|
||||
"github.com/yaoapp/kun/exception"
|
||||
"github.com/yaoapp/xiang/share"
|
||||
)
|
||||
|
||||
// Tables 已载入模型
|
||||
|
|
@ -58,7 +60,83 @@ func Select(name string) *Table {
|
|||
}
|
||||
|
||||
// Reload 更新数据表格配置
|
||||
func (tab *Table) Reload() *Table {
|
||||
tab = Load(tab.Source, tab.Name)
|
||||
return tab
|
||||
func (table *Table) Reload() *Table {
|
||||
*table = *Load(table.Source, table.Name)
|
||||
return table
|
||||
}
|
||||
|
||||
// loadAPIs 加载数据管理 API
|
||||
func (table *Table) loadAPIs() {
|
||||
if table.Bind.Model == "" {
|
||||
return
|
||||
}
|
||||
defaults := getDefaultAPIs(table.Bind)
|
||||
defaults["setting"] = apiDefaultSetting(table)
|
||||
|
||||
for name := range table.APIs {
|
||||
if _, has := defaults[name]; !has {
|
||||
delete(table.APIs, name)
|
||||
continue
|
||||
}
|
||||
|
||||
api := defaults[name]
|
||||
api.Name = name
|
||||
if table.APIs[name].Process != "" {
|
||||
api.Process = table.APIs[name].Process
|
||||
}
|
||||
|
||||
if table.APIs[name].Guard != "" {
|
||||
api.Guard = table.APIs[name].Guard
|
||||
}
|
||||
|
||||
if table.APIs[name].Default != nil {
|
||||
api.Default = table.APIs[name].Default
|
||||
}
|
||||
defaults[name] = api
|
||||
}
|
||||
|
||||
table.APIs = defaults
|
||||
}
|
||||
|
||||
// getDefaultAPIs 读取数据模型绑定的APIs
|
||||
func getDefaultAPIs(bind Bind) map[string]share.API {
|
||||
name := bind.Model
|
||||
model := gou.Select(name)
|
||||
apis := map[string]share.API{
|
||||
"search": apiSearchDefault(model, bind.Withs),
|
||||
"find": apiFindDefault(model, bind.Withs),
|
||||
"save": apiDefault(model, "save", "Save"),
|
||||
"delete": apiDefault(model, "delete", "Delete"),
|
||||
"insert": apiDefault(model, "insert", "Insert"),
|
||||
"delete-in": apiDefault(model, "delete-in", "DeleteWhere"),
|
||||
"delete-where": apiDefaultWhere(model, bind.Withs, "delete-where", "DeleteWhere"),
|
||||
"update-in": apiDefault(model, "update-in", "UpdateWhere"),
|
||||
"update-where": apiDefaultWhere(model, bind.Withs, "update-where", "UpdateWhere"),
|
||||
}
|
||||
|
||||
return apis
|
||||
}
|
||||
|
||||
// loadFilters 加载查询过滤器
|
||||
func (table *Table) loadFilters() {
|
||||
if table.Bind.Model == "" {
|
||||
return
|
||||
}
|
||||
defaults := share.GetDefaultFilters(table.Bind.Model)
|
||||
for name, filter := range table.Filters {
|
||||
defaults[name] = filter
|
||||
}
|
||||
table.Filters = defaults
|
||||
}
|
||||
|
||||
// loadColumns 加载字段呈现方式
|
||||
func (table *Table) loadColumns() {
|
||||
if table.Bind.Model == "" {
|
||||
return
|
||||
}
|
||||
defaults := share.GetDefaultColumns(table.Bind.Model)
|
||||
for name, column := range table.Columns {
|
||||
defaults[name] = column
|
||||
}
|
||||
table.Columns = defaults
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,26 @@
|
|||
package table
|
||||
|
||||
import "github.com/yaoapp/gou"
|
||||
import (
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/xiang/share"
|
||||
)
|
||||
|
||||
// Table 数据表格配置结构
|
||||
type Table struct {
|
||||
Table string `json:"-"`
|
||||
Source string `json:"-"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Decription string `json:"decription,omitempty"`
|
||||
Bind Bind `json:"bind,omitempty"`
|
||||
APIs map[string]API `json:"apis,omitempty"`
|
||||
Columns map[string]Column `json:"columns,omitempty"`
|
||||
Filters map[string]Filter `json:"filters,omitempty"`
|
||||
List Page `json:"list,omitempty"`
|
||||
Edit Page `json:"edit,omitempty"`
|
||||
View Page `json:"view,omitempty"`
|
||||
Insert Page `json:"insert,omitempty"`
|
||||
Table string `json:"-"`
|
||||
Source string `json:"-"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Decription string `json:"decription,omitempty"`
|
||||
Bind Bind `json:"bind,omitempty"`
|
||||
APIs map[string]share.API `json:"apis,omitempty"`
|
||||
Columns map[string]share.Column `json:"columns,omitempty"`
|
||||
Filters map[string]share.Filter `json:"filters,omitempty"`
|
||||
List share.Page `json:"list,omitempty"`
|
||||
Edit share.Page `json:"edit,omitempty"`
|
||||
View share.Page `json:"view,omitempty"`
|
||||
Insert share.Page `json:"insert,omitempty"`
|
||||
}
|
||||
|
||||
// Bind 绑定数据模型
|
||||
|
|
@ -25,42 +28,3 @@ type Bind struct {
|
|||
Model string `json:"model"`
|
||||
Withs map[string]gou.With `json:"withs,omitempty"`
|
||||
}
|
||||
|
||||
// API API 配置数据结构
|
||||
type API struct {
|
||||
Name string `json:"-"`
|
||||
Source string `json:"-"`
|
||||
Process string `json:"process,omitempty"`
|
||||
Guard string `json:"guard,omitempty"`
|
||||
Default []interface{} `json:"default,omitempty"`
|
||||
}
|
||||
|
||||
// Column 字段呈现方式
|
||||
type Column struct {
|
||||
Label string `json:"label"`
|
||||
View Render `json:"view,omitempty"`
|
||||
Edit Render `json:"edit,omitempty"`
|
||||
Form Render `json:"form,omitempty"`
|
||||
}
|
||||
|
||||
// Filter 查询过滤器
|
||||
type Filter struct {
|
||||
Label string `json:"label"`
|
||||
Bind string `json:"bind,omitempty"`
|
||||
Input Render `json:"input,omitempty"`
|
||||
}
|
||||
|
||||
// Page 页面
|
||||
type Page struct {
|
||||
Primary string `json:"primary"`
|
||||
Layout map[string]interface{} `json:"layout"`
|
||||
Actions map[string]Render `json:"actions,omitempty"`
|
||||
Option map[string]interface{} `json:"option,omitempty"`
|
||||
}
|
||||
|
||||
// Render 组件渲染方式
|
||||
type Render struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Props map[string]interface{} `json:"props,omitempty"`
|
||||
Components map[string]interface{} `json:"components,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
"path": "/ping",
|
||||
"method": "GET",
|
||||
"guard": "-",
|
||||
"process": "xiang.global.Ping",
|
||||
"process": "xiang.main.Ping",
|
||||
"in": [],
|
||||
"out": {
|
||||
"status": 200,
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
"path": "/inspect",
|
||||
"method": "GET",
|
||||
"guard": "-",
|
||||
"process": "xiang.global.inspect",
|
||||
"process": "xiang.main.inspect",
|
||||
"in": [],
|
||||
"out": {
|
||||
"status": 200,
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
"path": "/favicon.ico",
|
||||
"method": "GET",
|
||||
"guard": "-",
|
||||
"process": "xiang.global.Favicon",
|
||||
"process": "xiang.main.Favicon",
|
||||
"in": [],
|
||||
"out": {
|
||||
"status": 200,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue