diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py
index c294ff2ed..259405104 100644
--- a/apps/assets/models/node.py
+++ b/apps/assets/models/node.py
@@ -10,7 +10,7 @@ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from django.core.cache import cache
-from common.utils import get_logger
+from common.utils import get_logger, timeit
from orgs.mixins.models import OrgModelMixin, OrgManager
from orgs.utils import set_current_org, get_current_org, tmp_to_org
from orgs.models import Organization
@@ -298,14 +298,15 @@ class NodeAssetsMixin:
return self.get_all_assets().valid()
@classmethod
+ @timeit
def get_nodes_all_assets(cls, nodes_keys):
from .asset import Asset
nodes_keys = cls.clean_children_keys(nodes_keys)
- pattern = set()
+ assets_ids = set()
for key in nodes_keys:
- pattern.add(r'^{0}$|^{0}:'.format(key))
- pattern = '|'.join(list(pattern))
- return Asset.objects.filter(nodes__key__regex=pattern)
+ node_assets_ids = cls.tree().all_assets(key)
+ assets_ids.update(set(node_assets_ids))
+ return Asset.objects.filter(id__in=assets_ids)
class SomeNodesMixin:
diff --git a/apps/assets/signals_handler.py b/apps/assets/signals_handler.py
index 2c980d22c..ea5f8f4ad 100644
--- a/apps/assets/signals_handler.py
+++ b/apps/assets/signals_handler.py
@@ -7,13 +7,14 @@ from django.db.models.signals import (
from django.db.models.aggregates import Count
from django.dispatch import receiver
-from common.utils import get_logger
+from common.utils import get_logger, timeit
from common.decorator import on_transaction_commit
from .models import Asset, SystemUser, Node
from .tasks import (
update_assets_hardware_info_util,
test_asset_connectivity_util,
- push_system_user_to_assets
+ push_system_user_to_assets,
+ add_nodes_assets_to_system_users
)
@@ -99,7 +100,7 @@ def on_system_user_nodes_change(sender, instance=None, action=None, model=None,
"""
if action != "post_add":
return
- logger.info("System user `{}` nodes update signal recv".format(instance))
+ logger.info("System user nodes update signal recv: {}".format(instance))
queryset = model.objects.filter(pk__in=pk_set)
if model == Node:
@@ -108,9 +109,7 @@ def on_system_user_nodes_change(sender, instance=None, action=None, model=None,
else:
nodes_keys = [instance.key]
system_users = queryset
- assets = Node.get_nodes_all_assets(nodes_keys).values_list('id', flat=True)
- for system_user in system_users:
- system_user.assets.add(*tuple(assets))
+ add_nodes_assets_to_system_users.delay(nodes_keys, system_users)
@receiver(m2m_changed, sender=Asset.nodes.through)
diff --git a/apps/assets/tasks/__init__.py b/apps/assets/tasks/__init__.py
index eb8c5a7b9..6f53c9fa2 100644
--- a/apps/assets/tasks/__init__.py
+++ b/apps/assets/tasks/__init__.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
#
from .utils import *
+from .common import *
from .admin_user_connectivity import *
from .asset_connectivity import *
from .asset_user_connectivity import *
diff --git a/apps/assets/tasks/common.py b/apps/assets/tasks/common.py
new file mode 100644
index 000000000..2c352b64e
--- /dev/null
+++ b/apps/assets/tasks/common.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+#
+
+from celery import shared_task
+
+__all__ = ['add_nodes_assets_to_system_users']
+
+
+@shared_task
+def add_nodes_assets_to_system_users(nodes_keys, system_users):
+ from ..models import Node
+ assets = Node.get_nodes_all_assets(nodes_keys).values_list('id', flat=True)
+ for system_user in system_users:
+ system_user.assets.add(*tuple(assets))
diff --git a/apps/assets/templates/assets/user_asset_list.html b/apps/assets/templates/assets/user_asset_list.html
index cd268a699..a158244a5 100644
--- a/apps/assets/templates/assets/user_asset_list.html
+++ b/apps/assets/templates/assets/user_asset_list.html
@@ -24,7 +24,7 @@
var treeUrl = "{% url 'api-perms:my-nodes-children-as-tree' %}?&cache_policy=1";
var assetTableUrl = "{% url 'api-perms:my-assets' %}?cache_policy=1";
var selectUrl = '{% url "api-perms:my-node-assets" node_id=DEFAULT_PK %}?cache_policy=1&all=1';
-var systemUsersUrl = "{% url 'api-perms:my-asset-system-users' asset_id=DEFAULT_PK %}";
+var systemUsersUrl = "{% url 'api-perms:my-asset-system-users' asset_id=DEFAULT_PK %}?cache_policy=1";
var showAssetHref = false; // Need input default true
var actions = {
targets: 4, createdCell: function (td, cellData) {
diff --git a/apps/common/utils/common.py b/apps/common/utils/common.py
index c73e9611d..667f166b3 100644
--- a/apps/common/utils/common.py
+++ b/apps/common/utils/common.py
@@ -213,3 +213,16 @@ def dict_get_any(d, keys):
if value:
return value
return None
+
+
+class lazyproperty:
+ def __init__(self, func):
+ self.func = func
+
+ def __get__(self, instance, cls):
+ if instance is None:
+ return self
+ else:
+ value = self.func(instance)
+ setattr(instance, self.func.__name__, value)
+ return value
\ No newline at end of file
diff --git a/apps/perms/api/asset_permission.py b/apps/perms/api/asset_permission.py
index 3e7f4a078..c5745b84a 100644
--- a/apps/perms/api/asset_permission.py
+++ b/apps/perms/api/asset_permission.py
@@ -180,6 +180,7 @@ class AssetPermissionRemoveUserApi(RetrieveUpdateAPIView):
users = serializer.validated_data.get('users')
if users:
perm.users.remove(*tuple(users))
+ perm.save()
return Response({"msg": "ok"})
else:
return Response({"error": serializer.errors})
@@ -197,6 +198,7 @@ class AssetPermissionAddUserApi(RetrieveUpdateAPIView):
users = serializer.validated_data.get('users')
if users:
perm.users.add(*tuple(users))
+ perm.save()
return Response({"msg": "ok"})
else:
return Response({"error": serializer.errors})
@@ -217,6 +219,7 @@ class AssetPermissionRemoveAssetApi(RetrieveUpdateAPIView):
assets = serializer.validated_data.get('assets')
if assets:
perm.assets.remove(*tuple(assets))
+ perm.save()
return Response({"msg": "ok"})
else:
return Response({"error": serializer.errors})
@@ -234,6 +237,7 @@ class AssetPermissionAddAssetApi(RetrieveUpdateAPIView):
assets = serializer.validated_data.get('assets')
if assets:
perm.assets.add(*tuple(assets))
+ perm.save()
return Response({"msg": "ok"})
else:
return Response({"error": serializer.errors})
diff --git a/apps/perms/api/user_permission/common.py b/apps/perms/api/user_permission/common.py
index 6a2f8adf7..7e4271af8 100644
--- a/apps/perms/api/user_permission/common.py
+++ b/apps/perms/api/user_permission/common.py
@@ -51,8 +51,7 @@ class GetUserAssetPermissionActionsApi(UserAssetPermissionMixin,
asset = get_object_or_404(Asset, id=asset_id)
system_user = get_object_or_404(SystemUser, id=system_id)
- system_users_actions = self.util.get_asset_system_users_with_actions(
- asset)
+ system_users_actions = self.util.get_asset_system_users_with_actions(asset)
actions = system_users_actions.get(system_user)
return {"actions": actions}
@@ -103,8 +102,7 @@ class UserGrantedAssetSystemUsersApi(UserAssetPermissionMixin, ListAPIView):
def get_queryset(self):
asset_id = self.kwargs.get('asset_id')
asset = get_object_or_404(Asset, id=asset_id)
- system_users_with_actions = self.util.get_asset_system_users_with_actions(
- asset)
+ system_users_with_actions = self.util.get_asset_system_users_with_actions(asset)
system_users = []
for system_user, actions in system_users_with_actions.items():
system_user.actions = actions
diff --git a/apps/perms/api/user_permission/mixin.py b/apps/perms/api/user_permission/mixin.py
index 9ca8c5e7d..a25e49251 100644
--- a/apps/perms/api/user_permission/mixin.py
+++ b/apps/perms/api/user_permission/mixin.py
@@ -1,23 +1,27 @@
# -*- coding: utf-8 -*-
#
+from common.utils import lazyproperty
+from common.tree import TreeNodeSerializer
from ..mixin import UserPermissionMixin
from ...utils import AssetPermissionUtilV2, ParserNode
from ...hands import Node, Asset
-from common.tree import TreeNodeSerializer
class UserAssetPermissionMixin(UserPermissionMixin):
util = None
- tree = None
- def initial(self, *args, **kwargs):
- super().initial(*args, *kwargs)
+ @lazyproperty
+ def util(self):
cache_policy = self.request.query_params.get('cache_policy', '0')
system_user_id = self.request.query_params.get("system_user")
- self.util = AssetPermissionUtilV2(self.obj, cache_policy=cache_policy)
+ util = AssetPermissionUtilV2(self.obj, cache_policy=cache_policy)
if system_user_id:
- self.util.filter_permissions(system_users=system_user_id)
- self.tree = self.util.get_user_tree()
+ util.filter_permissions(system_users=system_user_id)
+ return util
+
+ @lazyproperty
+ def tree(self):
+ return self.util.get_user_tree()
class UserNodeTreeMixin:
diff --git a/apps/perms/signals_handler.py b/apps/perms/signals_handler.py
index 8066ce5ca..eecd101e8 100644
--- a/apps/perms/signals_handler.py
+++ b/apps/perms/signals_handler.py
@@ -19,18 +19,6 @@ permission_m2m_senders = (
)
-@on_transaction_commit
-def on_permission_m2m_change(sender, action='', **kwargs):
- if not action.startswith('post'):
- return
- logger.debug('Asset permission m2m changed, refresh user tree cache')
- AssetPermissionUtilV2.expire_all_user_tree_cache()
-
-
-for sender in permission_m2m_senders:
- m2m_changed.connect(on_permission_m2m_change, sender=sender)
-
-
@receiver([post_save, post_delete], sender=AssetPermission)
@on_transaction_commit
def on_permission_change(sender, action='', **kwargs):
diff --git a/apps/perms/utils/asset_permission.py b/apps/perms/utils/asset_permission.py
index ed3616933..f472a162a 100644
--- a/apps/perms/utils/asset_permission.py
+++ b/apps/perms/utils/asset_permission.py
@@ -1,7 +1,7 @@
# coding: utf-8
+import time
import pickle
-import threading
from collections import defaultdict
from functools import reduce
from hashlib import md5
@@ -12,7 +12,7 @@ from django.db.models import Q
from django.conf import settings
from orgs.utils import set_to_root_org
-from common.utils import get_logger, timeit
+from common.utils import get_logger, timeit, lazyproperty
from common.tree import TreeNode
from assets.utils import TreeService
from ..models import AssetPermission
@@ -131,18 +131,19 @@ class AssetPermissionUtilV2(AssetPermissionUtilCacheMixin):
self.cache_policy = cache_policy
self.obj_id = str(obj.id) if obj else None
self._permissions = None
- self._permissions_id = None # 标记_permission的唯一值
self._filter_id = 'None' # 当通过filter更改 permission是标记
self.change_org_if_need()
self._user_tree = None
self._user_tree_filter_id = 'None'
- self.full_tree = Node.tree()
- self.mutex = threading.Lock()
@staticmethod
def change_org_if_need():
set_to_root_org()
+ @lazyproperty
+ def full_tree(self):
+ return Node.tree()
+
@property
def permissions(self):
if self._permissions:
@@ -161,7 +162,7 @@ class AssetPermissionUtilV2(AssetPermissionUtilCacheMixin):
self._permissions = self.permissions.filter(**filters)
self._filter_id = md5(filters_json.encode()).hexdigest()
- @property
+ @lazyproperty
def user_tree(self):
return self.get_user_tree()
@@ -305,27 +306,26 @@ class AssetPermissionUtilV2(AssetPermissionUtilCacheMixin):
@timeit
def get_user_tree(self):
# 使用锁,保证多次获取tree的时候顺序执行,可以使用缓存
- with self.mutex:
- user_tree = self.get_user_tree_from_local()
- if user_tree:
- return user_tree
- user_tree = self.get_user_tree_from_cache_if_need()
- if user_tree:
- self.set_user_tree_to_local(user_tree)
- return user_tree
- user_tree = TreeService()
- full_tree_root = self.full_tree.root_node()
- user_tree.create_node(
- tag=full_tree_root.tag,
- identifier=full_tree_root.identifier
- )
- self.add_direct_nodes_to_user_tree(user_tree)
- self.add_single_assets_node_to_user_tree(user_tree)
- self.parse_user_tree_to_full_tree(user_tree)
- self.add_empty_node_if_need(user_tree)
- self.set_user_tree_to_cache_if_need(user_tree)
+ user_tree = self.get_user_tree_from_local()
+ if user_tree:
+ return user_tree
+ user_tree = self.get_user_tree_from_cache_if_need()
+ if user_tree:
self.set_user_tree_to_local(user_tree)
return user_tree
+ user_tree = TreeService()
+ full_tree_root = self.full_tree.root_node()
+ user_tree.create_node(
+ tag=full_tree_root.tag,
+ identifier=full_tree_root.identifier
+ )
+ self.add_direct_nodes_to_user_tree(user_tree)
+ self.add_single_assets_node_to_user_tree(user_tree)
+ self.parse_user_tree_to_full_tree(user_tree)
+ self.add_empty_node_if_need(user_tree)
+ self.set_user_tree_to_cache_if_need(user_tree)
+ self.set_user_tree_to_local(user_tree)
+ return user_tree
# Todo: 是否可以获取多个资产的系统用户
def get_asset_system_users_with_actions(self, asset):
diff --git a/apps/users/templates/users/_granted_assets.html b/apps/users/templates/users/_granted_assets.html
index 173aec607..eabff1487 100644
--- a/apps/users/templates/users/_granted_assets.html
+++ b/apps/users/templates/users/_granted_assets.html
@@ -72,16 +72,10 @@ function initTable() {
$(td).html(cellData);
}},
{targets: 3, createdCell: function (td, cellData) {
- function success(systemUsers) {
- var users = [];
- $.each(systemUsers, function (id, data) {
- var name = htmlEscape(data.name);
- users.push(name);
- });
- $(td).html(users.join(','))
- }
- $(td).html("{% trans 'Loading' %}");
- getGrantedAssetSystemUsers(cellData, success)
+ var innerHtml = ' {% trans "Show" %} '
+ .replace('99999999', cellData);
+ $(td).html(innerHtml);
+
}},
],
ajax_url: assetTableUrl,
@@ -185,5 +179,19 @@ $(document).ready(function () {
var val = $(this).text();
$("#user_assets_table_filter input").val(val);
assetTable.search(val).draw();
- })
+}).on('click', '.btn-show-system-users', function () {
+ var $this = $(this);
+ var assetId = $this.data('aid');
+
+ function success(systemUsers) {
+ var users = [];
+ $.each(systemUsers, function (id, data) {
+ var name = htmlEscape(data.name);
+ users.push(name);
+ });
+ $this.parent().html(users.join(','))
+ }
+
+ getGrantedAssetSystemUsers(assetId, success)
+})
diff --git a/apps/users/templates/users/user_granted_asset.html b/apps/users/templates/users/user_granted_asset.html
index d70418081..184537cd4 100644
--- a/apps/users/templates/users/user_granted_asset.html
+++ b/apps/users/templates/users/user_granted_asset.html
@@ -33,9 +33,9 @@
{% block custom_foot_js %}