Commit 1448d23c authored by ibuler's avatar ibuler

[Update] 准备优化 asset user

parent cdbdc853
...@@ -20,6 +20,7 @@ from common.mixins import IDInCacheFilterMixin, ApiMessageMixin ...@@ -20,6 +20,7 @@ from common.mixins import IDInCacheFilterMixin, ApiMessageMixin
from common.utils import get_logger, get_object_or_none from common.utils import get_logger, get_object_or_none
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
from orgs.mixins import OrgBulkModelViewSet
from ..const import CACHE_KEY_ASSET_BULK_UPDATE_ID_PREFIX from ..const import CACHE_KEY_ASSET_BULK_UPDATE_ID_PREFIX
from ..models import Asset, AdminUser, Node from ..models import Asset, AdminUser, Node
from .. import serializers from .. import serializers
...@@ -36,7 +37,7 @@ __all__ = [ ...@@ -36,7 +37,7 @@ __all__ = [
] ]
class AssetViewSet(IDInCacheFilterMixin, LabelFilter, ApiMessageMixin, BulkModelViewSet): class AssetViewSet(LabelFilter, ApiMessageMixin, OrgBulkModelViewSet):
""" """
API endpoint that allows Asset to be viewed or edited. API endpoint that allows Asset to be viewed or edited.
""" """
...@@ -100,11 +101,6 @@ class AssetViewSet(IDInCacheFilterMixin, LabelFilter, ApiMessageMixin, BulkModel ...@@ -100,11 +101,6 @@ class AssetViewSet(IDInCacheFilterMixin, LabelFilter, ApiMessageMixin, BulkModel
queryset = self.filter_admin_user_id(queryset) queryset = self.filter_admin_user_id(queryset)
return queryset return queryset
def get_queryset(self):
queryset = super().get_queryset().distinct()
queryset = self.get_serializer_class().setup_eager_loading(queryset)
return queryset
class AssetListUpdateApi(IDInCacheFilterMixin, ListBulkCreateUpdateDestroyAPIView): class AssetListUpdateApi(IDInCacheFilterMixin, ListBulkCreateUpdateDestroyAPIView):
""" """
......
...@@ -127,15 +127,14 @@ class AssetUserAuthInfoApi(generics.RetrieveAPIView): ...@@ -127,15 +127,14 @@ class AssetUserAuthInfoApi(generics.RetrieveAPIView):
return Response(serializer.data, status=status_code) return Response(serializer.data, status=status_code)
def get_object(self): def get_object(self):
username = self.request.GET.get('username') query_params = self.request.query_params
asset_id = self.request.GET.get('asset_id') username = query_params.get('username')
prefer = self.request.GET.get("prefer") asset_id = query_params.get('asset_id')
prefer = query_params.get("prefer")
asset = get_object_or_none(Asset, pk=asset_id) asset = get_object_or_none(Asset, pk=asset_id)
try: try:
manger = AssetUserManager() manger = AssetUserManager()
if prefer: instance = manger.get(username, asset, prefer=prefer)
manger.prefer(prefer)
instance = manger.get(username, asset)
except Exception as e: except Exception as e:
logger.error(e, exc_info=True) logger.error(e, exc_info=True)
return None return None
......
...@@ -22,6 +22,7 @@ from rest_framework.pagination import LimitOffsetPagination ...@@ -22,6 +22,7 @@ from rest_framework.pagination import LimitOffsetPagination
from common.utils import get_logger from common.utils import get_logger
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
from common.mixins import IDInCacheFilterMixin from common.mixins import IDInCacheFilterMixin
from orgs.mixins import OrgBulkModelViewSet
from ..models import SystemUser, Asset from ..models import SystemUser, Asset
from .. import serializers from .. import serializers
from ..tasks import push_system_user_to_assets_manual, \ from ..tasks import push_system_user_to_assets_manual, \
...@@ -39,7 +40,7 @@ __all__ = [ ...@@ -39,7 +40,7 @@ __all__ = [
] ]
class SystemUserViewSet(IDInCacheFilterMixin, BulkModelViewSet): class SystemUserViewSet(OrgBulkModelViewSet):
""" """
System user api set, for add,delete,update,list,retrieve resource System user api set, for add,delete,update,list,retrieve resource
""" """
......
...@@ -14,6 +14,11 @@ class AssetUserBackend(BaseBackend): ...@@ -14,6 +14,11 @@ class AssetUserBackend(BaseBackend):
@classmethod @classmethod
def filter(cls, username=None, assets=None, **kwargs): def filter(cls, username=None, assets=None, **kwargs):
queryset = cls.model.objects.all() queryset = cls.model.objects.all()
prefer_id = kwargs.get('prefer_id')
if prefer_id:
queryset = queryset.filter(id=prefer_id)
instances = cls.construct_authbook_objects(queryset, assets)
return instances
if username: if username:
queryset = queryset.filter(username=username) queryset = queryset.filter(username=username)
if assets: if assets:
......
...@@ -7,11 +7,13 @@ from abc import abstractmethod ...@@ -7,11 +7,13 @@ from abc import abstractmethod
class BaseBackend: class BaseBackend:
@classmethod @classmethod
@abstractmethod @abstractmethod
def filter(cls, username=None, assets=None, latest=True): def filter(cls, username=None, assets=None, latest=True, prefer=None, prefer_id=None):
""" """
:param username: 用户名 :param username: 用户名
:param assets: <Asset>对象 :param assets: <Asset>对象
:param latest: 是否是最新记录 :param latest: 是否是最新记录
:param prefer: 优先使用
:param prefer_id: 使用id
:return: 元素为<AuthBook>的可迭代对象(<list> or <QuerySet>) :return: 元素为<AuthBook>的可迭代对象(<list> or <QuerySet>)
""" """
pass pass
......
...@@ -7,7 +7,7 @@ from .base import BaseBackend ...@@ -7,7 +7,7 @@ from .base import BaseBackend
class AuthBookBackend(BaseBackend): class AuthBookBackend(BaseBackend):
@classmethod @classmethod
def filter(cls, username=None, assets=None, latest=True): def filter(cls, username=None, assets=None, latest=True, **kwargs):
queryset = AuthBook.objects.all() queryset = AuthBook.objects.all()
if username is not None: if username is not None:
queryset = queryset.filter(username=username) queryset = queryset.filter(username=username)
......
...@@ -30,24 +30,22 @@ class AssetUserManager: ...@@ -30,24 +30,22 @@ class AssetUserManager:
) )
_prefer = "system_user" _prefer = "system_user"
_using = None
def filter(self, username=None, assets=None, latest=True): def filter(self, username=None, assets=None, latest=True, prefer=None, prefer_id=None):
if assets is not None and not assets: if assets is not None and not assets:
return AssetUserQuerySet([]) return AssetUserQuerySet([])
if self._using: if prefer:
backend = dict(self.backends).get(self._using) self._prefer = prefer
if not backend:
return self.none()
instances = backend.filter(username=username, assets=assets, latest=latest)
return AssetUserQuerySet(instances)
instances_map = {} instances_map = {}
instances = [] instances = []
for name, backend in self.backends: for name, backend in self.backends:
if name != "db" and self._prefer != name:
continue
_instances = backend.filter( _instances = backend.filter(
username=username, assets=assets, latest=latest username=username, assets=assets, latest=latest,
prefer=self._prefer, prefer_id=prefer_id,
) )
instances_map[name] = _instances instances_map[name] = _instances
...@@ -64,12 +62,12 @@ class AssetUserManager: ...@@ -64,12 +62,12 @@ class AssetUserManager:
else: else:
ordering.extend(["admin_user", "system_user"]) ordering.extend(["admin_user", "system_user"])
# 根据prefer决定优先使用系统用户或管理用户谁的 # 根据prefer决定优先使用系统用户或管理用户谁的
ordering_instances = [instances_map.get(i) for i in ordering] ordering_instances = [instances_map.get(i, []) for i in ordering]
instances = self._merge_instances(*ordering_instances) instances = self._merge_instances(*ordering_instances)
return AssetUserQuerySet(instances) return AssetUserQuerySet(instances)
def get(self, username, asset): def get(self, username, asset, **kwargs):
instances = self.filter(username, assets=[asset]) instances = self.filter(username, assets=[asset], **kwargs)
if len(instances) == 1: if len(instances) == 1:
return instances[0] return instances[0]
elif len(instances) == 0: elif len(instances) == 0:
...@@ -95,10 +93,6 @@ class AssetUserManager: ...@@ -95,10 +93,6 @@ class AssetUserManager:
self._prefer = s self._prefer = s
return self return self
def using(self, s):
self._using = s
return self
@staticmethod @staticmethod
def none(): def none():
return AssetUserQuerySet() return AssetUserQuerySet()
......
...@@ -5,6 +5,7 @@ import uuid ...@@ -5,6 +5,7 @@ import uuid
from hashlib import md5 from hashlib import md5
import sshpubkeys import sshpubkeys
from django.core.cache import cache
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.conf import settings from django.conf import settings
...@@ -34,7 +35,10 @@ class AssetUser(OrgModelMixin): ...@@ -34,7 +35,10 @@ class AssetUser(OrgModelMixin):
date_updated = models.DateTimeField(auto_now=True, verbose_name=_("Date updated")) date_updated = models.DateTimeField(auto_now=True, verbose_name=_("Date updated"))
created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by')) created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by'))
CONNECTIVITY_ASSET_CACHE_KEY = "ASSET_USER_ASSET_CONNECTIVITY_{}" CONNECTIVITY_ASSET_CACHE_KEY = "ASSET_USER_{}_ASSET_CONNECTIVITY"
CONNECTIVITY_AMOUNT_CACHE_KEY = "ASSET_USER_{}_CONNECTIVITY_AMOUNT"
ASSETS_AMOUNT_CACHE_KEY = "ASSET_USER_{}_ASSETS_AMOUNT"
ASSET_USER_CACHE_TIME = 3600 * 24
_prefer = "system_user" _prefer = "system_user"
...@@ -67,6 +71,11 @@ class AssetUser(OrgModelMixin): ...@@ -67,6 +71,11 @@ class AssetUser(OrgModelMixin):
pass pass
return None return None
@property
def part_id(self):
i = '-'.join(str(self.id).split('-')[:3])
return i
def get_related_assets(self): def get_related_assets(self):
assets = self.assets.all() assets = self.assets.all()
return assets return assets
...@@ -97,10 +106,14 @@ class AssetUser(OrgModelMixin): ...@@ -97,10 +106,14 @@ class AssetUser(OrgModelMixin):
self.set_asset_connectivity(asset, Connectivity.reachable()) self.set_asset_connectivity(asset, Connectivity.reachable())
else: else:
self.set_asset_connectivity(asset, Connectivity.unknown()) self.set_asset_connectivity(asset, Connectivity.unknown())
cache_key = self.CONNECTIVITY_AMOUNT_CACHE_KEY.format(self.part_id)
cache.delete(cache_key)
@property @property
def connectivity(self): def connectivity(self):
assets = self.get_related_assets() assets = self.get_related_assets()\
.select_related('admin_user')\
.only('id', 'hostname', 'admin_user')
data = { data = {
'unreachable': [], 'unreachable': [],
'reachable': [], 'reachable': [],
...@@ -118,11 +131,25 @@ class AssetUser(OrgModelMixin): ...@@ -118,11 +131,25 @@ class AssetUser(OrgModelMixin):
@property @property
def connectivity_amount(self): def connectivity_amount(self):
return {k: len(v) for k, v in self.connectivity.items()} cache_key = self.CONNECTIVITY_AMOUNT_CACHE_KEY.format(self.part_id)
amount = cache.get(cache_key)
if not amount:
connectivity = {k: len(v) for k, v in self.connectivity.items()}
cache.set(cache_key, connectivity, self.ASSET_USER_CACHE_TIME)
return amount
@property @property
def assets_amount(self): def assets_amount(self):
return self.get_related_assets().count() cache_key = self.ASSETS_AMOUNT_CACHE_KEY.format(self.id)
cached = cache.get(cache_key)
if not cached:
cached = self.get_related_assets().count()
cache.set(cache_key, cached, self.ASSET_USER_CACHE_TIME)
return cached
def expire_assets_amount(self):
cache_key = self.ASSETS_AMOUNT_CACHE_KEY.format(self.id)
cache.delete(cache_key)
def get_asset_connectivity(self, asset): def get_asset_connectivity(self, asset):
i = self.generate_id_with_asset(asset) i = self.generate_id_with_asset(asset)
...@@ -133,12 +160,15 @@ class AssetUser(OrgModelMixin): ...@@ -133,12 +160,15 @@ class AssetUser(OrgModelMixin):
i = self.generate_id_with_asset(asset) i = self.generate_id_with_asset(asset)
key = self.CONNECTIVITY_ASSET_CACHE_KEY.format(i) key = self.CONNECTIVITY_ASSET_CACHE_KEY.format(i)
Connectivity.set(key, c) Connectivity.set(key, c)
# 当为某个系统用户或管理用户设置的的时候,失效掉他们的连接数量
amount_key = self.CONNECTIVITY_AMOUNT_CACHE_KEY.format(self.part_id)
cache.delete(amount_key)
def get_asset_user(self, asset): def get_asset_user(self, asset):
from ..backends import AssetUserManager from ..backends import AssetUserManager
try: try:
manager = AssetUserManager().prefer(self._prefer) manager = AssetUserManager().prefer(self._prefer)
other = manager.get(username=self.username, asset=asset) other = manager.get(username=self.username, asset=asset, prefer_id=self.id)
return other return other
except Exception as e: except Exception as e:
logger.error(e, exc_info=True) logger.error(e, exc_info=True)
...@@ -150,8 +180,11 @@ class AssetUser(OrgModelMixin): ...@@ -150,8 +180,11 @@ class AssetUser(OrgModelMixin):
self._merge_auth(instance) self._merge_auth(instance)
def _merge_auth(self, other): def _merge_auth(self, other):
if other.password:
self.password = other.password self.password = other.password
if other.public_key:
self.public_key = other.public_key self.public_key = other.public_key
if other.private_key:
self.private_key = other.private_key self.private_key = other.private_key
def clear_auth(self): def clear_auth(self):
...@@ -185,7 +218,7 @@ class AssetUser(OrgModelMixin): ...@@ -185,7 +218,7 @@ class AssetUser(OrgModelMixin):
} }
def generate_id_with_asset(self, asset): def generate_id_with_asset(self, asset):
user_id = str(self.id).split('-')[:3] user_id = [self.part_id]
asset_id = str(asset.id).split('-')[3:] asset_id = str(asset.id).split('-')[3:]
ids = user_id + asset_id ids = user_id + asset_id
return '-'.join(ids) return '-'.join(ids)
......
...@@ -192,6 +192,7 @@ class AssetsAmountMixin: ...@@ -192,6 +192,7 @@ class AssetsAmountMixin:
_assets_amount_cache_key = '_NODE_ASSETS_AMOUNT_{}' _assets_amount_cache_key = '_NODE_ASSETS_AMOUNT_{}'
_assets_amount = None _assets_amount = None
key = '' key = ''
cache_time = 3600 * 24 * 7
@property @property
def assets_amount(self): def assets_amount(self):
...@@ -213,7 +214,7 @@ class AssetsAmountMixin: ...@@ -213,7 +214,7 @@ class AssetsAmountMixin:
def assets_amount(self, value): def assets_amount(self, value):
self._assets_amount = value self._assets_amount = value
cache_key = self._assets_amount_cache_key.format(self.key) cache_key = self._assets_amount_cache_key.format(self.key)
cache.set(cache_key, value) cache.set(cache_key, value, self.cache_time)
def expire_assets_amount(self): def expire_assets_amount(self):
ancestor_keys = self.get_ancestor_keys(with_self=True) ancestor_keys = self.get_ancestor_keys(with_self=True)
......
...@@ -17,7 +17,7 @@ class AdminUserSerializer(BulkOrgResourceModelSerializer): ...@@ -17,7 +17,7 @@ class AdminUserSerializer(BulkOrgResourceModelSerializer):
""" """
class Meta: class Meta:
# list_serializer_class = AdaptedBulkListSerializer list_serializer_class = AdaptedBulkListSerializer
model = AdminUser model = AdminUser
fields = [ fields = [
'id', 'name', 'username', 'password', 'private_key', 'public_key', 'id', 'name', 'username', 'password', 'private_key', 'public_key',
......
...@@ -76,8 +76,8 @@ class AssetSerializer(BulkOrgResourceModelSerializer): ...@@ -76,8 +76,8 @@ class AssetSerializer(BulkOrgResourceModelSerializer):
@classmethod @classmethod
def setup_eager_loading(cls, queryset): def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """ """ Perform necessary eager loading of data. """
queryset = queryset.prefetch_related('labels', 'nodes')\ queryset = queryset.prefetch_related('labels', 'nodes', 'protocols')\
.select_related('admin_user') .select_related('admin_user', 'domain')
return queryset return queryset
@staticmethod @staticmethod
......
...@@ -20,7 +20,7 @@ class SystemUserSerializer(BulkOrgResourceModelSerializer): ...@@ -20,7 +20,7 @@ class SystemUserSerializer(BulkOrgResourceModelSerializer):
'id', 'name', 'username', 'password', 'public_key', 'private_key', 'id', 'name', 'username', 'password', 'public_key', 'private_key',
'login_mode', 'login_mode_display', 'priority', 'protocol', 'login_mode', 'login_mode_display', 'priority', 'protocol',
'auto_push', 'cmd_filters', 'sudo', 'shell', 'comment', 'nodes', 'auto_push', 'cmd_filters', 'sudo', 'shell', 'comment', 'nodes',
'assets', 'assets_amount', 'connectivity_amount' 'assets_amount', 'connectivity_amount'
] ]
extra_kwargs = { extra_kwargs = {
'password': {"write_only": True}, 'password': {"write_only": True},
...@@ -32,6 +32,12 @@ class SystemUserSerializer(BulkOrgResourceModelSerializer): ...@@ -32,6 +32,12 @@ class SystemUserSerializer(BulkOrgResourceModelSerializer):
'created_by': {'read_only': True}, 'created_by': {'read_only': True},
} }
@classmethod
def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.prefetch_related('cmd_filters', 'nodes')
return queryset
class SystemUserAuthSerializer(AuthSerializer): class SystemUserAuthSerializer(AuthSerializer):
""" """
...@@ -47,8 +53,6 @@ class SystemUserAuthSerializer(AuthSerializer): ...@@ -47,8 +53,6 @@ class SystemUserAuthSerializer(AuthSerializer):
class SystemUserSimpleSerializer(serializers.ModelSerializer): class SystemUserSimpleSerializer(serializers.ModelSerializer):
""" """
系统用户最基本信息的数据结构 系统用户最基本信息的数据结构
......
...@@ -27,11 +27,6 @@ def test_asset_conn_on_created(asset): ...@@ -27,11 +27,6 @@ def test_asset_conn_on_created(asset):
test_asset_connectivity_util.delay([asset]) test_asset_connectivity_util.delay([asset])
def set_asset_root_node(asset):
logger.debug("Set asset default node: {}".format(Node.root()))
asset.nodes.add(Node.root())
@receiver(post_save, sender=Asset, dispatch_uid="my_unique_identifier") @receiver(post_save, sender=Asset, dispatch_uid="my_unique_identifier")
@on_transaction_commit @on_transaction_commit
def on_asset_created_or_update(sender, instance=None, created=False, **kwargs): def on_asset_created_or_update(sender, instance=None, created=False, **kwargs):
......
...@@ -84,7 +84,7 @@ function initTable() { ...@@ -84,7 +84,7 @@ function initTable() {
$(td).html(innerHtml) $(td).html(innerHtml)
}}, }},
{targets: 5, createdCell: function (td, cellData) { {targets: 5, createdCell: function (td, cellData) {
var data = cellData['unreachable']; var data = cellData.unreachable;
var innerHtml = ""; var innerHtml = "";
if (data !== 0) { if (data !== 0) {
innerHtml = "<span class='text-danger'>" + data + "</span>"; innerHtml = "<span class='text-danger'>" + data + "</span>";
......
...@@ -80,7 +80,7 @@ function initTable() { ...@@ -80,7 +80,7 @@ function initTable() {
}}, }},
{targets: 6, createdCell: function (td, cellData) { {targets: 6, createdCell: function (td, cellData) {
var innerHtml = ""; var innerHtml = "";
var data = cellData['reachable']; var data = cellData.reachable;
if (data !== 0) { if (data !== 0) {
innerHtml = "<span class='text-navy'>" + data + "</span>"; innerHtml = "<span class='text-navy'>" + data + "</span>";
} else { } else {
...@@ -89,7 +89,7 @@ function initTable() { ...@@ -89,7 +89,7 @@ function initTable() {
$(td).html(innerHtml) $(td).html(innerHtml)
}}, }},
{targets: 7, createdCell: function (td, cellData) { {targets: 7, createdCell: function (td, cellData) {
var data = cellData['unreachable']; var data = cellData.unreachable;
var innerHtml = ""; var innerHtml = "";
if (data !== 0) { if (data !== 0) {
innerHtml = "<span class='text-danger'>" + data + "</span>"; innerHtml = "<span class='text-danger'>" + data + "</span>";
...@@ -103,7 +103,7 @@ function initTable() { ...@@ -103,7 +103,7 @@ function initTable() {
var innerHtml = ""; var innerHtml = "";
var total = rowData.assets_amount; var total = rowData.assets_amount;
var reachable = cellData.reachable; var reachable = cellData.reachable;
if (total !== 0) { if (total && total !== 0) {
val = reachable/total * 100; val = reachable/total * 100;
} }
...@@ -119,7 +119,8 @@ function initTable() { ...@@ -119,7 +119,8 @@ function initTable() {
var update_btn = '<a href="{% url "assets:system-user-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var update_btn = '<a href="{% url "assets:system-user-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_admin_user_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_admin_user_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn) $(td).html(update_btn + del_btn)
}}], }},
],
ajax_url: '{% url "api-assets:system-user-list" %}', ajax_url: '{% url "api-assets:system-user-list" %}',
columns: [ columns: [
{data: "id" }, {data: "name" }, {data: "username" }, {data: "protocol"}, {data: "login_mode_display"}, {data: "assets_amount" }, {data: "id" }, {data: "name" }, {data: "username" }, {data: "protocol"}, {data: "login_mode_display"}, {data: "assets_amount" },
......
...@@ -220,6 +220,11 @@ class AssetDetailView(PermissionsMixin, DetailView): ...@@ -220,6 +220,11 @@ class AssetDetailView(PermissionsMixin, DetailView):
template_name = 'assets/asset_detail.html' template_name = 'assets/asset_detail.html'
permission_classes = [IsValidUser] permission_classes = [IsValidUser]
def get_queryset(self):
return super().get_queryset().prefetch_related(
"nodes", "labels", "protocols"
).select_related('admin_user', 'domain')
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
nodes_remain = Node.objects.exclude(assets=self.object) nodes_remain = Node.objects.exclude(assets=self.object)
context = { context = {
......
...@@ -97,7 +97,10 @@ class SystemUserAssetView(PermissionsMixin, DetailView): ...@@ -97,7 +97,10 @@ class SystemUserAssetView(PermissionsMixin, DetailView):
permission_classes = [IsOrgAdmin] permission_classes = [IsOrgAdmin]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
nodes_remain = sorted(Node.objects.exclude(systemuser=self.object), reverse=True) from ..utils import NodeUtil
nodes_remain = Node.objects.exclude(systemuser=self.object)
util = NodeUtil()
nodes_remain = util.get_nodes_by_queryset(nodes_remain)
context = { context = {
'app': _('assets'), 'app': _('assets'),
'action': _('System user asset'), 'action': _('System user asset'),
......
...@@ -8,11 +8,12 @@ from django.core.signals import request_finished ...@@ -8,11 +8,12 @@ from django.core.signals import request_finished
from django.db import connection from django.db import connection
from .utils import get_logger from common.utils import get_logger
from .local import thread_local from .local import thread_local
logger = get_logger(__file__)
pattern = re.compile(r'FROM `(\w+)`') pattern = re.compile(r'FROM `(\w+)`')
# logger = logging.getLogger('jmsdb')
logger = get_logger(__name__)
class Counter: class Counter:
......
...@@ -27,7 +27,11 @@ class OrgModelViewSet(IDInCacheFilterMixin, ModelViewSet): ...@@ -27,7 +27,11 @@ class OrgModelViewSet(IDInCacheFilterMixin, ModelViewSet):
class OrgBulkModelViewSet(IDInCacheFilterMixin, BulkModelViewSet): class OrgBulkModelViewSet(IDInCacheFilterMixin, BulkModelViewSet):
def get_queryset(self): def get_queryset(self):
return super().get_queryset().all() queryset = super().get_queryset().all()
if hasattr(self, 'serializer_class') and \
hasattr(self.serializer_class, 'setup_eager_loading'):
queryset = self.serializer_class.setup_eager_loading(queryset)
return queryset
class OrgMembershipModelViewSetMixin: class OrgMembershipModelViewSetMixin:
......
...@@ -31,7 +31,8 @@ class SessionViewSet(OrgBulkModelViewSet): ...@@ -31,7 +31,8 @@ class SessionViewSet(OrgBulkModelViewSet):
pagination_class = LimitOffsetPagination pagination_class = LimitOffsetPagination
permission_classes = (IsOrgAdminOrAppUser | IsAuditor, ) permission_classes = (IsOrgAdminOrAppUser | IsAuditor, )
filter_fields = [ filter_fields = [
"user", "asset", "system_user", "terminal", "is_finished", "user", "asset", "system_user", "remote_addr",
"protocol", "terminal", "is_finished",
] ]
date_range_filter_fields = [ date_range_filter_fields = [
('date_start', ('date_from', 'date_to')) ('date_start', ('date_from', 'date_to'))
......
...@@ -191,26 +191,22 @@ class Session(OrgModelMixin): ...@@ -191,26 +191,22 @@ class Session(OrgModelMixin):
@property @property
def _date_start_first_has_replay_rdp_session(self): def _date_start_first_has_replay_rdp_session(self):
if self._DATE_START_FIRST_HAS_REPLAY_RDP_SESSION is None: if self.__class__._DATE_START_FIRST_HAS_REPLAY_RDP_SESSION is None:
instance = self.__class__.objects.filter( instance = self.__class__.objects.filter(
protocol='rdp', has_replay=True).order_by('date_start').first() protocol='rdp', has_replay=True
).order_by('date_start').first()
if not instance: if not instance:
return None date_start = timezone.now() - timezone.timedelta(days=365)
self._DATE_START_FIRST_HAS_REPLAY_RDP_SESSION = instance.date_start else:
date_start = instance.date_start
return self._DATE_START_FIRST_HAS_REPLAY_RDP_SESSION self.__class__._DATE_START_FIRST_HAS_REPLAY_RDP_SESSION = date_start
return self.__class__._DATE_START_FIRST_HAS_REPLAY_RDP_SESSION
def can_replay(self): def can_replay(self):
if self.has_replay: if self.has_replay:
return True return True
# 判断对RDP Session添加上报has_replay状态机制之前的录像回放
if self._date_start_first_has_replay_rdp_session is None:
return True
if self.date_start < self._date_start_first_has_replay_rdp_session: if self.date_start < self._date_start_first_has_replay_rdp_session:
return True return True
return False return False
def save_to_storage(self, f): def save_to_storage(self, f):
......
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
{% block content_bottom_left %}{% endblock %} {% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}" charset="UTF-8"></script> <script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}" charset="UTF-8"></script>
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.zh-CN.min.js' %}" charset="UTF-8"></script> <script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.zh-CN.min.js' %}" ></script>
<script> <script>
var table; var table;
...@@ -136,8 +136,8 @@ $(document).ready(function () { ...@@ -136,8 +136,8 @@ $(document).ready(function () {
$('.dropdown-menu.search-help').hide(); $('.dropdown-menu.search-help').hide();
keyword.focus() keyword.focus()
}) })
.on("click", "document", function () { .on('click', 'body', function (e) {
$('.dropdown-menu.search-help').hide(); $('.dropdown-menu.search-help').hide()
}) })
.on('click', '.toggle', function (e) { .on('click', '.toggle', function (e) {
e.preventDefault(); e.preventDefault();
...@@ -162,12 +162,7 @@ $(document).ready(function () { ...@@ -162,12 +162,7 @@ $(document).ready(function () {
detailRows.push(tr.attr('id')); detailRows.push(tr.attr('id'));
} }
} }
}).on('click', 'body', function (e) { })
$('.dropdown-menu.search-help').hide()
}).on('change', '#date_start', function () {
console.log("date change")
});
function format(d) { function format(d) {
......
...@@ -71,13 +71,15 @@ ...@@ -71,13 +71,15 @@
<li><a class="search-item" data-value="user">{% trans 'User' %}</a></li> <li><a class="search-item" data-value="user">{% trans 'User' %}</a></li>
<li><a class="search-item" data-value="asset">{% trans 'Asset' %}</a></li> <li><a class="search-item" data-value="asset">{% trans 'Asset' %}</a></li>
<li><a class="search-item" data-value="system_user">{% trans 'System user' %}</a></li> <li><a class="search-item" data-value="system_user">{% trans 'System user' %}</a></li>
<li><a class="search-item" data-value="input">{% trans 'Command' %}</a></li> <li><a class="search-item" data-value="remote_addr">{% trans 'Remote addr' %}</a></li>
<li><a class="search-item" data-value="protocol">{% trans 'Protocol' %}</a></li>
</ul> </ul>
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script> <script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.zh-CN.min.js' %}" ></script>
<script> <script>
function terminateSession(data) { function terminateSession(data) {
...@@ -182,19 +184,42 @@ function finishedSession(data) { ...@@ -182,19 +184,42 @@ function finishedSession(data) {
} }
var table; var table;
$(document).ready(function() { $(document).ready(function() {
table = initTable("#session_table"); table = initTable("#session_table").on('init', function () {
$('.select2').select2({ var dateFromRef = $("#date_from");
dropdownAutoWidth: true, var dateToRef = $("#date_to");
width: "auto" var options = {
});
$('.input-daterange.input-group').datepicker({
format: "yyyy-mm-dd", format: "yyyy-mm-dd",
todayBtn: "linked", todayBtn: "linked",
keyboardNavigation: false, keyboardNavigation: false,
forceParse: false, forceParse: false,
calendarWeeks: true, calendarWeeks: true,
autoclose: true autoclose: true,
language: navigator.language || "en",
};
dateFromRef.datepicker(options).on("changeDate", function () {
if (!$(this).val()) {
return
}
var value = $(this).val() + ' 0:0:0';
var date = new Date(value);
var url = table.ajax.url();
url = setUrlParam(url, "date_from", date.toISOString());
table.ajax.url(url);
table.ajax.reload();
});
dateToRef.datepicker(options).on("changeDate", function () {
if (!$(this).val()) {
return
}
var value = $(this).val() + ' 23:59:59';
var date = new Date(value);
var url = table.ajax.url();
url = setUrlParam(url, "date_to", date.toISOString());
table.ajax.url(url);
table.ajax.reload();
}); });
});
}).on('click', '.btn-term', function () { }).on('click', '.btn-term', function () {
var $this = $(this); var $this = $(this);
var session_id = $this.attr('value'); var session_id = $this.attr('value');
...@@ -207,6 +232,34 @@ $(document).ready(function() { ...@@ -207,6 +232,34 @@ $(document).ready(function() {
var replayUrl = "/luna/replay/" + sessionID; var replayUrl = "/luna/replay/" + sessionID;
window.open(replayUrl, "height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no"); window.open(replayUrl, "height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no");
}) })
.on("click", '#session_table_filter input', function (e) {
e.preventDefault();
e.stopPropagation();
var offset1 = $('#session_table_filter input').offset();
var x = offset1.left;
var y = offset1.top;
var offset = $(".search-help").parent().offset();
x -= offset.left;
y -= offset.top;
x += 18;
y += 80;
$('.search-help').css({"top":y+"px", "left":x+"px", "position": "absolute"});
$('.dropdown-menu.search-help').show();
})
.on('click', '.search-item', function (e) {
e.preventDefault();
e.stopPropagation();
var keyword = $("#session_table_filter input");
var value = $(this).data('value');
var old_value = keyword.val();
var new_value = old_value + ' ' + value + ':';
keyword.val(new_value.trim());
$('.dropdown-menu.search-help').hide();
keyword.focus()
})
.on('click', 'body', function (e) {
$('.dropdown-menu.search-help').hide()
})
.on('click', '#btn_bulk_update', function () { .on('click', '#btn_bulk_update', function () {
var action = $('#slct_bulk_update').val(); var action = $('#slct_bulk_update').val();
var idList = table.selected; var idList = table.selected;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment