You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
2.0 KiB

package tag
import (
"git.aiterp.net/rpdata2-take2/rpdata2/auth"
"git.aiterp.net/rpdata2-take2/rpdata2/internal/genutils"
)
type Node struct {
Tag
Children []Node `json:"children"`
}
func (n Node) WithoutSecret(reqUser *auth.UserInfo) *Node {
return n.filter(func(n Node) bool {
if !n.Secret {
return false
}
return reqUser != nil && reqUser.HasIDOrPermission(n.OwnerID, "tag", "view_secret")
})
}
func (n Node) WithoutUnlisted() *Node {
return n.filter(func(n Node) bool { return n.Listed })
}
func (n Node) filter(cb func(n Node) bool) *Node {
if !cb(n) {
return nil
}
filtered := make([]Node, 0, len(n.Children))
for _, child := range n.Children {
pruned := child.filter(cb)
if pruned == nil {
continue
}
filtered = append(filtered, *pruned)
}
n.Children = filtered
return &n
}
func (n Node) Less(n2 Node) bool {
if n.Kind < n2.Kind {
return true
}
return n.Name < n2.Name
}
func BuildForest(tags []Tag) []Node {
nodes := make(map[string]*Node)
for _, tag := range tags {
nodes[tag.ID] = &Node{Tag: tag, Children: []Node{}}
}
children := make(map[string][]*Node, len(tags))
for _, node := range nodes {
if node.ParentID != nil {
children[*node.ParentID] = append(children[*node.ParentID], node)
}
}
cleared := make(map[string]bool)
for len(cleared) < len(nodes) {
anyCleared := false
for _, node := range nodes {
if cleared[node.ID] {
continue
}
good := true
for _, child := range children[node.ID] {
if !cleared[child.ID] {
good = false
break
}
}
if good {
genutils.SortSlice(node.Children)
cleared[node.ID] = true
anyCleared = true
if node.ParentID != nil {
nodes[*node.ParentID].Children = append(nodes[*node.ParentID].Children, *node)
}
}
}
if !anyCleared {
panic("deadlock in tag.BuildForest")
}
}
res := make([]Node, 0, 8)
for _, node := range nodes {
if node.ParentID == nil {
res = append(res, *node)
}
}
genutils.SortSlice(res)
return res
}