From 0d8ff4073a9ad25c437d7d5a1421c9d37ede5f28 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 3 Dec 2022 19:12:51 +0800 Subject: [PATCH] [add] widget.apis process --- widgets/action.go | 1 + widgets/api.go | 231 ++++++++++++++++++++++++++++++++++++++++ widgets/item.go | 89 ++++++++++++++++ widgets/process.go | 32 ++++++ widgets/process_test.go | 27 +++++ widgets/widgets_test.go | 7 ++ 6 files changed, 387 insertions(+) create mode 100644 widgets/action.go create mode 100644 widgets/api.go create mode 100644 widgets/item.go create mode 100644 widgets/process.go create mode 100644 widgets/process_test.go diff --git a/widgets/action.go b/widgets/action.go new file mode 100644 index 00000000..dbe9a3e9 --- /dev/null +++ b/widgets/action.go @@ -0,0 +1 @@ +package widgets diff --git a/widgets/api.go b/widgets/api.go new file mode 100644 index 00000000..1562c4cf --- /dev/null +++ b/widgets/api.go @@ -0,0 +1,231 @@ +package widgets + +import ( + "fmt" + "os" + "strings" + + "github.com/yaoapp/gou" + "github.com/yaoapp/yao/widgets/chart" + "github.com/yaoapp/yao/widgets/form" + "github.com/yaoapp/yao/widgets/list" + "github.com/yaoapp/yao/widgets/table" +) + +// Apis return loaded apis +func Apis() []Item { + apis := map[string]interface{}{} + userApis(apis) + tableApis(apis) + formApis(apis) + listApis(apis) + chartApis(apis) + + grouping := Grouping(apis) + items := Array(grouping, []Item{}) + Sort(items, []string{"apis", "tables", "forms", "lists", "charts"}) + return items +} + +func userApis(apis map[string]interface{}) { + + // Name string `json:"name"` + // Version string `json:"version"` + // Description string `json:"description,omitempty"` + // Group string `json:"group,omitempty"` + // Guard string `json:"guard,omitempty"` + // Paths []Path `json:"paths,omitempty"` + for group, api := range gou.APIs { + if strings.HasPrefix(group, "widgets") { + continue + } + + // Label string `json:"label,omitempty"` + // Description string `json:"description,omitempty"` + // Path string `json:"path"` + // Method string `json:"method"` + // Process string `json:"process"` + // Guard string `json:"guard,omitempty"` + // In []string `json:"in,omitempty"` + // Out Out `json:"out,omitempty"` + paths := []map[string]interface{}{} + for _, path := range api.HTTP.Paths { + guard := path.Guard + if guard == "" { + guard = api.HTTP.Guard + } + fullpath := fmt.Sprintf("/apis/%s%s", api.HTTP.Group, path.Path) + paths = append(paths, map[string]interface{}{ + "name": path.Label, + "description": path.Description, + "guard": guard, + "method": path.Method, + "path": path.Path, + "router": fullpath, + "fullpath": fullpath, + "in": path.In, + "out": path.Out, + "process": path.Process, + "params": map[string]interface{}{}, + }) + } + + dsl := fmt.Sprintf("apis%s%s.http.json", string(os.PathSeparator), strings.ReplaceAll(group, ".", string(os.PathSeparator))) + apis[dsl] = map[string]interface{}{ + "DSL": dsl, + "name": api.HTTP.Name, + "version": api.HTTP.Version, + "group": fmt.Sprintf("/%s", api.HTTP.Group), + "guard": api.HTTP.Guard, + "description": api.HTTP.Description, + "paths": paths, + } + } +} + +func tableApis(apis map[string]interface{}) { + + api, has := gou.APIs["widgets.table"] + if !has { + return + } + + for id, widget := range table.Tables { + dsl := fmt.Sprintf("tables%s%s.tab.json", string(os.PathSeparator), strings.ReplaceAll(id, ".", string(os.PathSeparator))) + groupGuard := "bearer-jwt" + pathGuards := []map[string]string{ + {"name": "/:id/search", "guard": widget.Action.Search.Guard}, + {"name": "/:id/get", "guard": widget.Action.Get.Guard}, + {"name": "/:id/find/:primary", "guard": widget.Action.Find.Guard}, + {"name": "/:id/save", "guard": widget.Action.Save.Guard}, + {"name": "/:id/create", "guard": widget.Action.Create.Guard}, + {"name": "/:id/insert", "guard": widget.Action.Insert.Guard}, + {"name": "/:id/update/:primary", "guard": widget.Action.Update.Guard}, + {"name": "/:id/update/in", "guard": widget.Action.UpdateIn.Guard}, + {"name": "/:id/update/where", "guard": widget.Action.UpdateWhere.Guard}, + {"name": "/:id/delete/:primary", "guard": widget.Action.Delete.Guard}, + {"name": "/:id/delete/in", "guard": widget.Action.DeleteIn.Guard}, + {"name": "/:id/delete/where", "guard": widget.Action.DeleteWhere.Guard}, + {"name": "/:id/upload/:xpath/:method", "guard": widget.Action.Upload.Guard}, + {"name": "/:id/download/:field", "guard": widget.Action.Download.Guard}, + } + widgetApis(apis, api, id, dsl, groupGuard, pathGuards) + } +} + +func formApis(apis map[string]interface{}) { + + api, has := gou.APIs["widgets.form"] + if !has { + return + } + + for id, widget := range form.Forms { + dsl := fmt.Sprintf("forms%s%s.form.json", string(os.PathSeparator), strings.ReplaceAll(id, ".", string(os.PathSeparator))) + groupGuard := "bearer-jwt" + pathGuards := []map[string]string{ + {"name": "/:id/find/:primary", "guard": widget.Action.Find.Guard}, + {"name": "/:id/save", "guard": widget.Action.Save.Guard}, + {"name": "/:id/create", "guard": widget.Action.Create.Guard}, + {"name": "/:id/update/:primary", "guard": widget.Action.Update.Guard}, + {"name": "/:id/delete/:primary", "guard": widget.Action.Delete.Guard}, + {"name": "/:id/upload/:xpath/:method", "guard": widget.Action.Upload.Guard}, + {"name": "/:id/download/:field", "guard": widget.Action.Download.Guard}, + } + widgetApis(apis, api, id, dsl, groupGuard, pathGuards) + } +} + +func listApis(apis map[string]interface{}) { + + api, has := gou.APIs["widgets.list"] + if !has { + return + } + + for id, widget := range list.Lists { + dsl := fmt.Sprintf("lists%s%s.list.json", string(os.PathSeparator), strings.ReplaceAll(id, ".", string(os.PathSeparator))) + groupGuard := "bearer-jwt" + pathGuards := []map[string]string{ + {"name": "/:id/get", "guard": widget.Action.Get.Guard}, + {"name": "/:id/save", "guard": widget.Action.Save.Guard}, + {"name": "/:id/upload/:xpath/:method", "guard": widget.Action.Upload.Guard}, + {"name": "/:id/download/:field", "guard": widget.Action.Download.Guard}, + } + widgetApis(apis, api, id, dsl, groupGuard, pathGuards) + } +} + +func chartApis(apis map[string]interface{}) { + + api, has := gou.APIs["widgets.chart"] + if !has { + return + } + + for id, widget := range chart.Charts { + dsl := fmt.Sprintf("charts%s%s.chart.json", string(os.PathSeparator), strings.ReplaceAll(id, ".", string(os.PathSeparator))) + groupGuard := "bearer-jwt" + pathGuards := []map[string]string{ + {"name": "/:id/data", "guard": widget.Action.Data.Guard}, + } + widgetApis(apis, api, id, dsl, groupGuard, pathGuards) + } +} + +func widgetApis(apis map[string]interface{}, api *gou.API, widgetID string, dsl string, groupGuard string, pathGuards []map[string]string) { + + pathMapping := map[string]gou.Path{} + for _, path := range api.HTTP.Paths { + pathMapping[path.Path] = path + } + + // Label string `json:"label,omitempty"` + // Description string `json:"description,omitempty"` + // Path string `json:"path"` + // Method string `json:"method"` + // Process string `json:"process"` + // Guard string `json:"guard,omitempty"` + // In []string `json:"in,omitempty"` + // Out Out `json:"out,omitempty"` + paths := []map[string]interface{}{} + for _, pathGuard := range pathGuards { + + name := pathGuard["name"] + guard := pathGuard["guard"] + + path, has := pathMapping[name] + if !has { + continue + } + + if guard == "" { + guard = groupGuard + } + + fullpath := fmt.Sprintf("/apis/%s%s", api.HTTP.Group, path.Path) + paths = append(paths, map[string]interface{}{ + "name": path.Label, + "description": path.Description, + "guard": guard, + "method": path.Method, + "path": path.Path, + "fullpath": fullpath, + "router": strings.ReplaceAll(fullpath, ":id", widgetID), + "in": path.In, + "out": path.Out, + "process": path.Process, + "params": map[string]interface{}{"id": widgetID}, + }) + } + + apis[dsl] = map[string]interface{}{ + "DSL": dsl, + "name": api.HTTP.Name, + "version": api.HTTP.Version, + "group": fmt.Sprintf("/%s", api.HTTP.Group), + "guard": groupGuard, + "description": api.HTTP.Description, + "paths": paths, + } +} diff --git a/widgets/item.go b/widgets/item.go new file mode 100644 index 00000000..8e4d8143 --- /dev/null +++ b/widgets/item.go @@ -0,0 +1,89 @@ +package widgets + +import ( + "os" + "sort" + "strings" +) + +// Item the item +type Item struct { + Name string `json:"name,omitempty"` + Data interface{} `json:"data,omitempty"` + Children []Item `json:"children,omitempty"` +} + +// Sort items +func Sort(items []Item, orders []string) { + + rank := map[string]int{} + if orders != nil { + for i, name := range orders { + rank[name] = i + } + } + + sort.Slice(items, func(i, j int) bool { + rankI, hasI := rank[items[i].Name] + rankJ, hasJ := rank[items[j].Name] + if hasI && hasJ { + return rankI < rankJ + } + return strings.Compare(items[i].Name, items[j].Name) < 0 + }) + + // Sort Children + for i := range items { + if len(items[i].Children) > 0 { + Sort(items[i].Children, nil) + } + } + +} + +// Grouping by name +func Grouping(items map[string]interface{}) map[string]interface{} { + grouping := map[string]interface{}{} + for name, item := range items { + paths := strings.Split(name, string(os.PathSeparator)) + node := grouping + for _, path := range paths { + if strings.HasSuffix(path, ".json") { + node[path] = Item{Name: path, Data: item, Children: []Item{}} + continue + } + if _, has := node[path]; !has { + node[path] = map[string]interface{}{"name": path, "data": map[string]interface{}{}} + } + node = node[path].(map[string]interface{}) + } + } + return grouping +} + +// Array to Array +func Array(groupingItems map[string]interface{}, res []Item) []Item { + + for key, item := range groupingItems { + + switch it := item.(type) { + + case map[string]interface{}: // Path + if it["name"] == nil { + break + } + res = append(res, Item{ + Name: key, + Data: nil, + Children: Array(it, []Item{}), + }) + break + + case Item: // Data + res = append(res, it) + break + } + } + + return res +} diff --git a/widgets/process.go b/widgets/process.go new file mode 100644 index 00000000..2c49d81f --- /dev/null +++ b/widgets/process.go @@ -0,0 +1,32 @@ +package widgets + +import ( + "github.com/yaoapp/gou" +) + +// WidgetHandlers Processes +var WidgetHandlers = map[string]gou.ProcessHandler{ + "apis": processApis, +} + +func init() { + gou.RegisterProcessGroup("widget", WidgetHandlers) +} + +// Get the loaded APIs +func processApis(process *gou.Process) interface{} { + return Apis() +} + +// Get the actions of each widget +func processActions() { +} + +// Get the loaded Models +func processModels() {} + +// Get the loaded flows +func processFlows() {} + +// Get the loaded Models +func processScripts() {} diff --git a/widgets/process_test.go b/widgets/process_test.go new file mode 100644 index 00000000..ff80a03b --- /dev/null +++ b/widgets/process_test.go @@ -0,0 +1,27 @@ +package widgets + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/yaoapp/gou" + "github.com/yaoapp/yao/config" +) + +func TestProcessApis(t *testing.T) { + testData(t) + args := []interface{}{} + res, err := gou.NewProcess("widget.apis", args...).Exec() + if err != nil { + t.Fatal(err) + } + assert.Greater(t, len(res.([]Item)), 0) +} + +func testData(t *testing.T) { + prepare(t) + err := Load(config.Conf) + if err != nil { + t.Fatal(err) + } +} diff --git a/widgets/widgets_test.go b/widgets/widgets_test.go index 7cf5b1f2..71e17d6c 100644 --- a/widgets/widgets_test.go +++ b/widgets/widgets_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/yaoapp/yao/api" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/i18n" "github.com/yaoapp/yao/model" @@ -42,4 +43,10 @@ func prepare(t *testing.T, language ...string) { t.Fatal(err) } + // load apis + err = api.Load(config.Conf) + if err != nil { + t.Fatal(err) + } + }