From 6d2cdaaf1b8f76af88fea8d4a8137537a719f6cc Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 19 Jan 2022 22:29:21 +0800 Subject: [PATCH] =?UTF-8?q?v0.9.33=20=E4=BF=AE=E5=A4=8D=E8=A1=A8=E6=A0=BC?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E6=95=B0=E6=8D=AEBUG=20&=20=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flow/flow_test.go | 2 +- share/api.go | 5 + share/const.go | 2 +- table/api.go | 2 +- table/process.go | 24 ++- table/table.go | 10 +- table/table_test.go | 2 +- tests/app.json | 6 +- tests/flows/hooks/session.flow.json | 17 ++ tests/tables/service.json | 1 - tests/tables/session.json | 305 ++++++++++++++++++++++++++++ user/user.go | 45 ++-- xiang/apis/table.http.json | 2 +- 13 files changed, 373 insertions(+), 50 deletions(-) create mode 100644 tests/flows/hooks/session.flow.json create mode 100644 tests/tables/session.json diff --git a/flow/flow_test.go b/flow/flow_test.go index 7af92b2aaa..fefe612826 100644 --- a/flow/flow_test.go +++ b/flow/flow_test.go @@ -20,5 +20,5 @@ func check(t *testing.T) { for key := range gou.Flows { keys = append(keys, key) } - assert.Equal(t, 18, len(keys)) + assert.Equal(t, 19, len(keys)) } diff --git a/share/api.go b/share/api.go index b578d2b8d5..eba2c91313 100644 --- a/share/api.go +++ b/share/api.go @@ -118,15 +118,20 @@ func (api API) MergeDefaultQueryParam(param gou.QueryParam, i int, sid string) g // GetQueryParam 解析参数 func GetQueryParam(v interface{}, sid string) gou.QueryParam { + fmt.Println("\n==== GetQueryParam ===== SID:", sid) data := map[string]interface{}{} if sid != "" { var err error ss := session.Global().ID(sid) data, err = ss.Dump() + utils.Dump(data) if err != nil { xlog.Printf("读取会话信息出错 %s", err.Error()) } } + fmt.Println("==== GetQueryParam========================") + fmt.Println("") + v = share.Bind(v, maps.Of(data).Dot()) param, ok := gou.AnyToQueryParam(v) if !ok { diff --git a/share/const.go b/share/const.go index 603cc27ef1..5bf5cb72c3 100644 --- a/share/const.go +++ b/share/const.go @@ -1,7 +1,7 @@ package share // VERSION 版本号 -const VERSION = "0.9.32" +const VERSION = "0.9.33" // DOMAIN 许可域(废弃) const DOMAIN = "*.iqka.com" diff --git a/table/api.go b/table/api.go index 68fce173bf..b69d828f96 100644 --- a/table/api.go +++ b/table/api.go @@ -70,7 +70,7 @@ func apiDefaultWhere(model *gou.Model, withs map[string]gou.With, name string, p } // apiDefaultSetting 数据表格配置默认值 -func apiDefaultSetting(table *Table) share.API { +func apiDefaultSetting() share.API { return share.API{ Name: "setting", Guard: "bearer-jwt", diff --git a/table/process.go b/table/process.go index 98cb2e0c96..aa3ec1b46c 100644 --- a/table/process.go +++ b/table/process.go @@ -1,11 +1,13 @@ package table import ( + "fmt" "strings" "github.com/yaoapp/gou" "github.com/yaoapp/kun/any" "github.com/yaoapp/kun/maps" + "github.com/yaoapp/kun/utils" ) func init() { @@ -39,11 +41,17 @@ func ProcessSearch(process *gou.Process) interface{} { } // Before Hook - process.Args = table.Before(table.Hooks.BeforeSearch, process.Args) + process.Args = table.Before(table.Hooks.BeforeSearch, process.Args, process.Sid) // 参数表 process.ValidateArgNums(4) param := api.MergeDefaultQueryParam(process.ArgsQueryParams(1), 0, process.Sid) + + fmt.Println("\n==== ProcessSearch ============= SID:", process.Sid) + utils.Dump(param) + fmt.Println("==== END ProcessSearch ===============================================") + fmt.Println("") + page := process.ArgsInt(2, api.DefaultInt(1)) pagesize := process.ArgsInt(3, api.DefaultInt(2)) @@ -51,7 +59,7 @@ func ProcessSearch(process *gou.Process) interface{} { response := gou.NewProcess(api.Process, param, page, pagesize).Run() // After Hook - return table.After(table.Hooks.AfterSearch, response) + return table.After(table.Hooks.AfterSearch, response, process.Sid) } // ProcessFind xiang.table.Find @@ -67,7 +75,7 @@ func ProcessFind(process *gou.Process) interface{} { } // Before Hook - process.Args = table.Before(table.Hooks.BeforeFind, process.Args) + process.Args = table.Before(table.Hooks.BeforeFind, process.Args, process.Sid) // 参数表 process.ValidateArgNums(2) @@ -78,7 +86,7 @@ func ProcessFind(process *gou.Process) interface{} { response := gou.NewProcess(api.Process, id, param).Run() // After Hook - return table.After(table.Hooks.AfterFind, response) + return table.After(table.Hooks.AfterFind, response, process.Sid) } // ProcessSave xiang.table.Save @@ -95,7 +103,7 @@ func ProcessSave(process *gou.Process) interface{} { } // Before Hook - process.Args = table.Before(table.Hooks.BeforeSave, process.Args) + process.Args = table.Before(table.Hooks.BeforeSave, process.Args, process.Sid) // 参数处理 process.ValidateArgNums(2) @@ -104,7 +112,7 @@ func ProcessSave(process *gou.Process) interface{} { response := gou.NewProcess(api.Process, process.Args[1]).Run() // After Hook - return table.After(table.Hooks.AfterSave, response) + return table.After(table.Hooks.AfterSave, response, process.Sid) } // ProcessDelete xiang.table.Delete @@ -315,10 +323,10 @@ func ProcessSelect(process *gou.Process) interface{} { } // Before Hook - process.Args = table.Before(table.Hooks.BeforeSelect, process.Args) + process.Args = table.Before(table.Hooks.BeforeSelect, process.Args, process.Sid) response := gou.NewProcess(api.Process, process.Args[1:]...).Run() // After Hook - return table.After(table.Hooks.AfterSelect, response) + return table.After(table.Hooks.AfterSelect, response, process.Sid) } diff --git a/table/table.go b/table/table.go index 1b7883aa1a..34541ab78e 100644 --- a/table/table.go +++ b/table/table.go @@ -93,7 +93,7 @@ func (table *Table) loadAPIs() { return } defaults := getDefaultAPIs(table.Bind) - defaults["setting"] = apiDefaultSetting(table) + defaults["setting"] = apiDefaultSetting() for name := range table.APIs { if _, has := defaults[name]; !has { @@ -150,7 +150,7 @@ func getDefaultAPIs(bind Bind) map[string]share.API { } // Before 运行 Before hook -func (table *Table) Before(process string, processArgs []interface{}) []interface{} { +func (table *Table) Before(process string, processArgs []interface{}, sid string) []interface{} { if process == "" { return processArgs } @@ -161,7 +161,7 @@ func (table *Table) Before(process string, processArgs []interface{}) []interfac res = append(res, processArgs[0]) } - response, err := gou.NewProcess(process, args...).Exec() + response, err := gou.NewProcess(process, args...).WithSID(sid).Exec() if err != nil { xlog.Println("Hook执行失败: ", err.Error(), maps.StrAny{"process": process, "args": args}) return processArgs @@ -177,11 +177,11 @@ func (table *Table) Before(process string, processArgs []interface{}) []interfac } // After 运行 After hook -func (table *Table) After(process string, data interface{}) interface{} { +func (table *Table) After(process string, data interface{}, sid string) interface{} { if process == "" { return data } - response, err := gou.NewProcess(process, data).Exec() + response, err := gou.NewProcess(process, data).WithSID(sid).Exec() if err != nil { xlog.Println("Hook执行失败: ", err.Error(), maps.StrAny{"process": process, "data": data}) return data diff --git a/table/table_test.go b/table/table_test.go index 62e3ff6603..e56e8060fe 100644 --- a/table/table_test.go +++ b/table/table_test.go @@ -48,5 +48,5 @@ func check(t *testing.T) { for key := range Tables { keys = append(keys, key) } - assert.Equal(t, 8, len(keys)) + assert.Equal(t, 9, len(keys)) } diff --git a/tests/app.json b/tests/app.json index 8006cebc69..3f642d30d1 100644 --- a/tests/app.json +++ b/tests/app.json @@ -2,6 +2,9 @@ "name": "象传应用", "short": "象传", "description": "象传应用后台", + "option": { + "index": "/table/service" + }, "storage": { "default": "oss", "oss": { @@ -14,6 +17,5 @@ }, "cos": {}, "s3": {} - }, - "option": {} + } } diff --git a/tests/flows/hooks/session.flow.json b/tests/flows/hooks/session.flow.json new file mode 100644 index 0000000000..c2e219e39d --- /dev/null +++ b/tests/flows/hooks/session.flow.json @@ -0,0 +1,17 @@ +{ + "label": "会话测试", + "version": "1.0.0", + "description": "Before:Select", + "nodes": [ + { + "name": "会话数据", + "process": "session.Dump" + }, + { + "name": "打印数据", + "process": "xiang.helper.Print", + "args": ["会话数据:", "{{$res.会话数据}}"] + } + ], + "output": "{{$in}}" +} diff --git a/tests/tables/service.json b/tests/tables/service.json index 9f3d96116a..871bc4958e 100644 --- a/tests/tables/service.json +++ b/tests/tables/service.json @@ -22,7 +22,6 @@ "select": { "guard": "-" }, "search": { "process": "models.service.Paginate", - "guard": "-", "default": [null, null, 15] }, "find": { diff --git a/tests/tables/session.json b/tests/tables/session.json new file mode 100644 index 0000000000..77cbfb9169 --- /dev/null +++ b/tests/tables/session.json @@ -0,0 +1,305 @@ +{ + "name": "会话调试", + "version": "1.0.0", + "decription": "会话调试", + "bind": { + "model": "service", + "withs": { + "manu": { + "query": { + "select": ["id", "name", "short_name", "status"] + } + }, + "kind": { + "query": { + "select": ["id", "name"] + } + } + } + }, + "hooks": { + "before:search": "flows.hooks.session", + "after:search": "flows.hooks.session" + }, + "apis": { + "search": { + "default": [ + { + "wheres": [{ "column": "status", "value": "{{user_id}}" }], + "withs": { "manu": {}, "kind": {} } + }, + null, + 10 + ] + } + }, + "columns": { + "服务名称": { + "label": "服务名称", + "view": { + "type": "label", + "props": { + "value": ":name" + } + }, + "edit": { + "type": "input", + "props": { + "value": ":name" + } + } + }, + "所属厂商": { + "label": "所属厂商", + "view": { + "name": "label", + "props": { + "value": ":manu.short_name" + } + }, + "edit": { + "type": "select", + "props": { + "value": ":manu.id", + "searchable": true, + "remote": { + "api": "/api/manu/get", + "query": { + "select": ["id", "name"], + "keyword": "where_name_like" + } + } + } + } + }, + "服务类型": { + "label": "服务类型", + "view": { + "name": "label", + "props": { + "value": ":kind.name" + } + }, + "edit": { + "type": "select", + "props": { + "value": ":kind.id", + "tree": true, + "searchable": true, + "remote": { + "api": "/api/kind/tree", + "query": { + "select": ["id", "name"], + "keyword": "where_name_like" + } + } + } + } + }, + "服务领域": { + "label": "服务领域", + "view": { + "name": "tags", + "props": { + "value": ":fields" + } + }, + "edit": { + "type": "select", + "props": { + "value": ":fields", + "searchable": true, + "inputable": true, + "multiple": true, + "options": [ + { "label": "视频会议", "value": "视频会议" }, + { "label": "即时通信", "value": "即时通信" }, + { "label": "客服管理", "value": "客服管理" }, + { "label": "财务管理", "value": "财务管理" }, + { "label": "客户关系管理", "value": "客户关系管理" }, + { "label": "营销管理", "value": "营销管理" }, + { "label": "办公自动化", "value": "办公自动化" }, + { "label": "ERP", "value": "ERP" }, + { "label": "人力", "value": "人力" }, + { "label": "采购", "value": "采购" }, + { "label": "供应链", "value": "供应链" }, + { "label": "企业网盘", "value": "企业网盘" }, + { "label": "邮件服务", "value": "邮件服务" }, + { "label": "电子合同", "value": "电子合同" }, + { "label": "安全工具", "value": "安全工具" }, + { "label": "舆情分析", "value": "舆情分析" }, + { "label": "行业应用", "value": "行业应用" }, + { "label": "其他", "value": "其他" } + ] + } + } + }, + "计费方式C": { + "label": "计费方式", + "view": { + "name": "xxxxx", + "components": { "label": {}, "image": {} } + } + }, + "计费方式": { + "label": "计费方式", + "view": { + "name": "tags", + "props": { + "value": ":fields", + "format": [".jpg", "..."] + } + }, + "edit": { + "type": "select", + "props": { + "value": ":price_options", + "multiple": true, + "options": [ + { "label": "按年订阅", "value": "按年订阅" }, + { "label": "按月订阅", "value": "按月订阅" }, + { "label": "按量计费", "value": "按量计费" }, + { "label": "私有化部署", "value": "私有化部署" }, + { "label": "其他", "value": "其他" } + ] + } + } + }, + "行业覆盖": { + "label": "行业覆盖", + "view": { + "name": "tags", + "props": { + "value": ":industries" + } + }, + "edit": { + "type": "select", + "props": { + "value": ":industries", + "inputable": true, + "multiple": true, + "options": [ + { "label": "房地产", "value": "房地产" }, + { "label": "旅游", "value": "旅游" }, + { "label": "教育", "value": "教育" }, + { "label": "互联网", "value": "互联网" }, + { "label": "其他", "value": "其他" } + ] + } + } + }, + "状态": { + "label": "状态", + "view": { + "name": "tags", + "props": { + "value": ":status", + "options": [ + { "label": "开启", "value": "enabled", "color": "primary" }, + { "label": "关闭", "value": "disabled", "color": "danger" } + ] + } + }, + "edit": { + "type": "select", + "props": { + "value": ":status", + "options": [ + { "label": "开启", "value": "enabled" }, + { "label": "关闭", "value": "disabled" } + ] + } + } + }, + "创建时间": { + "label": "创建时间", + "view": { + "name": "label", + "props": { + "value": ":created_at", + "datetime-format": "YYYY年MM月DD日 @hh:mm:ss" + } + } + }, + "更新时间": { + "label": "更新时间", + "view": { + "name": "label", + "props": { + "value": ":update_at", + "datetime-format": "YYYY年MM月DD日 @hh:mm:ss" + } + } + }, + "查询排序": { + "label": "查询排序", + "view": { + "type": "label", + "props": { + "value": ":rank" + } + }, + "edit": { + "type": "input", + "props": { + "value": ":rank", + "type": "number" + } + } + } + }, + "filters": {}, + "list": { + "primary": "id", + "layout": { + "columns": [ + { "name": "服务名称", "width": 6 }, + { "name": "所属厂商", "width": 6 }, + { "name": "服务类型", "width": 4 }, + { "name": "状态", "width": 4 }, + { "name": "服务领域", "width": 4 }, + { "name": "计费方式", "width": 4 }, + { "name": "创建时间", "width": 6 }, + { "name": "更新时间", "width": 6 } + ], + "filters": [] + }, + "actions": {} + }, + "edit": { + "primary": "id", + "layout": { + "fieldset": [ + { + "title": "基础信息", + "description": "", + "columns": [ + { "name": "服务名称", "width": 6 }, + { "name": "所属厂商", "width": 6 }, + { "name": "服务类型", "width": 6 }, + { "name": "状态", "width": 6 }, + { "name": "rank", "width": 6 } + ] + }, + { + "title": "数据标签", + "description": "", + "columns": ["服务领域", "计费方式", "行业覆盖"] + } + ] + }, + "actions": { + "cancel": {}, + "save": { + "type": "button", + "props": { + "label": "保存" + } + }, + "delete": {} + } + }, + "insert": {}, + "view": {} +} diff --git a/user/user.go b/user/user.go index b1864f1122..8204f6ceba 100644 --- a/user/user.go +++ b/user/user.go @@ -1,14 +1,15 @@ package user import ( - "fmt" "time" "github.com/golang-jwt/jwt" "github.com/yaoapp/gou" + "github.com/yaoapp/gou/session" + "github.com/yaoapp/kun/any" "github.com/yaoapp/kun/exception" "github.com/yaoapp/kun/maps" - "github.com/yaoapp/xiang/config" + "github.com/yaoapp/xiang/helper" "golang.org/x/crypto/bcrypt" ) @@ -52,6 +53,7 @@ func Auth(field string, value string, password string) maps.Map { row := rows[0] passwordHash := row.Get("password").(string) + row.Del("password") err = bcrypt.CompareHashAndPassword([]byte(passwordHash), []byte(password)) if err != nil { @@ -59,38 +61,23 @@ func Auth(field string, value string, password string) maps.Map { } expiresAt := time.Now().Unix() + 3600 - token := MakeToken(row, expiresAt) - row.Del("password") + + // token := MakeToken(row, expiresAt) + sid := session.ID() + id := any.Of(row.Get("id")).CInt() + token := helper.JwtMake(id, map[string]interface{}{}, map[string]interface{}{ + "expires_at": expiresAt, + "sid": sid, + }) + session.Global().Expire(time.Duration(token.ExpiresAt)*time.Second).ID(sid).Set("user_id", id) + session.Global().ID(sid).Set("user", row) // 读取菜单 menus := gou.NewProcess("flows.xiang.menu").Run() return maps.Map{ - "expires_at": expiresAt, - "token": token, + "expires_at": token.ExpiresAt, + "token": token.Token, "user": row, "menus": menus, } } - -// MakeToken 生成 JWT Token -func MakeToken(row maps.Map, ExpiresAt int64) string { - claims := &JwtClaims{ - ID: int(row.Get("id").(int64)), - Type: row.Get("type").(string), - Name: row.Get("name").(string), - StandardClaims: jwt.StandardClaims{ - Id: fmt.Sprintf("%s_%d", row.Get("type"), row.Get("id")), - Subject: fmt.Sprintf("%d", row.Get("id")), - ExpiresAt: ExpiresAt, - Issuer: fmt.Sprintf("%d", row.Get("id")), - }, - } - - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - tokenString, err := token.SignedString([]byte(config.Conf.JWT.Secret)) - if err != nil { - exception.New("生成登录口令失败 %s", 500, err).Throw() - } - - return tokenString -} diff --git a/xiang/apis/table.http.json b/xiang/apis/table.http.json index a7529433b2..8b43503546 100644 --- a/xiang/apis/table.http.json +++ b/xiang/apis/table.http.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "数据表格接口API", "group": "xiang/table", - "guard": "in-process", + "guard": "bearer-jwt", "paths": [ { "path": "/:name/search",