|
|
# -*- coding: utf-8 -*-
|
|
|
#
|
|
|
from collections import defaultdict
|
|
|
from common.struct import Stack
|
|
|
from common.utils import timeit
|
|
|
from assets.utils import NodeUtil
|
|
|
|
|
|
|
|
|
class PermStackUtilMixin:
|
|
|
def __init__(self, debug=False):
|
|
|
self.stack = None
|
|
|
self._nodes = {}
|
|
|
self._debug = debug
|
|
|
|
|
|
@staticmethod
|
|
|
def sorted_by(node_dict):
|
|
|
return [int(i) for i in node_dict['key'].split(':')]
|
|
|
|
|
|
@staticmethod
|
|
|
def is_children(item1, item2):
|
|
|
key1 = item1["key"]
|
|
|
key2 = item2["key"]
|
|
|
return key2.startswith(key1 + ':') and (
|
|
|
len(key2.split(':')) - len(key1.split(':'))
|
|
|
) == 1
|
|
|
|
|
|
def debug(self, msg):
|
|
|
self._debug and print(msg)
|
|
|
|
|
|
|
|
|
class PermSystemUserNodeUtil(PermStackUtilMixin):
|
|
|
"""
|
|
|
self._nodes: {node.key: {system_user.id: actions,}}
|
|
|
"""
|
|
|
@timeit
|
|
|
def get_nodes_family_and_system_users(self, nodes_with_system_users):
|
|
|
"""
|
|
|
返回所有nodes_with_system_users中的node的家族节点的信息,
|
|
|
并子会继承祖先的系统用户和actions信息
|
|
|
:param nodes_with_system_users:
|
|
|
{node.key: {system_user.id: actions,}, }
|
|
|
:return:
|
|
|
{node.key: {system_user.id: actions,}, }
|
|
|
"""
|
|
|
node_util = NodeUtil()
|
|
|
_nodes_keys = nodes_with_system_users.keys()
|
|
|
family_keys = node_util.get_some_nodes_family_keys_by_keys(_nodes_keys)
|
|
|
|
|
|
nodes_items = []
|
|
|
for i in family_keys:
|
|
|
system_users = nodes_with_system_users.get(i, defaultdict(int))
|
|
|
item = {"key": i, "system_users": system_users}
|
|
|
nodes_items.append(item)
|
|
|
# 按照父子关系排序
|
|
|
nodes_items.sort(key=self.sorted_by)
|
|
|
nodes_items.append({"key": "", "system_users": defaultdict(int)})
|
|
|
|
|
|
self.stack = Stack()
|
|
|
for item in nodes_items:
|
|
|
self.debug("准备: {} 栈顶: {}".format(
|
|
|
item['key'], self.stack.top["key"] if self.stack.top else None)
|
|
|
)
|
|
|
# 入栈之前检查,该节点是不是栈顶节点的子节点
|
|
|
# 如果不是,则栈顶出栈
|
|
|
while self.stack.top and not self.is_children(self.stack.top, item):
|
|
|
# 出栈
|
|
|
self.pop_from_stack_system_users()
|
|
|
# 入栈
|
|
|
self.push_to_stack_system_users(item)
|
|
|
# 出栈最后一个
|
|
|
self.debug("剩余: {}".format(', '.join([n["key"] for n in self.stack])))
|
|
|
return self._nodes
|
|
|
|
|
|
def push_to_stack_system_users(self, item):
|
|
|
"""
|
|
|
:param item:
|
|
|
{"key": node.key, "system_users": {system_user.id: actions,},}
|
|
|
"""
|
|
|
if not self.stack.is_empty():
|
|
|
item_system_users = item["system_users"]
|
|
|
for system_user, action in self.stack.top["system_users"].items():
|
|
|
# 更新栈顶的系统用户和action到将要入栈的item中
|
|
|
item_system_users[system_user] |= action
|
|
|
item["system_users"] = item_system_users
|
|
|
self.debug("入栈: {}".format(item['key']))
|
|
|
self.stack.push(item)
|
|
|
|
|
|
# 出栈
|
|
|
def pop_from_stack_system_users(self):
|
|
|
_node = self.stack.pop()
|
|
|
self._nodes[_node["key"]] = _node["system_users"]
|
|
|
self.debug("出栈: {} 栈顶: {}".format(_node['key'], self.stack.top['key'] if self.stack.top else None))
|
|
|
|
|
|
|
|
|
class PermAssetsAmountUtil(PermStackUtilMixin):
|
|
|
def push_to_stack_nodes_amount(self, item):
|
|
|
self.debug("入栈: {}".format(item['key']))
|
|
|
self.stack.push(item)
|
|
|
|
|
|
def pop_from_stack_nodes_amount(self):
|
|
|
_node = self.stack.pop()
|
|
|
self.debug("出栈: {} 栈顶: {}".format(
|
|
|
_node['key'], self.stack.top['key'] if self.stack.top else None)
|
|
|
)
|
|
|
_node["assets_amount"] = len(_node["all_assets"] | _node["assets"])
|
|
|
self._nodes[_node.pop("key")] = _node
|
|
|
|
|
|
if not self.stack.top:
|
|
|
return
|
|
|
self.stack.top["all_assets"]\
|
|
|
.update(_node["all_assets"] | _node["assets"])
|
|
|
|
|
|
def compute_nodes_assets_amount(self, nodes_with_assets):
|
|
|
self.stack = Stack()
|
|
|
nodes_items = []
|
|
|
for key, values in nodes_with_assets.items():
|
|
|
nodes_items.append({
|
|
|
"key": key, "assets": values["assets"],
|
|
|
"all_assets": values["all_assets"], "assets_amount": 0
|
|
|
})
|
|
|
|
|
|
nodes_items.sort(key=self.sorted_by)
|
|
|
nodes_items.append({"key": "", "assets": set(), "all_assets": set(), "assets_amount": 0})
|
|
|
self.stack = Stack()
|
|
|
for item in nodes_items:
|
|
|
self.debug("准备: {} 栈顶: {}".format(
|
|
|
item['key'], self.stack.top["key"] if self.stack.top else None)
|
|
|
)
|
|
|
# 入栈之前检查,该节点是不是栈顶节点的子节点
|
|
|
# 如果不是,则栈顶出栈
|
|
|
while self.stack.top and not self.is_children(self.stack.top, item):
|
|
|
self.pop_from_stack_nodes_amount()
|
|
|
self.push_to_stack_nodes_amount(item)
|
|
|
# 出栈最后一个
|
|
|
self.debug("剩余: {}".format(', '.join([n["key"] for n in self.stack])))
|
|
|
return self._nodes |