package usecase import ( "backend/pkg/permission/domain/entity" "backend/pkg/permission/domain/permission" "backend/pkg/permission/domain/usecase" "fmt" "go.mongodb.org/mongo-driver/v2/bson" ) // PermissionTree 權限樹 (優化版本) type PermissionTree struct { // 所有節點 (ID -> Node) nodes map[string]*PermissionNode // 根節點列表 roots []*PermissionNode // 名稱索引 (Name -> IDs) nameIndex map[string][]string // 子節點索引 (ParentID -> Children IDs) childrenIndex map[string][]string } // PermissionNode 權限節點 type PermissionNode struct { Permission *entity.Permission Parent *PermissionNode Children []*PermissionNode PathIDs []string // 從根到此節點的完整路徑 ID } // NewPermissionTree 建立權限樹 func NewPermissionTree(permissions []*entity.Permission) *PermissionTree { tree := &PermissionTree{ nodes: make(map[string]*PermissionNode), roots: make([]*PermissionNode, 0), nameIndex: make(map[string][]string), childrenIndex: make(map[string][]string), } // 第一遍:建立所有節點 for _, perm := range permissions { node := &PermissionNode{ Permission: perm, Children: make([]*PermissionNode, 0), PathIDs: make([]string, 0), } idHex := perm.ID.Hex() tree.nodes[idHex] = node // 建立名稱索引 tree.nameIndex[perm.Name] = append(tree.nameIndex[perm.Name], idHex) // 建立子節點索引 parentIDHex := perm.ParentID.Hex() tree.childrenIndex[parentIDHex] = append(tree.childrenIndex[parentIDHex], idHex) } // 第二遍:建立父子關係 for _, node := range tree.nodes { if node.Permission.ParentID.IsZero() { // 根節點 tree.roots = append(tree.roots, node) } else { // 找到父節點並建立關係 parentIDHex := node.Permission.ParentID.Hex() if parent, ok := tree.nodes[parentIDHex]; ok { node.Parent = parent parent.Children = append(parent.Children, node) } } } // 第三遍:計算 PathIDs (從根節點向下遞迴) var buildPathIDs func(*PermissionNode, []string) buildPathIDs = func(node *PermissionNode, parentPath []string) { node.PathIDs = make([]string, len(parentPath)) copy(node.PathIDs, parentPath) // 為子節點建立新路徑 (加入當前節點 ID) childPath := append(parentPath, node.Permission.ID.Hex()) for _, child := range node.Children { buildPathIDs(child, childPath) } } // 從所有根節點開始 for _, root := range tree.roots { buildPathIDs(root, []string{}) } return tree } // GetNode 取得節點 func (t *PermissionTree) GetNode(id string) *PermissionNode { return t.nodes[id] } // GetNodeByObjectID 根據 ObjectID 取得節點 func (t *PermissionTree) GetNodeByObjectID(id bson.ObjectID) *PermissionNode { return t.nodes[id.Hex()] } // GetNodesByName 根據名稱取得節點列表 func (t *PermissionTree) GetNodesByName(name string) []*PermissionNode { ids, ok := t.nameIndex[name] if !ok { return nil } nodes := make([]*PermissionNode, 0, len(ids)) for _, id := range ids { if node, ok := t.nodes[id]; ok { nodes = append(nodes, node) } } return nodes } // ExpandPermissions 展開權限 (包含所有父權限) func (t *PermissionTree) ExpandPermissions(permissions permission.Permissions) (permission.Permissions, error) { expanded := make(permission.Permissions) visited := make(map[string]bool) for name, status := range permissions { if status != permission.Open { continue } nodes := t.GetNodesByName(name) if len(nodes) == 0 { return nil, fmt.Errorf("permission not found: %s", name) } for _, node := range nodes { // 如果是父節點,檢查是否有任何子節點被開啟 if len(node.Children) > 0 { hasActiveChild := false for _, child := range node.Children { if permissions.HasPermission(child.Permission.Name) { hasActiveChild = true break } } // 如果沒有任何子節點被開啟,跳過此父節點 if !hasActiveChild { continue } } // 加入此節點 idHex := node.Permission.ID.Hex() if !visited[idHex] { expanded.AddPermission(node.Permission.Name) visited[idHex] = true } // 加入所有父節點 for _, parentID := range node.PathIDs { if !visited[parentID] { if parentNode := t.GetNode(parentID); parentNode != nil { expanded.AddPermission(parentNode.Permission.Name) visited[parentID] = true } } } } } return expanded, nil } // GetPermissionIDs 取得權限 ID 列表 (包含父權限) func (t *PermissionTree) GetPermissionIDs(permissions permission.Permissions) ([]bson.ObjectID, error) { ids := make([]bson.ObjectID, 0) visited := make(map[string]bool) for name, status := range permissions { if status != permission.Open { continue } nodes := t.GetNodesByName(name) if len(nodes) == 0 { return nil, fmt.Errorf("permission not found: %s", name) } for _, node := range nodes { // 檢查父節點邏輯 if len(node.Children) > 0 { hasActiveChild := false for _, child := range node.Children { if permissions.HasPermission(child.Permission.Name) { hasActiveChild = true break } } if !hasActiveChild { continue } } // 加入此節點和所有父節點 idHex := node.Permission.ID.Hex() pathIDs := append(node.PathIDs, idHex) for _, id := range pathIDs { if !visited[id] { oid, _ := bson.ObjectIDFromHex(id) ids = append(ids, oid) visited[id] = true } } } } return ids, nil } // BuildPermissionsFromIDs 從權限 ID 列表建立權限集合 (包含父權限) func (t *PermissionTree) BuildPermissionsFromIDs(permissionIDs []bson.ObjectID) permission.Permissions { permissions := make(permission.Permissions) visited := make(map[string]bool) for _, id := range permissionIDs { node := t.GetNodeByObjectID(id) if node == nil { continue } // 加入此節點 idHex := node.Permission.ID.Hex() if !visited[idHex] { permissions.AddPermission(node.Permission.Name) visited[idHex] = true } // 加入所有父節點 for _, parentID := range node.PathIDs { if !visited[parentID] { if parentNode := t.GetNode(parentID); parentNode != nil { permissions.AddPermission(parentNode.Permission.Name) visited[parentID] = true } } } } return permissions } // ToTree 轉換為樹狀結構回應 func (t *PermissionTree) ToTree() []*usecase.PermissionTreeNode { result := make([]*usecase.PermissionTreeNode, 0, len(t.roots)) for _, root := range t.roots { result = append(result, t.buildTreeNode(root)) } return result } func (t *PermissionTree) buildTreeNode(node *PermissionNode) *usecase.PermissionTreeNode { status := permission.Open if !node.Permission.State.IsActive() { status = permission.Close } treeNode := &usecase.PermissionTreeNode{ PermissionResponse: &usecase.PermissionResponse{ ID: node.Permission.ID.Hex(), ParentID: node.Permission.ParentID.Hex(), Name: node.Permission.Name, HTTPPath: node.Permission.HTTPPath, HTTPMethod: node.Permission.HTTPMethod, Status: status, Type: node.Permission.Type, }, Children: make([]*usecase.PermissionTreeNode, 0, len(node.Children)), } for _, child := range node.Children { treeNode.Children = append(treeNode.Children, t.buildTreeNode(child)) } return treeNode } // DetectCircularDependency 檢測循環依賴 func (t *PermissionTree) DetectCircularDependency() error { for _, node := range t.nodes { visited := make(map[string]bool) if err := t.detectCircular(node, visited); err != nil { return err } } return nil } func (t *PermissionTree) detectCircular(node *PermissionNode, visited map[string]bool) error { idHex := node.Permission.ID.Hex() if visited[idHex] { return fmt.Errorf("circular dependency detected at permission: %s", node.Permission.Name) } visited[idHex] = true if node.Parent != nil { return t.detectCircular(node.Parent, visited) } return nil }