diff --git a/apps/assets/templates/assets/_asset_user_list.html b/apps/assets/templates/assets/_asset_user_list.html
index 52cd94b52..fda69e5d8 100644
--- a/apps/assets/templates/assets/_asset_user_list.html
+++ b/apps/assets/templates/assets/_asset_user_list.html
@@ -60,8 +60,8 @@ function initAssetUserTable() {
},
{
targets: 6, createdCell: function (td, cellData) {
- var date = new Date(cellData);
- $(td).html(date.toLocaleString());
+ var data = formatDateAsCN(cellData);
+ $(td).html(data);
},
},
{
diff --git a/apps/assets/templates/assets/system_user_list.html b/apps/assets/templates/assets/system_user_list.html
index 176744212..50d294026 100644
--- a/apps/assets/templates/assets/system_user_list.html
+++ b/apps/assets/templates/assets/system_user_list.html
@@ -15,27 +15,27 @@
{% block table_search %}
+
+
+
+
+
{% endblock %}
{% block table_container %}
diff --git a/apps/common/apps.py b/apps/common/apps.py
index d5a78046e..9d4d80677 100644
--- a/apps/common/apps.py
+++ b/apps/common/apps.py
@@ -6,11 +6,12 @@ from django.dispatch import receiver
from django.db.backends.signals import connection_created
-@receiver(connection_created, dispatch_uid="my_unique_identifier")
+@receiver(connection_created)
def on_db_connection_ready(sender, **kwargs):
from .signals import django_ready
if 'migrate' not in sys.argv:
django_ready.send(CommonConfig)
+ connection_created.disconnect(on_db_connection_ready)
class CommonConfig(AppConfig):
diff --git a/apps/orgs/models.py b/apps/orgs/models.py
index 2547e373c..7f44c861c 100644
--- a/apps/orgs/models.py
+++ b/apps/orgs/models.py
@@ -21,6 +21,7 @@ class Organization(models.Model):
ROOT_NAME = 'ROOT'
DEFAULT_ID = 'DEFAULT'
DEFAULT_NAME = 'DEFAULT'
+ _user_admin_orgs = None
class Meta:
verbose_name = _("Organization")
@@ -92,6 +93,8 @@ class Organization(models.Model):
@classmethod
def get_user_admin_orgs(cls, user):
+ if cls._user_admin_orgs and user.id in cls._user_admin_orgs:
+ return cls._user_admin_orgs[user.id]
admin_orgs = []
if user.is_anonymous:
return admin_orgs
@@ -100,6 +103,11 @@ class Organization(models.Model):
admin_orgs.append(cls.default())
elif user.is_org_admin:
admin_orgs = user.admin_orgs.all()
+
+ if cls._user_admin_orgs is None:
+ cls._user_admin_orgs = {user.id: admin_orgs}
+ else:
+ cls._user_admin_orgs[user.id] = admin_orgs
return admin_orgs
@classmethod
diff --git a/apps/orgs/signals_handler.py b/apps/orgs/signals_handler.py
index 42387ccde..9d3c8882f 100644
--- a/apps/orgs/signals_handler.py
+++ b/apps/orgs/signals_handler.py
@@ -41,3 +41,8 @@ def on_org_user_changed(sender, instance=None, **kwargs):
for user_group in user_groups:
user_group.users.remove(user)
set_current_org(old_org)
+
+
+@receiver(m2m_changed, sender=Organization.admins.through)
+def on_org_admin_change(sender, **kwargs):
+ Organization._user_admin_orgs = None
diff --git a/apps/perms/api/user_permission.py b/apps/perms/api/user_permission.py
index 666b7f55a..377b39722 100644
--- a/apps/perms/api/user_permission.py
+++ b/apps/perms/api/user_permission.py
@@ -263,6 +263,7 @@ class UserGrantedNodesWithAssetsAsTreeApi(UserPermissionCacheMixin, ListAPIView)
system_users=self.system_user_id
)
nodes = util.get_nodes_with_assets()
+ print(list(nodes.keys()))
for node, assets in nodes.items():
data = parse_node_to_tree_node(node)
queryset.append(data)
diff --git a/apps/perms/utils/asset_permission.py b/apps/perms/utils/asset_permission.py
index 4f2b8561f..c26047ff4 100644
--- a/apps/perms/utils/asset_permission.py
+++ b/apps/perms/utils/asset_permission.py
@@ -180,7 +180,7 @@ class GenerateTree:
return dict(nodes)
def get_nodes(self):
- return self.nodes.keys()
+ return list(self.nodes.keys())
def get_user_permissions(user, include_group=True):
@@ -256,9 +256,13 @@ class AssetPermissionCacheMixin:
)
@property
- def node_key(self):
+ def node_asset_key(self):
return self.get_cache_key('NODES_WITH_ASSETS')
+ @property
+ def node_key(self):
+ return self.get_cache_key('NODES')
+
@property
def asset_key(self):
key = self.get_cache_key('ASSETS')
@@ -268,54 +272,47 @@ class AssetPermissionCacheMixin:
def system_key(self):
return self.get_cache_key('SYSTEM_USER')
- def get_assets_from_cache(self):
- cached = cache.get(self.asset_key)
+ def get_resource_from_cache(self, resource):
+ key_map = {
+ "assets": self.asset_key,
+ "nodes": self.node_key,
+ "nodes_with_assets": self.node_asset_key,
+ "system_users": self.system_key
+ }
+ key = key_map.get(resource)
+ if not key:
+ raise ValueError("Not a valid resource: {}".format(resource))
+ cached = cache.get(key)
if not cached:
self.update_cache()
- cached = cache.get(self.asset_key)
+ cached = cache.get(key)
return cached
- def get_nodes_with_assets_from_cache(self):
- cached = cache.get(self.node_key)
- if not cached:
- self.update_cache()
- cached = cache.get(self.node_key)
- return cached
+ def get_resource(self, resource):
+ if self._is_using_cache():
+ return self.get_resource_from_cache(resource)
+ elif self._is_refresh_cache():
+ self.expire_cache()
+ data = self.get_resource_from_cache(resource)
+ return data
+ else:
+ return self.get_resource_without_cache(resource)
+
+ def get_resource_without_cache(self, resource):
+ attr = 'get_{}_without_cache'.format(resource)
+ return getattr(self, attr)()
def get_nodes_with_assets(self):
- if self._is_using_cache():
- return self.get_nodes_with_assets_from_cache()
- elif self._is_refresh_cache():
- self.expire_cache()
- return self.get_nodes_with_assets_from_cache()
- else:
- return self.get_nodes_with_assets_without_cache()
-
- def get_system_user_from_cache(self):
- cached = cache.get(self.system_key)
- if not cached:
- self.update_cache()
- cached = cache.get(self.system_key)
- return cached
+ return self.get_resource("nodes_with_assets")
def get_assets(self):
- if self._is_using_cache():
- return self.get_assets_from_cache()
- elif self._is_refresh_cache():
- self.expire_cache()
- return self.get_assets_from_cache()
- else:
- self.expire_cache()
- return self.get_assets_without_cache()
+ return self.get_resource("assets")
+
+ def get_nodes(self):
+ return self.get_resource("nodes")
def get_system_users(self):
- if self._is_using_cache():
- return self.get_system_user_from_cache()
- elif self._is_refresh_cache():
- self.expire_cache()
- return self.get_system_user_from_cache()
- else:
- return self.get_system_user_without_cache()
+ return self.get_resource("system_users")
def get_meta_cache_key(self):
cache_key = self.CACHE_META_KEY_PREFIX + '{obj_id}_{filter_id}'
@@ -332,6 +329,17 @@ class AssetPermissionCacheMixin:
# print("Meta id: {}".format(meta["id"]))
return meta
+ def update_cache(self):
+ assets = self.get_resource_without_cache("assets")
+ nodes_with_assets = self.get_resource_without_cache("nodes_with_assets")
+ system_users = self.get_resource_without_cache("system_users")
+ nodes = self.get_resource_without_cache("nodes")
+ cache.set(self.asset_key, assets, self.CACHE_TIME)
+ cache.set(self.node_asset_key, nodes_with_assets, self.CACHE_TIME)
+ cache.set(self.system_key, system_users, self.CACHE_TIME)
+ cache.set(self.node_key, nodes, self.CACHE_TIME)
+ self.set_meta_to_cache()
+
def set_meta_to_cache(self):
key = self.get_meta_cache_key()
meta = {
@@ -348,15 +356,6 @@ class AssetPermissionCacheMixin:
key = cache_key.format(obj_id=self.obj_id)
cache.delete_pattern(key)
- def update_cache(self):
- assets = self.get_assets_without_cache()
- nodes = self.get_nodes_with_assets_without_cache()
- system_users = self.get_system_user_without_cache()
- cache.set(self.asset_key, assets, self.CACHE_TIME)
- cache.set(self.node_key, nodes, self.CACHE_TIME)
- cache.set(self.system_key, system_users, self.CACHE_TIME)
- self.set_meta_to_cache()
-
def expire_cache(self):
"""
因为 获取用户的节点,资产,系统用户等都能会缓存,这里会清理所有与该对象有关的
@@ -378,15 +377,6 @@ class AssetPermissionCacheMixin:
key = cls.CACHE_KEY_PREFIX + '*'
cache.delete_pattern(key)
- def get_assets_without_cache(self):
- raise NotImplementedError()
-
- def get_nodes_with_assets_without_cache(self):
- raise NotImplementedError()
-
- def get_system_user_without_cache(self):
- raise NotImplementedError()
-
class AssetPermissionUtil(AssetPermissionCacheMixin):
get_permissions_map = {
@@ -396,8 +386,10 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
"Node": get_node_permissions,
"SystemUser": get_system_user_permissions,
}
- assets_prefetch = ('id', 'hostname', 'ip', "platform", "domain_id",
- "comment", "is_active", "os", "org_id")
+ assets_only = (
+ 'id', 'hostname', 'ip', "platform", "domain_id",
+ 'comment', 'is_active', 'os', 'org_id'
+ )
def __init__(self, obj, cache_policy='0'):
self.object = obj
@@ -411,6 +403,8 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
self.change_org_if_need()
self.nodes = None
self._nodes = None
+ self._assets_direct = None
+ self._nodes_direct = None
@staticmethod
def change_org_if_need():
@@ -438,6 +432,8 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
返回用户/组授权规则直接关联的节点
:return: {node1: {system_user1: {'actions': set()},}}
"""
+ if self._nodes_direct:
+ return self._nodes_direct
nodes = defaultdict(lambda: defaultdict(int))
for perm in self.permissions:
actions = [perm.actions]
@@ -446,9 +442,10 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
for node, system_user, action in itertools.product(_nodes, system_users, actions):
nodes[node][system_user] |= action
self.tree.add_nodes(nodes)
+ self._nodes_direct = nodes
return nodes
- def get_nodes(self):
+ def get_nodes_without_cache(self):
self.get_assets_direct()
return self.tree.get_nodes()
@@ -458,15 +455,18 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
返回用户授权规则直接关联的资产
:return: {asset1: {system_user1: 1,}}
"""
+ if self._assets_direct:
+ return self._assets_direct
assets = defaultdict(lambda: defaultdict(int))
for perm in self.permissions:
actions = [perm.actions]
- _assets = perm.assets.all().prefetch_related(*self.assets_prefetch)
+ _assets = perm.assets.all().only(*self.assets_only)
system_users = perm.system_users.all()
iterable = itertools.product(_assets, system_users, actions)
for asset, system_user, action in iterable:
assets[asset][system_user] |= action
self.tree.add_assets(assets)
+ self._assets_direct = assets
return assets
#@timeit
@@ -476,6 +476,7 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
"""
if self._assets:
return self._assets
+ self.get_assets_direct()
nodes = self.get_nodes_direct()
pattern = set()
for node in nodes:
@@ -484,7 +485,7 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
if pattern:
assets = Asset.objects.filter(nodes__key__regex=pattern)\
.prefetch_related('nodes', "protocols")\
- .only(*self.assets_prefetch)\
+ .only(*self.assets_only)\
.distinct()
else:
assets = []
@@ -501,9 +502,11 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
:return:
"""
self.get_assets_without_cache()
- return self.tree.get_nodes_with_assets()
+ nodes_assets = self.tree.get_nodes_with_assets()
+ print(nodes_assets.keys())
+ return nodes_assets
- def get_system_user_without_cache(self):
+ def get_system_users_without_cache(self):
system_users = set()
permissions = self.permissions.prefetch_related('system_users')
for perm in permissions:
diff --git a/apps/settings/signals_handler.py b/apps/settings/signals_handler.py
index 9302b63e2..cb7603ec7 100644
--- a/apps/settings/signals_handler.py
+++ b/apps/settings/signals_handler.py
@@ -24,6 +24,7 @@ def refresh_settings_on_changed(sender, instance=None, **kwargs):
@receiver(django_ready, dispatch_uid="my_unique_identifier")
def monkey_patch_settings(sender, **kwargs):
+ logger.debug("Monkey patch settings")
cache_key_prefix = '_SETTING_'
custom_need_cache_settings = [
'AUTHENTICATION_BACKENDS', 'TERMINAL_HOST_KEY',
@@ -77,7 +78,6 @@ def monkey_patch_settings(sender, **kwargs):
@receiver(django_ready)
def auto_generate_terminal_host_key(sender, **kwargs):
try:
- print("Auto gen host key")
if Setting.objects.filter(name='TERMINAL_HOST_KEY').exists():
return
private_key, public_key = ssh_key_gen()
diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js
index 5f85d5e42..471cb00a4 100644
--- a/apps/static/js/jumpserver.js
+++ b/apps/static/js/jumpserver.js
@@ -648,8 +648,6 @@ jumpserver.initServerSideDataTable = function (options) {
$.each(rows, function (id, row) {
table.selected_rows.push(row);
if (row.id && $.inArray(row.id, table.selected) === -1){
- console.log(table)
- console.log(table.selected);
table.selected.push(row.id)
}
})
@@ -1096,3 +1094,8 @@ function objectAttrsIsBool(obj, attrs) {
}
})
}
+
+function formatDateAsCN(d) {
+ var date = new Date(d);
+ return date.toISOString().replace("T", " ").replace(/\..*/, "");
+}
diff --git a/apps/terminal/api/session.py b/apps/terminal/api/session.py
index 93628af22..04f97bfc3 100644
--- a/apps/terminal/api/session.py
+++ b/apps/terminal/api/session.py
@@ -55,7 +55,7 @@ class SessionViewSet(BulkModelViewSet):
return super().perform_create(serializer)
-class CommandViewSet(viewsets.ViewSet):
+class CommandViewSet(viewsets.ModelViewSet):
"""接受app发送来的command log, 格式如下
{
"user": "admin",
@@ -70,10 +70,14 @@ class CommandViewSet(viewsets.ViewSet):
"""
command_store = get_command_storage()
serializer_class = SessionCommandSerializer
+ pagination_class = LimitOffsetPagination
permission_classes = (IsOrgAdminOrAppUser | IsAuditor,)
+ filter_fields = ("asset", "system_user", "user", "input")
def get_queryset(self):
- self.command_store.filter(**dict(self.request.query_params))
+ multi_command_storage = get_multi_command_storage()
+ queryset = multi_command_storage.filter()
+ return queryset
def create(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data, many=True)
@@ -88,12 +92,6 @@ class CommandViewSet(viewsets.ViewSet):
logger.error(msg)
return Response({"msg": msg}, status=401)
- def list(self, request, *args, **kwargs):
- multi_command_storage = get_multi_command_storage()
- queryset = multi_command_storage.filter()
- serializer = self.serializer_class(queryset, many=True)
- return Response(serializer.data)
-
class SessionReplayViewSet(viewsets.ViewSet):
serializer_class = serializers.ReplaySerializer
diff --git a/apps/terminal/backends/command/multi.py b/apps/terminal/backends/command/multi.py
index 1ac822a81..0a4418c0d 100644
--- a/apps/terminal/backends/command/multi.py
+++ b/apps/terminal/backends/command/multi.py
@@ -9,8 +9,12 @@ class CommandStore(CommandBase):
self.storage_list = storage_list
def filter(self, **kwargs):
- queryset = []
+ if len(self.storage_list) == 1:
+ storage = list(self.storage_list)[0]
+ queryset = storage.filter(**kwargs)
+ return queryset
+ queryset = []
for storage in self.storage_list:
queryset.extend(storage.filter(**kwargs))
return sorted(queryset, key=lambda command: command.timestamp, reverse=True)
diff --git a/apps/terminal/templates/terminal/command_list.html b/apps/terminal/templates/terminal/command_list.html
index 50daf682d..1ce2d80a5 100644
--- a/apps/terminal/templates/terminal/command_list.html
+++ b/apps/terminal/templates/terminal/command_list.html
@@ -8,109 +8,65 @@
{% endblock %}
-{% block content_left_head %}
+{% block table_pagination %}
{% endblock %}
{% block table_search %}
-
{% endblock %}
{% block table_container %}
-