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

1 year ago
  1. package tag
  2. import (
  3. "git.aiterp.net/rpdata2-take2/rpdata2/auth"
  4. "git.aiterp.net/rpdata2-take2/rpdata2/internal/genutils"
  5. )
  6. type Node struct {
  7. Tag
  8. Children []Node `json:"children"`
  9. }
  10. func (n Node) WithoutSecret(reqUser *auth.UserInfo) *Node {
  11. return n.filter(func(n Node) bool {
  12. if !n.Secret {
  13. return false
  14. }
  15. return reqUser != nil && reqUser.HasIDOrPermission(n.OwnerID, "tag", "view_secret")
  16. })
  17. }
  18. func (n Node) WithoutUnlisted() *Node {
  19. return n.filter(func(n Node) bool { return n.Listed })
  20. }
  21. func (n Node) filter(cb func(n Node) bool) *Node {
  22. if !cb(n) {
  23. return nil
  24. }
  25. filtered := make([]Node, 0, len(n.Children))
  26. for _, child := range n.Children {
  27. pruned := child.filter(cb)
  28. if pruned == nil {
  29. continue
  30. }
  31. filtered = append(filtered, *pruned)
  32. }
  33. n.Children = filtered
  34. return &n
  35. }
  36. func (n Node) Less(n2 Node) bool {
  37. if n.Kind < n2.Kind {
  38. return true
  39. }
  40. return n.Name < n2.Name
  41. }
  42. func BuildForest(tags []Tag) []Node {
  43. nodes := make(map[string]*Node)
  44. for _, tag := range tags {
  45. nodes[tag.ID] = &Node{Tag: tag, Children: []Node{}}
  46. }
  47. children := make(map[string][]*Node, len(tags))
  48. for _, node := range nodes {
  49. if node.ParentID != nil {
  50. children[*node.ParentID] = append(children[*node.ParentID], node)
  51. }
  52. }
  53. cleared := make(map[string]bool)
  54. for len(cleared) < len(nodes) {
  55. anyCleared := false
  56. for _, node := range nodes {
  57. if cleared[node.ID] {
  58. continue
  59. }
  60. good := true
  61. for _, child := range children[node.ID] {
  62. if !cleared[child.ID] {
  63. good = false
  64. break
  65. }
  66. }
  67. if good {
  68. genutils.SortSlice(node.Children)
  69. cleared[node.ID] = true
  70. anyCleared = true
  71. if node.ParentID != nil {
  72. nodes[*node.ParentID].Children = append(nodes[*node.ParentID].Children, *node)
  73. }
  74. }
  75. }
  76. if !anyCleared {
  77. panic("deadlock in tag.BuildForest")
  78. }
  79. }
  80. res := make([]Node, 0, 8)
  81. for _, node := range nodes {
  82. if node.ParentID == nil {
  83. res = append(res, *node)
  84. }
  85. }
  86. genutils.SortSlice(res)
  87. return res
  88. }