mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-09-05 17:30:30 +00:00
* Bai reactor tree ( 重构获取完整资产树中节点下资产总数的逻辑) (#5548) * tree: v0.1 * tree: v0.2 * tree: v0.3 * tree: v0.4 * tree: 添加并发锁未请求到时的debug日志 * 以空间换时间的方式优化资产树 * Reactor tree togther v2 (#5576) * Bai reactor tree ( 重构获取完整资产树中节点下资产总数的逻辑) (#5548) * tree: v0.1 * tree: v0.2 * tree: v0.3 * tree: v0.4 * tree: 添加并发锁未请求到时的debug日志 * 以空间换时间的方式优化资产树 * 修改授权适配新方案 * 添加树处理工具 * 完成新的用户授权树计算以及修改一些信号 * 重构了获取资产的一些 api * 重构了一些节点的api * 整理了一些代码 * 完成了api 的重构 * 重构检查节点数量功能 * 完成重构授权树工具类 * api 添加强制刷新参数 * 整理一些信号 * 处理一些信号的问题 * 完成了信号的处理 * 重构了资产树相关的锁机制 * RebuildUserTreeTask 还得添加回来 * 优化下不能在root组织的检查函数 * 优化资产树变化时锁的使用 * 修改一些算法的小工具 * 资产树锁不再校验是否在具体组织里 * 整理了一些信号的位置 * 修复资产与节点关系维护的bug * 去掉一些调试代码 * 修复资产授权过期检查刷新授权树的 bug * 添加了可重入锁 * 添加一些计时,优化一些sql * 增加 union 查询的支持 * 尝试用 sql 解决节点资产数量问题 * 开始优化计算授权树节点资产数量不用冗余表 * 新代码能跑起来了,修复一下bug * 去掉 UserGrantedMappingNode 换成 UserAssetGrantedTreeNodeRelation * 修了些bug,做了些优化 * 优化QuerySetStage 执行逻辑 * 与小白的内存结合了 * 删掉老的表,迁移新的 assets_amount 字段 * 优化用户授权页面资产列表 count 慢 * 修复批量命令数量不对 * 修改获取非直接授权节点的 children 的逻辑 * 获取整棵树的节点 * 回退锁 * 整理迁移脚本 * 改变更新树策略 * perf: 修改一波缩进 * fix: 修改handler名称 * 修复授权树获取资产sql 泛滥 * 修复授权规则有效bug * 修复一些bug * 修复一些bug * 又修了一些小bug * 去掉了老的 get_nodes_all_assets * 修改一些写法 * Reactor tree togther b2 (#5570) * fix: 修改handler名称 * perf: 优化生成树 * perf: 去掉注释 * 优化了一些 * 重新生成迁移脚本 * 去掉周期检查节点资产数量的任务 * Pr@reactor tree togther guang@perf mapping (#5573) * fix: 修改handler名称 * perf: mapping 拆分出来 * 修改名称 * perf: 修改锁名 * perf: 去掉检查节点任务 * perf: 修改一下名称 * perf: 优化一波 Co-authored-by: Jiangjie.Bai <32935519+BaiJiangJie@users.noreply.github.com> Co-authored-by: Bai <bugatti_it@163.com> Co-authored-by: xinwen <coderWen@126.com> Co-authored-by: xinwen <coderWen@126.com> Co-authored-by: 老广 <ibuler@qq.com>
This commit is contained in:
@@ -2,7 +2,10 @@ import logging
|
||||
from functools import reduce
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db.models import F
|
||||
|
||||
from common.db.models import ChoiceSet
|
||||
from orgs.mixins.models import OrgModelMixin
|
||||
from common.db import models
|
||||
from common.utils import lazyproperty
|
||||
from assets.models import Asset, SystemUser, Node, FamilyMixin
|
||||
@@ -11,7 +14,7 @@ from .base import BasePermission
|
||||
|
||||
|
||||
__all__ = [
|
||||
'AssetPermission', 'Action', 'UserGrantedMappingNode', 'RebuildUserTreeTask',
|
||||
'AssetPermission', 'Action', 'PermNode', 'UserAssetGrantedTreeNodeRelation',
|
||||
]
|
||||
|
||||
# 使用场景
|
||||
@@ -135,39 +138,109 @@ class AssetPermission(BasePermission):
|
||||
from assets.models import Node
|
||||
nodes_keys = self.nodes.all().values_list('key', flat=True)
|
||||
assets_ids = set(self.assets.all().values_list('id', flat=True))
|
||||
nodes_assets_ids = Node.get_nodes_all_assets_ids(nodes_keys)
|
||||
nodes_assets_ids = Node.get_nodes_all_assets_ids_by_keys(nodes_keys)
|
||||
assets_ids.update(nodes_assets_ids)
|
||||
assets = Asset.objects.filter(id__in=assets_ids)
|
||||
return assets
|
||||
|
||||
|
||||
class UserAssetGrantedTreeNodeRelation(OrgModelMixin, FamilyMixin, models.JMSBaseModel):
|
||||
class NodeFrom(ChoiceSet):
|
||||
granted = 'granted', 'Direct node granted'
|
||||
child = 'child', 'Have children node'
|
||||
asset = 'asset', 'Direct asset granted'
|
||||
|
||||
class UserGrantedMappingNode(FamilyMixin, models.JMSBaseModel):
|
||||
node = models.ForeignKey('assets.Node', default=None, on_delete=models.CASCADE,
|
||||
db_constraint=False, null=True, related_name='mapping_nodes')
|
||||
key = models.CharField(max_length=64, verbose_name=_("Key"), db_index=True) # '1:1:1:1'
|
||||
user = models.ForeignKey('users.User', db_constraint=False, on_delete=models.CASCADE)
|
||||
granted = models.BooleanField(default=False, db_index=True)
|
||||
asset_granted = models.BooleanField(default=False, db_index=True)
|
||||
parent_key = models.CharField(max_length=64, default='', verbose_name=_('Parent key'), db_index=True) # '1:1:1:1'
|
||||
assets_amount = models.IntegerField(default=0)
|
||||
node = models.ForeignKey('assets.Node', default=None, on_delete=models.CASCADE,
|
||||
db_constraint=False, null=False, related_name='granted_node_rels')
|
||||
node_key = models.CharField(max_length=64, verbose_name=_("Key"), db_index=True)
|
||||
node_parent_key = models.CharField(max_length=64, default='', verbose_name=_('Parent key'), db_index=True)
|
||||
node_from = models.CharField(choices=NodeFrom.choices, max_length=16, db_index=True)
|
||||
node_assets_amount = models.IntegerField(default=0)
|
||||
|
||||
GRANTED_DIRECT = 1
|
||||
GRANTED_INDIRECT = 2
|
||||
GRANTED_NONE = 0
|
||||
@property
|
||||
def key(self):
|
||||
return self.node_key
|
||||
|
||||
@property
|
||||
def parent_key(self):
|
||||
return self.node_parent_key
|
||||
|
||||
@classmethod
|
||||
def get_node_granted_status(cls, key, user):
|
||||
ancestor_keys = Node.get_node_ancestor_keys(key, with_self=True)
|
||||
has_granted = UserGrantedMappingNode.objects.filter(
|
||||
key__in=ancestor_keys, user=user
|
||||
).values_list('granted', flat=True)
|
||||
if not has_granted:
|
||||
return cls.GRANTED_NONE
|
||||
if any(list(has_granted)):
|
||||
return cls.GRANTED_DIRECT
|
||||
return cls.GRANTED_INDIRECT
|
||||
def get_node_granted_status(cls, user, key):
|
||||
ancestor_keys = set(cls.get_node_ancestor_keys(key, with_self=True))
|
||||
ancestor_rel_nodes = cls.objects.filter(user=user, node_key__in=ancestor_keys)
|
||||
|
||||
for rel_node in ancestor_rel_nodes:
|
||||
if rel_node.key == key:
|
||||
return rel_node.node_from, rel_node
|
||||
if rel_node.node_from == cls.NodeFrom.granted:
|
||||
return cls.NodeFrom.granted, None
|
||||
return '', None
|
||||
|
||||
|
||||
class RebuildUserTreeTask(models.JMSBaseModel):
|
||||
user = models.ForeignKey('users.User', on_delete=models.CASCADE, verbose_name=_('User'))
|
||||
class PermNode(Node):
|
||||
class Meta:
|
||||
proxy = True
|
||||
ordering = []
|
||||
|
||||
# 特殊节点
|
||||
UNGROUPED_NODE_KEY = 'ungrouped'
|
||||
UNGROUPED_NODE_VALUE = _('Ungrouped')
|
||||
FAVORITE_NODE_KEY = 'favorite'
|
||||
FAVORITE_NODE_VALUE = _('Favorite')
|
||||
|
||||
node_from = ''
|
||||
granted_assets_amount = 0
|
||||
|
||||
# 提供可以设置 资产数量的字段
|
||||
_assets_amount = None
|
||||
|
||||
annotate_granted_node_rel_fields = {
|
||||
'granted_assets_amount': F('granted_node_rels__node_assets_amount'),
|
||||
'node_from': F('granted_node_rels__node_from')
|
||||
}
|
||||
|
||||
@property
|
||||
def assets_amount(self):
|
||||
_assets_amount = getattr(self, '_assets_amount')
|
||||
if isinstance(_assets_amount, int):
|
||||
return _assets_amount
|
||||
return super().assets_amount
|
||||
|
||||
@assets_amount.setter
|
||||
def assets_amount(self, value):
|
||||
self._assets_amount = value
|
||||
|
||||
def use_granted_assets_amount(self):
|
||||
self.assets_amount = self.granted_assets_amount
|
||||
|
||||
@classmethod
|
||||
def get_ungrouped_node(cls, assets_amount):
|
||||
return cls(
|
||||
id=cls.UNGROUPED_NODE_KEY,
|
||||
key=cls.UNGROUPED_NODE_KEY,
|
||||
value=cls.UNGROUPED_NODE_VALUE,
|
||||
assets_amount=assets_amount
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_favorite_node(cls, assets_amount):
|
||||
node = cls(
|
||||
id=cls.FAVORITE_NODE_KEY,
|
||||
key=cls.FAVORITE_NODE_KEY,
|
||||
value=cls.FAVORITE_NODE_VALUE,
|
||||
)
|
||||
node.assets_amount = assets_amount
|
||||
return node
|
||||
|
||||
def get_granted_status(self, user):
|
||||
status, rel_node = UserAssetGrantedTreeNodeRelation.get_node_granted_status(user, self.key)
|
||||
self.node_from = status
|
||||
if rel_node:
|
||||
self.granted_assets_amount = rel_node.node_assets_amount
|
||||
return status
|
||||
|
||||
def save(self):
|
||||
# 这是个只读 Model
|
||||
raise NotImplementedError
|
||||
|
Reference in New Issue
Block a user