diff --git a/sql/n9e_rdb.sql b/sql/n9e_rdb.sql index 4a25e9b8..3d4595df 100644 --- a/sql/n9e_rdb.sql +++ b/sql/n9e_rdb.sql @@ -247,7 +247,7 @@ CREATE TABLE `role` `note` varchar(255) not null default '', `cate` char(6) not null default '' comment 'category: global or local', PRIMARY KEY (`id`), - UNIQUE KEY (`name`) + UNIQUE KEY (`name`,`cate`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8; diff --git a/src/models/tools.go b/src/models/tools.go index 85a6a1cf..64182186 100644 --- a/src/models/tools.go +++ b/src/models/tools.go @@ -2,6 +2,7 @@ package models import ( "fmt" + "regexp" "strings" "time" @@ -39,3 +40,124 @@ func Paths(longPath string) []string { return paths } + +func parseConditions(conditions string) (string, []interface{}) { + conditions = strings.TrimSpace(conditions) + if conditions == "" { + return "", []interface{}{} + } + + var ( + where []string + args []interface{} + ) + + arr := strings.Split(conditions, ",") + cnt := len(arr) + for i := 0; i < cnt; i++ { + if strings.Contains(arr[i], "~=") { + pair := strings.Split(arr[i], "~=") + if WarningStr(pair[0]) { + continue + } + if strings.Contains(pair[0], "|") { + keys := strings.Split(pair[0], "|") + str := "(" + for i, k := range keys { + if i < len(keys)-1 { + str += fmt.Sprintf("%s like ? OR ", k) + } else { + str += fmt.Sprintf("%s like ?)", k) + } + args = append(args, "%"+pair[1]+"%") + } + where = append(where, str) + } else { + where = append(where, pair[0]+" like ?") + args = append(args, "%"+pair[1]+"%") + } + continue + } + + if strings.Contains(arr[i], "!=") { + pair := strings.Split(arr[i], "!=") + if WarningStr(pair[0]) { + continue + } + where = append(where, pair[0]+" != ?") + args = append(args, pair[1]) + continue + } + + if strings.Contains(arr[i], ">=") { + pair := strings.Split(arr[i], ">=") + if WarningStr(pair[0]) { + continue + } + where = append(where, pair[0]+" >= ?") + args = append(args, pair[1]) + continue + } + + if strings.Contains(arr[i], "<=") { + pair := strings.Split(arr[i], "<=") + if WarningStr(pair[0]) { + continue + } + where = append(where, pair[0]+" <= ?") + args = append(args, pair[1]) + continue + } + + if strings.Contains(arr[i], "=") { + pair := strings.Split(arr[i], "=") + if WarningStr(pair[0]) { + continue + } + where = append(where, pair[0]+" = ?") + args = append(args, pair[1]) + continue + } + + if strings.Contains(arr[i], ">") { + pair := strings.Split(arr[i], ">") + if WarningStr(pair[0]) { + continue + } + where = append(where, pair[0]+" > ?") + args = append(args, pair[1]) + continue + } + + if strings.Contains(arr[i], "<") { + pair := strings.Split(arr[i], "<") + if WarningStr(pair[0]) { + continue + } + where = append(where, pair[0]+" < ?") + args = append(args, pair[1]) + continue + } + + if strings.Contains(arr[i], "^^") { + pair := strings.Split(arr[i], "^^") + if WarningStr(pair[0]) { + continue + } + where = append(where, pair[0]+" in ("+strings.Join(strings.Split(pair[1], "|"), ",")+")") + continue + } + } + + return strings.Join(where, " and "), args +} + +var dbfieldPattern = regexp.MustCompile("^[a-z][a-z0-9\\|_A-Z]*$") + +func WarningStr(s string) bool { + if dbfieldPattern.MatchString(s) || s == "" { + return false + } + + return true +} diff --git a/src/models/user_service.go b/src/models/user_service.go index c2a2dac6..98580fd8 100644 --- a/src/models/user_service.go +++ b/src/models/user_service.go @@ -141,9 +141,13 @@ func UsernameCandoNodeOp(username, operation string, nodeId int64) (bool, error) return user.HasPermByNode(node, operation) } -func UserAndTotalGets(query, org string, limit, offset int, ids []int64) ([]User, int64, error) { - where := "1 = 1" +func UserAndTotalGets(query, org string, conditions string, limit, offset int, ids []int64) ([]User, int64, error) { + where := "" param := []interface{}{} + where, param = parseConditions(conditions) + if where == "" { + where = "1 = 1" + } if query != "" { q := "%" + query + "%" diff --git a/src/modules/rdb/http/router.go b/src/modules/rdb/http/router.go index f8d2224b..c189a702 100644 --- a/src/modules/rdb/http/router.go +++ b/src/modules/rdb/http/router.go @@ -183,6 +183,7 @@ func Config(r *gin.Engine) { v1.GET("/nodes", nodeGets) v1.GET("/node/:id", nodeGet) + v1.GET("/node-include-trash/:id", nodeIncludeTrashGet) v1.GET("/node/:id/projs", v1treeUntilProjectGetsByNid) v1.GET("/tree/projs", v1TreeUntilProjectGets) v1.GET("/tree", v1TreeUntilTypGets) diff --git a/src/modules/rdb/http/router_node.go b/src/modules/rdb/http/router_node.go index df366c14..09606625 100644 --- a/src/modules/rdb/http/router_node.go +++ b/src/modules/rdb/http/router_node.go @@ -15,6 +15,42 @@ func nodeGet(c *gin.Context) { renderData(c, node, nil) } +//使用场景:节点被删除了,但还是需要查询节点来补全信息 +func nodeIncludeTrashGet(c *gin.Context) { + nid := urlParamInt64(c, "id") + realNode, err := models.NodeGet("id=?", nid) + dangerous(err) + if realNode != nil { + realNode.FillAdmins() + renderData(c, realNode, nil) + return + } + + var node *models.Node + nodesInTrash, err := models.NodeTrashGetByIds([]int64{nid}) + dangerous(err) + if len(nodesInTrash) == 1 { + nodeInTrash := nodesInTrash[0] + node = &models.Node{ + Id: nid, + Pid: nodeInTrash.Pid, + Ident: nodeInTrash.Ident, + Name: nodeInTrash.Name, + Note: nodeInTrash.Note, + Path: nodeInTrash.Path, + Leaf: nodeInTrash.Leaf, + Cate: nodeInTrash.Cate, + IconColor: nodeInTrash.IconColor, + IconChar: nodeInTrash.IconChar, + Proxy: nodeInTrash.Proxy, + Creator: nodeInTrash.Creator, + LastUpdated: nodeInTrash.LastUpdated, + } + } + + renderData(c, node, nil) +} + func nodeGets(c *gin.Context) { cate := queryStr(c, "cate", "") withInner := queryInt(c, "inner", 0) @@ -151,7 +187,8 @@ func nodePut(c *gin.Context) { id := urlParamInt64(c, "id") node := Node(id) - loginUser(c).CheckPermByNode(node, "rdb_node_modify") + me := loginUser(c) + me.CheckPermByNode(node, "rdb_node_modify") // 即使是第三方系统创建的节点,也可以修改,只是改个名字、备注、类别、管理员,没啥大不了的 // 第三方系统主要是管理下面的资源的挂载 @@ -168,14 +205,17 @@ func nodePut(c *gin.Context) { } err := node.Modify(f.Name, f.Cate, f.Note, f.AdminIds) + go models.OperationLogNew(me.Username, "node", node.Id, fmt.Sprintf("NodeModify path: %s, name: %s clientIP: %s", node.Path, node.Name, c.ClientIP())) renderData(c, node, err) } func nodeDel(c *gin.Context) { id := urlParamInt64(c, "id") node := Node(id) + me := loginUser(c) + me.CheckPermByNode(node, "rdb_node_delete") - loginUser(c).CheckPermByNode(node, "rdb_node_delete") - - renderMessage(c, node.Del()) + dangerous(node.Del()) + go models.OperationLogNew(me.Username, "node", node.Id, fmt.Sprintf("NodeDelete path: %s, name: %s clientIP: %s", node.Path, node.Name, c.ClientIP())) + renderMessage(c, nil) } diff --git a/src/modules/rdb/http/router_resource.go b/src/modules/rdb/http/router_resource.go index 899f3447..e4069bc2 100644 --- a/src/modules/rdb/http/router_resource.go +++ b/src/modules/rdb/http/router_resource.go @@ -380,9 +380,17 @@ func resourceBindNode(c *gin.Context) { bomb("field[%s] not supported", f.Field) } - loginUser(c).CheckPermByNode(node, "rdb_resource_bind") + me := loginUser(c) + me.CheckPermByNode(node, "rdb_resource_bind") + dangerous(node.Bind(ids)) - renderMessage(c, node.Bind(ids)) + sql := "id in (" + str.IdsString(ids) + ")" + resources, _ := models.ResourceGets(sql) + for _, resource := range resources { + go models.OperationLogNew(me.Username, "node", node.Id, fmt.Sprintf("NodeBind path: %s, name: %s resource:%s clientIP: %s", node.Path, node.Name, resource.Ident, c.ClientIP())) + } + + renderMessage(c, nil) } func resourceUnbindNode(c *gin.Context) { @@ -395,9 +403,17 @@ func resourceUnbindNode(c *gin.Context) { var f idsForm bind(c, &f) - loginUser(c).CheckPermByNode(node, "rdb_resource_unbind") + me := loginUser(c) + me.CheckPermByNode(node, "rdb_resource_unbind") + dangerous(node.Unbind(f.Ids)) - renderMessage(c, node.Unbind(f.Ids)) + sql := "id in (" + str.IdsString(f.Ids) + ")" + resources, _ := models.ResourceGets(sql) + for _, resource := range resources { + go models.OperationLogNew(me.Username, "node", node.Id, fmt.Sprintf("NodeUnbind path: %s, name: %s resource:%s clientIP: %s", node.Path, node.Name, resource.Ident, c.ClientIP())) + } + + renderMessage(c, nil) } // 这个修改备注信息是在节点下挂载的资源页面,非游离资源页面 diff --git a/src/modules/rdb/http/router_user.go b/src/modules/rdb/http/router_user.go index 69a858c2..3ccb3cb0 100644 --- a/src/modules/rdb/http/router_user.go +++ b/src/modules/rdb/http/router_user.go @@ -17,10 +17,11 @@ import ( func userListGet(c *gin.Context) { limit := queryInt(c, "limit", 20) query := queryStr(c, "query", "") + conditions := queryStr(c, "conditions", "") org := queryStr(c, "org", "") ids := str.IdsInt64(queryStr(c, "ids", "")) - list, total, err := models.UserAndTotalGets(query, org, limit, offset(c, limit), ids) + list, total, err := models.UserAndTotalGets(query, org, conditions, limit, offset(c, limit), ids) dangerous(err) for i := 0; i < len(list); i++ { @@ -40,7 +41,7 @@ func v1UserListGet(c *gin.Context) { org := queryStr(c, "org", "") ids := str.IdsInt64(queryStr(c, "ids", "")) - list, total, err := models.UserAndTotalGets(query, org, limit, offset(c, limit), ids) + list, total, err := models.UserAndTotalGets(query, org, "", limit, offset(c, limit), ids) renderData(c, gin.H{ "list": list,