add some audit log

This commit is contained in:
710leo 2021-03-18 21:22:50 +08:00
parent d89eaec596
commit 184c39d311
7 changed files with 197 additions and 13 deletions

View File

@ -247,7 +247,7 @@ CREATE TABLE `role`
`note` varchar(255) not null default '', `note` varchar(255) not null default '',
`cate` char(6) not null default '' comment 'category: global or local', `cate` char(6) not null default '' comment 'category: global or local',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY (`name`) UNIQUE KEY (`name`,`cate`)
) ENGINE = InnoDB ) ENGINE = InnoDB
DEFAULT CHARSET = utf8; DEFAULT CHARSET = utf8;

View File

@ -2,6 +2,7 @@ package models
import ( import (
"fmt" "fmt"
"regexp"
"strings" "strings"
"time" "time"
@ -39,3 +40,124 @@ func Paths(longPath string) []string {
return paths 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
}

View File

@ -141,9 +141,13 @@ func UsernameCandoNodeOp(username, operation string, nodeId int64) (bool, error)
return user.HasPermByNode(node, operation) return user.HasPermByNode(node, operation)
} }
func UserAndTotalGets(query, org string, limit, offset int, ids []int64) ([]User, int64, error) { func UserAndTotalGets(query, org string, conditions string, limit, offset int, ids []int64) ([]User, int64, error) {
where := "1 = 1" where := ""
param := []interface{}{} param := []interface{}{}
where, param = parseConditions(conditions)
if where == "" {
where = "1 = 1"
}
if query != "" { if query != "" {
q := "%" + query + "%" q := "%" + query + "%"

View File

@ -183,6 +183,7 @@ func Config(r *gin.Engine) {
v1.GET("/nodes", nodeGets) v1.GET("/nodes", nodeGets)
v1.GET("/node/:id", nodeGet) v1.GET("/node/:id", nodeGet)
v1.GET("/node-include-trash/:id", nodeIncludeTrashGet)
v1.GET("/node/:id/projs", v1treeUntilProjectGetsByNid) v1.GET("/node/:id/projs", v1treeUntilProjectGetsByNid)
v1.GET("/tree/projs", v1TreeUntilProjectGets) v1.GET("/tree/projs", v1TreeUntilProjectGets)
v1.GET("/tree", v1TreeUntilTypGets) v1.GET("/tree", v1TreeUntilTypGets)

View File

@ -15,6 +15,42 @@ func nodeGet(c *gin.Context) {
renderData(c, node, nil) 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) { func nodeGets(c *gin.Context) {
cate := queryStr(c, "cate", "") cate := queryStr(c, "cate", "")
withInner := queryInt(c, "inner", 0) withInner := queryInt(c, "inner", 0)
@ -151,7 +187,8 @@ func nodePut(c *gin.Context) {
id := urlParamInt64(c, "id") id := urlParamInt64(c, "id")
node := Node(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) 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) renderData(c, node, err)
} }
func nodeDel(c *gin.Context) { func nodeDel(c *gin.Context) {
id := urlParamInt64(c, "id") id := urlParamInt64(c, "id")
node := Node(id) node := Node(id)
me := loginUser(c)
me.CheckPermByNode(node, "rdb_node_delete")
loginUser(c).CheckPermByNode(node, "rdb_node_delete") 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, node.Del()) renderMessage(c, nil)
} }

View File

@ -380,9 +380,17 @@ func resourceBindNode(c *gin.Context) {
bomb("field[%s] not supported", f.Field) 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) { func resourceUnbindNode(c *gin.Context) {
@ -395,9 +403,17 @@ func resourceUnbindNode(c *gin.Context) {
var f idsForm var f idsForm
bind(c, &f) 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)
} }
// 这个修改备注信息是在节点下挂载的资源页面,非游离资源页面 // 这个修改备注信息是在节点下挂载的资源页面,非游离资源页面

View File

@ -17,10 +17,11 @@ import (
func userListGet(c *gin.Context) { func userListGet(c *gin.Context) {
limit := queryInt(c, "limit", 20) limit := queryInt(c, "limit", 20)
query := queryStr(c, "query", "") query := queryStr(c, "query", "")
conditions := queryStr(c, "conditions", "")
org := queryStr(c, "org", "") org := queryStr(c, "org", "")
ids := str.IdsInt64(queryStr(c, "ids", "")) 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) dangerous(err)
for i := 0; i < len(list); i++ { for i := 0; i < len(list); i++ {
@ -40,7 +41,7 @@ func v1UserListGet(c *gin.Context) {
org := queryStr(c, "org", "") org := queryStr(c, "org", "")
ids := str.IdsInt64(queryStr(c, "ids", "")) 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{ renderData(c, gin.H{
"list": list, "list": list,