Commit a1905ecf authored by oldseven's avatar oldseven

Merge branch 'master' of https://github.com/jumpserver/jumpserver

Conflicts:
	apps/terminal/api.py
parents 0d8a6002 f2216274
...@@ -19,14 +19,8 @@ Jumpserver采纳分布式架构,支持多机房跨区域部署,中心节点 ...@@ -19,14 +19,8 @@ Jumpserver采纳分布式架构,支持多机房跨区域部署,中心节点
---- ----
### 功能 ### 功能
- 统一认证
- 资产管理 ![Jumpserver功能](https://jumpserver-release.oss-cn-hangzhou.aliyuncs.com/Jumpserver13.jpg "Jumpserver功能")
- 统一授权
- 审计
- 支持LDAP认证
- Web terminal
- SSH Server
- 支持Windows RDP
### 开始使用 ### 开始使用
......
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
__version__ = "1.2.1" __version__ = "1.3.1"
...@@ -43,6 +43,7 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet): ...@@ -43,6 +43,7 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
queryset = super().get_queryset() queryset = super().get_queryset()
admin_user_id = self.request.query_params.get('admin_user_id') admin_user_id = self.request.query_params.get('admin_user_id')
node_id = self.request.query_params.get("node_id") node_id = self.request.query_params.get("node_id")
show_current_asset = self.request.query_params.get("show_current_asset")
if admin_user_id: if admin_user_id:
admin_user = get_object_or_404(AdminUser, id=admin_user_id) admin_user = get_object_or_404(AdminUser, id=admin_user_id)
...@@ -51,8 +52,11 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet): ...@@ -51,8 +52,11 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
node = get_object_or_404(Node, id=node_id) node = get_object_or_404(Node, id=node_id)
if not node.is_root(): if not node.is_root():
queryset = queryset.filter( queryset = queryset.filter(
nodes__key__regex='{}(:[0-9]+)*$'.format(node.key), nodes__key__regex='^{}(:[0-9]+)*$'.format(node.key),
).distinct() ).distinct()
if show_current_asset and node_id:
queryset = queryset.filter(nodes=node_id).distinct()
return queryset return queryset
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
# limitations under the License. # limitations under the License.
from rest_framework import generics, mixins from rest_framework import generics, mixins
from rest_framework.serializers import ValidationError
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet from rest_framework_bulk import BulkModelViewSet
...@@ -41,7 +42,14 @@ __all__ = [ ...@@ -41,7 +42,14 @@ __all__ = [
class NodeViewSet(BulkModelViewSet): class NodeViewSet(BulkModelViewSet):
queryset = Node.objects.all() queryset = Node.objects.all()
permission_classes = (IsSuperUser,) permission_classes = (IsSuperUser,)
serializer_class = serializers.NodeSerializer # serializer_class = serializers.NodeSerializer
def get_serializer_class(self):
show_current_asset = self.request.query_params.get('show_current_asset')
if show_current_asset:
return serializers.NodeCurrentSerializer
else:
return serializers.NodeSerializer
def perform_create(self, serializer): def perform_create(self, serializer):
child_key = Node.root().get_next_child_key() child_key = Node.root().get_next_child_key()
...@@ -83,16 +91,29 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView): ...@@ -83,16 +91,29 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
serializer_class = serializers.NodeSerializer serializer_class = serializers.NodeSerializer
instance = None instance = None
def counter(self):
values = [
child.value[child.value.rfind(' '):]
for child in self.get_object().get_children()
if child.value.startswith("新节点 ")
]
values = [int(value) for value in values if value.strip().isdigit()]
count = max(values)+1 if values else 1
return count
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
if not request.data.get("value"): if not request.data.get("value"):
request.data["value"] = _("New node {}").format( request.data["value"] = _("New node {}").format(self.counter())
Node.root().get_next_child_key().split(":")[-1]
)
return super().post(request, *args, **kwargs) return super().post(request, *args, **kwargs)
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
instance = self.get_object() instance = self.get_object()
value = request.data.get("value") value = request.data.get("value")
values = [child.value for child in instance.get_children()]
if value in values:
raise ValidationError(
'The same level node name cannot be the same'
)
node = instance.create_child(value=value) node = instance.create_child(value=value)
return Response( return Response(
{"id": node.id, "key": node.key, "value": node.value}, {"id": node.id, "key": node.key, "value": node.value},
...@@ -127,8 +148,9 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView): ...@@ -127,8 +148,9 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
node_fake.id = asset.id node_fake.id = asset.id
node_fake.parent = node node_fake.parent = node
node_fake.value = asset.hostname node_fake.value = asset.hostname
node_fake.is_asset = True node_fake.is_node = False
queryset.append(node_fake) queryset.append(node_fake)
queryset = sorted(queryset, key=lambda x: x.is_node, reverse=True)
return queryset return queryset
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
...@@ -162,8 +184,9 @@ class NodeAddChildrenApi(generics.UpdateAPIView): ...@@ -162,8 +184,9 @@ class NodeAddChildrenApi(generics.UpdateAPIView):
for node in children: for node in children:
if not node: if not node:
continue continue
node.parent = instance # node.parent = instance
node.save() # node.save()
node.set_parent(instance)
return Response("OK") return Response("OK")
...@@ -190,6 +213,9 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView): ...@@ -190,6 +213,9 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView):
instance = self.get_object() instance = self.get_object()
if instance != Node.root(): if instance != Node.root():
instance.assets.remove(*tuple(assets)) instance.assets.remove(*tuple(assets))
else:
assets = [asset for asset in assets if asset.nodes.count() > 1]
instance.assets.remove(*tuple(assets))
class NodeReplaceAssetsApi(generics.UpdateAPIView): class NodeReplaceAssetsApi(generics.UpdateAPIView):
......
...@@ -40,7 +40,7 @@ class SystemUserViewSet(BulkModelViewSet): ...@@ -40,7 +40,7 @@ class SystemUserViewSet(BulkModelViewSet):
permission_classes = (IsSuperUserOrAppUser,) permission_classes = (IsSuperUserOrAppUser,)
class SystemUserAuthInfoApi(generics.RetrieveUpdateAPIView): class SystemUserAuthInfoApi(generics.RetrieveUpdateDestroyAPIView):
""" """
Get system user auth info Get system user auth info
""" """
...@@ -48,6 +48,11 @@ class SystemUserAuthInfoApi(generics.RetrieveUpdateAPIView): ...@@ -48,6 +48,11 @@ class SystemUserAuthInfoApi(generics.RetrieveUpdateAPIView):
permission_classes = (IsSuperUserOrAppUser,) permission_classes = (IsSuperUserOrAppUser,)
serializer_class = serializers.SystemUserAuthSerializer serializer_class = serializers.SystemUserAuthSerializer
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
instance.clear_auth()
return Response(status=204)
class SystemUserPushApi(generics.RetrieveAPIView): class SystemUserPushApi(generics.RetrieveAPIView):
""" """
...@@ -58,6 +63,9 @@ class SystemUserPushApi(generics.RetrieveAPIView): ...@@ -58,6 +63,9 @@ class SystemUserPushApi(generics.RetrieveAPIView):
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
system_user = self.get_object() system_user = self.get_object()
nodes = system_user.nodes.all()
for node in nodes:
system_user.assets.add(*tuple(node.get_all_assets()))
task = push_system_user_to_assets_manual.delay(system_user) task = push_system_user_to_assets_manual.delay(system_user)
return Response({"task": task.id}) return Response({"task": task.id})
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
import uuid import uuid
import logging import logging
import random
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 _
...@@ -35,6 +34,19 @@ def default_node(): ...@@ -35,6 +34,19 @@ def default_node():
return None return None
class AssetQuerySet(models.QuerySet):
def active(self):
return self.filter(is_active=True)
def valid(self):
return self.active()
class AssetManager(models.Manager):
def get_queryset(self):
return AssetQuerySet(self.model, using=self._db)
class Asset(models.Model): class Asset(models.Model):
# Important # Important
PLATFORM_CHOICES = ( PLATFORM_CHOICES = (
...@@ -83,6 +95,8 @@ class Asset(models.Model): ...@@ -83,6 +95,8 @@ class Asset(models.Model):
date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created')) date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created'))
comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment')) comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
objects = AssetManager()
def __str__(self): def __str__(self):
return '{0.hostname}({0.ip})'.format(self) return '{0.hostname}({0.ip})'.format(self)
...@@ -103,7 +117,8 @@ class Asset(models.Model): ...@@ -103,7 +117,8 @@ class Asset(models.Model):
def get_nodes(self): def get_nodes(self):
from .node import Node from .node import Node
return self.nodes.all() or [Node.root()] nodes = self.nodes.all() or [Node.root()]
return nodes
@property @property
def hardware_info(self): def hardware_info(self):
......
...@@ -10,6 +10,7 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -10,6 +10,7 @@ from django.utils.translation import ugettext_lazy as _
from django.conf import settings from django.conf import settings
from common.utils import get_signer, ssh_key_string_to_obj, ssh_key_gen from common.utils import get_signer, ssh_key_string_to_obj, ssh_key_gen
from common.validators import alphanumeric
from .utils import private_key_validator from .utils import private_key_validator
signer = get_signer() signer = get_signer()
...@@ -18,7 +19,7 @@ signer = get_signer() ...@@ -18,7 +19,7 @@ signer = get_signer()
class AssetUser(models.Model): class AssetUser(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
username = models.CharField(max_length=128, verbose_name=_('Username')) username = models.CharField(max_length=32, verbose_name=_('Username'), validators=[alphanumeric])
_password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password')) _password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
_private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ]) _private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
_public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key')) _public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
...@@ -103,10 +104,16 @@ class AssetUser(models.Model): ...@@ -103,10 +104,16 @@ class AssetUser(models.Model):
if update_fields: if update_fields:
self.save(update_fields=update_fields) self.save(update_fields=update_fields)
def clear_auth(self):
self._password = ''
self._private_key = ''
self._public_key = ''
self.save()
def auto_gen_auth(self): def auto_gen_auth(self):
password = str(uuid.uuid4()) password = str(uuid.uuid4())
private_key, public_key = ssh_key_gen( private_key, public_key = ssh_key_gen(
username=self.username, password=password username=self.username
) )
self.set_auth(password=password, self.set_auth(password=password,
private_key=private_key, private_key=private_key,
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
# #
import uuid import uuid
from django.db import models from django.db import models, transaction
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
...@@ -12,11 +13,14 @@ __all__ = ['Node'] ...@@ -12,11 +13,14 @@ __all__ = ['Node']
class Node(models.Model): class Node(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
key = models.CharField(unique=True, max_length=64, verbose_name=_("Key")) # '1:1:1:1' key = models.CharField(unique=True, max_length=64, verbose_name=_("Key")) # '1:1:1:1'
value = models.CharField(max_length=128, unique=True, verbose_name=_("Value")) # value = models.CharField(
# max_length=128, unique=True, verbose_name=_("Value")
# )
value = models.CharField(max_length=128, verbose_name=_("Value"))
child_mark = models.IntegerField(default=0) child_mark = models.IntegerField(default=0)
date_create = models.DateTimeField(auto_now_add=True) date_create = models.DateTimeField(auto_now_add=True)
is_asset = False is_node = True
def __str__(self): def __str__(self):
return self.full_value return self.full_value
...@@ -36,6 +40,16 @@ class Node(models.Model): ...@@ -36,6 +40,16 @@ class Node(models.Model):
def level(self): def level(self):
return len(self.key.split(':')) return len(self.key.split(':'))
def set_parent(self, instance):
children = self.get_all_children()
old_key = self.key
with transaction.atomic():
self.parent = instance
for child in children:
child.key = child.key.replace(old_key, self.key, 1)
child.save()
self.save()
def get_next_child_key(self): def get_next_child_key(self):
mark = self.child_mark mark = self.child_mark
self.child_mark += 1 self.child_mark += 1
...@@ -48,56 +62,77 @@ class Node(models.Model): ...@@ -48,56 +62,77 @@ class Node(models.Model):
return child return child
def get_children(self): def get_children(self):
return self.__class__.objects.filter(key__regex=r'{}:[0-9]+$'.format(self.key)) return self.__class__.objects.filter(
key__regex=r'^{}:[0-9]+$'.format(self.key)
)
def get_children_with_self(self):
return self.__class__.objects.filter(
key__regex=r'^{0}$|^{0}:[0-9]+$'.format(self.key)
)
def get_all_children(self): def get_all_children(self):
return self.__class__.objects.filter(key__startswith='{}:'.format(self.key)) return self.__class__.objects.filter(
key__startswith='{}:'.format(self.key)
)
def get_all_children_with_self(self):
return self.__class__.objects.filter(
key__regex=r'^{0}$|^{0}:'.format(self.key)
)
def get_family(self): def get_family(self):
children = list(self.get_all_children()) ancestor = self.ancestor
children.append(self) children = self.get_all_children()
return children return [*tuple(ancestor), self, *tuple(children)]
def get_assets(self): def get_assets(self):
from .asset import Asset from .asset import Asset
assets = Asset.objects.filter(nodes__id=self.id) if self.is_root():
assets = Asset.objects.filter(
Q(nodes__id=self.id) | Q(nodes__isnull=True)
)
else:
assets = Asset.objects.filter(nodes__id=self.id)
return assets return assets
def get_active_assets(self): def get_valid_assets(self):
return self.get_assets().filter(is_active=True) return self.get_assets().valid()
def get_all_assets(self): def get_all_assets(self):
from .asset import Asset from .asset import Asset
if self.is_root(): if self.is_root():
assets = Asset.objects.all() assets = Asset.objects.all()
else: else:
nodes = self.get_family() nodes = self.get_all_children_with_self()
assets = Asset.objects.filter(nodes__in=nodes).distinct() assets = Asset.objects.filter(nodes__in=nodes).distinct()
return assets return assets
def get_current_assets(self):
from .asset import Asset
assets = Asset.objects.filter(nodes=self).distinct()
return assets
def has_assets(self): def has_assets(self):
return self.get_all_assets() return self.get_all_assets()
def get_all_active_assets(self): def get_all_valid_assets(self):
return self.get_all_assets().filter(is_active=True) return self.get_all_assets().valid()
def is_root(self): def is_root(self):
return self.key == '0' return self.key == '0'
@property @property
def parent(self): def parent(self):
if self.key == "0": if self.key == "0" or not self.key.startswith("0"):
return self.__class__.root()
elif not self.key.startswith("0"):
return self.__class__.root() return self.__class__.root()
parent_key = ":".join(self.key.split(":")[:-1]) parent_key = ":".join(self.key.split(":")[:-1])
try: try:
parent = self.__class__.objects.get(key=parent_key) parent = self.__class__.objects.get(key=parent_key)
return parent
except Node.DoesNotExist: except Node.DoesNotExist:
return self.__class__.root() return self.__class__.root()
else:
return parent
@parent.setter @parent.setter
def parent(self, parent): def parent(self, parent):
...@@ -105,14 +140,20 @@ class Node(models.Model): ...@@ -105,14 +140,20 @@ class Node(models.Model):
@property @property
def ancestor(self): def ancestor(self):
if self.parent == self.__class__.root(): _key = self.key.split(':')
ancestor_keys = []
if self.is_root():
return [self.__class__.root()] return [self.__class__.root()]
else:
return [self.parent, *tuple(self.parent.ancestor)] for i in range(len(_key)-1):
_key.pop()
ancestor_keys.append(':'.join(_key))
return self.__class__.objects.filter(key__in=ancestor_keys)
@property @property
def ancestor_with_node(self): def ancestor_with_self(self):
ancestor = self.ancestor ancestor = list(self.ancestor)
ancestor.insert(0, self) ancestor.insert(0, self)
return ancestor return ancestor
......
...@@ -18,8 +18,7 @@ class NodeTMPSerializer(serializers.ModelSerializer): ...@@ -18,8 +18,7 @@ class NodeTMPSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Node model = Node
fields = ['id', 'key', 'value', 'parent', 'assets_amount', fields = ['id', 'key', 'value', 'parent', 'assets_amount', 'is_node']
'is_asset']
list_serializer_class = BulkListSerializer list_serializer_class = BulkListSerializer
@staticmethod @staticmethod
...@@ -62,13 +61,13 @@ class AssetGrantedSerializer(serializers.ModelSerializer): ...@@ -62,13 +61,13 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
""" """
system_users_granted = AssetSystemUserSerializer(many=True, read_only=True) system_users_granted = AssetSystemUserSerializer(many=True, read_only=True)
system_users_join = serializers.SerializerMethodField() system_users_join = serializers.SerializerMethodField()
nodes = NodeTMPSerializer(many=True, read_only=True) # nodes = NodeTMPSerializer(many=True, read_only=True)
class Meta: class Meta:
model = Asset model = Asset
fields = ( fields = (
"id", "hostname", "ip", "port", "system_users_granted", "id", "hostname", "ip", "port", "system_users_granted",
"is_active", "system_users_join", "os", 'domain', "nodes", "is_active", "system_users_join", "os", 'domain',
"platform", "comment" "platform", "comment"
) )
......
...@@ -9,7 +9,7 @@ from .asset import AssetGrantedSerializer ...@@ -9,7 +9,7 @@ from .asset import AssetGrantedSerializer
__all__ = [ __all__ = [
'NodeSerializer', "NodeGrantedSerializer", "NodeAddChildrenSerializer", 'NodeSerializer', "NodeGrantedSerializer", "NodeAddChildrenSerializer",
"NodeAssetsSerializer", "NodeAssetsSerializer", "NodeCurrentSerializer",
] ]
...@@ -48,9 +48,20 @@ class NodeSerializer(serializers.ModelSerializer): ...@@ -48,9 +48,20 @@ class NodeSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Node model = Node
fields = ['id', 'key', 'value', 'parent', 'assets_amount', 'is_asset'] fields = ['id', 'key', 'value', 'parent', 'assets_amount', 'is_node']
list_serializer_class = BulkListSerializer list_serializer_class = BulkListSerializer
def validate(self, data):
value = data.get('value')
instance = self.instance if self.instance else Node.root()
children = instance.parent.get_children().exclude(key=instance.key)
values = [child.value for child in children]
if value in values:
raise serializers.ValidationError(
'The same level node name cannot be the same'
)
return data
@staticmethod @staticmethod
def get_parent(obj): def get_parent(obj):
return obj.parent.id return obj.parent.id
...@@ -66,6 +77,12 @@ class NodeSerializer(serializers.ModelSerializer): ...@@ -66,6 +77,12 @@ class NodeSerializer(serializers.ModelSerializer):
return fields return fields
class NodeCurrentSerializer(NodeSerializer):
@staticmethod
def get_assets_amount(obj):
return obj.get_current_assets().count()
class NodeAssetsSerializer(serializers.ModelSerializer): class NodeAssetsSerializer(serializers.ModelSerializer):
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
......
...@@ -22,7 +22,7 @@ TIMEOUT = 60 ...@@ -22,7 +22,7 @@ TIMEOUT = 60
logger = get_logger(__file__) logger = get_logger(__file__)
CACHE_MAX_TIME = 60*60*60 CACHE_MAX_TIME = 60*60*60
disk_pattern = re.compile(r'^hd|sd|xvd|vd') disk_pattern = re.compile(r'^hd|sd|xvd|vd')
PERIOD_TASK = os.environ.get("PERIOD_TASK", "on") PERIOD_TASK = os.environ.get("PERIOD_TASK", "off")
@shared_task @shared_task
......
...@@ -98,7 +98,10 @@ function initTree2() { ...@@ -98,7 +98,10 @@ function initTree2() {
$.get("{% url 'api-assets:node-list' %}", function(data, status){ $.get("{% url 'api-assets:node-list' %}", function(data, status){
$.each(data, function (index, value) { $.each(data, function (index, value) {
value["pId"] = value["parent"]; value["pId"] = value["parent"];
value["open"] = true; {#value["open"] = true;#}
if (value["key"] === "0") {
value["open"] = true;
}
value["name"] = value["value"] + ' (' + value['assets_amount'] + ')'; value["name"] = value["value"] + ' (' + value['assets_amount'] + ')';
value['value'] = value['value']; value['value'] = value['value'];
}); });
......
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
{% bootstrap_field form.private_key_file layout="horizontal" %} {% bootstrap_field form.private_key_file layout="horizontal" %}
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="{{ form.as_push.id_for_label }}" class="col-sm-2 control-label">{% trans 'Auto push' %}</label> <label for="{{ form.auto_push.id_for_label }}" class="col-sm-2 control-label">{% trans 'Auto push' %}</label>
<div class="col-sm-8"> <div class="col-sm-8">
{{ form.auto_push}} {{ form.auto_push}}
</div> </div>
...@@ -79,43 +79,50 @@ ...@@ -79,43 +79,50 @@
</div> </div>
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
var auto_generate_key = '#'+'{{ form.auto_generate_key.id_for_label }}'; var auto_generate_key = '#'+'{{ form.auto_generate_key.id_for_label }}';
var protocol_id = '#' + '{{ form.protocol.id_for_label }}'; var protocol_id = '#' + '{{ form.protocol.id_for_label }}';
var password_id = '#' + '{{ form.password.id_for_label }}'; var private_key_id = '#' + '{{ form.private_key_file.id_for_label }}';
var private_key_id = '#' + '{{ form.private_key_file.id_for_label }}'; var auto_push_id = '#' + '{{ form.auto_push.id_for_label }}';
var sudo_id = '#' + '{{ form.sudo.id_for_label }}'; var sudo_id = '#' + '{{ form.sudo.id_for_label }}';
var shell_id = '#' + '{{ form.shell.id_for_label }}'; var shell_id = '#' + '{{ form.shell.id_for_label }}';
var need_change_field = [
auto_generate_key, private_key_id, auto_push_id, sudo_id, shell_id
];
var need_change_field = [auto_generate_key, private_key_id, sudo_id, shell_id] ; function protocolChange() {
if ($(protocol_id + " option:selected").text() === 'rdp') {
$('.auth-fields').removeClass('hidden');
$.each(need_change_field, function (index, value) {
$(value).closest('.form-group').addClass('hidden')
});
} else {
authFieldsDisplay();
$.each(need_change_field, function (index, value) {
$(value).closest('.form-group').removeClass('hidden')
});
}
}
function authFieldsDisplay() { function authFieldsDisplay() {
if ($(auto_generate_key).prop('checked')) { if ($(auto_generate_key).prop('checked')) {
$('.auth-fields').addClass('hidden'); $('.auth-fields').addClass('hidden');
} else { } else {
$('.auth-fields').removeClass('hidden'); $('.auth-fields').removeClass('hidden');
} }
} }
function protocolChange() { $(document).ready(function () {
if ($(protocol_id).attr('value') === 'rdp') { $('.select2').select2();
$.each(need_change_field, function (index, value) { authFieldsDisplay();
$(value).addClass('hidden') protocolChange();
}); })
$(password_id).removeClass('hidden') .on('change', protocol_id, function(){
} else { protocolChange();
$.each(need_change_field, function (index, value) { })
$(value).removeClass('hidden') .on('change', auto_generate_key, function(){
}); authFieldsDisplay();
} });
}
$(document).ready(function () { </script>
$('.select2').select2();
authFieldsDisplay();
protocolChange();
$(auto_generate_key).change(function () {
authFieldsDisplay();
});
})
</script>
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -124,7 +124,7 @@ $(document).ready(function () { ...@@ -124,7 +124,7 @@ $(document).ready(function () {
var success = function (data) { var success = function (data) {
var task_id = data.task; var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id); var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600') window.open(url, '', 'width=800,height=600,left=400,top=400')
}; };
APIUpdateAttr({ APIUpdateAttr({
url: the_url, url: the_url,
......
...@@ -190,7 +190,7 @@ ...@@ -190,7 +190,7 @@
<td colspan="2" class="no-borders"> <td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Nodes' %}" id="groups_selected" class="select2 groups" style="width: 100%" multiple="" tabindex="4"> <select data-placeholder="{% trans 'Nodes' %}" id="groups_selected" class="select2 groups" style="width: 100%" multiple="" tabindex="4">
{% for node in nodes_remain %} {% for node in nodes_remain %}
<option value="{{ node.id }}" id="opt_{{ node.id }}" >{{ node.name }}</option> <option value="{{ node.id }}" id="opt_{{ node.id }}" >{{ node }}</option>
{% endfor %} {% endfor %}
</select> </select>
</td> </td>
...@@ -204,7 +204,7 @@ ...@@ -204,7 +204,7 @@
{% for node in asset.nodes.all %} {% for node in asset.nodes.all %}
<tr> <tr>
<td ><b class="bdg_node" data-gid={{ node.id }}>{{ node.name }}</b></td> <td ><b class="bdg_node" data-gid={{ node.id }}>{{ node }}</b></td>
<td> <td>
<button class="btn btn-danger pull-right btn-xs btn-leave-node" type="button"><i class="fa fa-minus"></i></button> <button class="btn btn-danger pull-right btn-xs btn-leave-node" type="button"><i class="fa fa-minus"></i></button>
</td> </td>
......
...@@ -17,20 +17,21 @@ ...@@ -17,20 +17,21 @@
position:absolute; position:absolute;
visibility:hidden; visibility:hidden;
text-align: left; text-align: left;
top: 100%; {#top: 100%;#}
top: 0;
left: 0; left: 0;
z-index: 1000; z-index: 1000;
float: left; {#float: left;#}
padding: 5px 0; padding: 0 0;
margin: 2px 0 0; margin: 2px 0 0;
list-style: none; list-style: none;
background-clip: padding-box; background-clip: padding-box;
} }
div#rMenu li{ div#rMenu li{
margin: 1px 0; margin: 1px 0;
cursor: pointer; cursor: pointer;
{#list-style: none outside none;#} list-style: none outside none;
} }
.dropdown a:hover { .dropdown a:hover {
background-color: #f1f1f1 background-color: #f1f1f1
} }
...@@ -47,7 +48,6 @@ ...@@ -47,7 +48,6 @@
<div class="file-manager "> <div class="file-manager ">
<div id="assetTree" class="ztree"> <div id="assetTree" class="ztree">
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
</div> </div>
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
<th class="text-center">{% trans 'IP' %}</th> <th class="text-center">{% trans 'IP' %}</th>
<th class="text-center">{% trans 'Hardware' %}</th> <th class="text-center">{% trans 'Hardware' %}</th>
<th class="text-center">{% trans 'Active' %}</th> <th class="text-center">{% trans 'Active' %}</th>
<th class="text-center">{% trans 'Reachable' %}</th> {# <th class="text-center">{% trans 'Reachable' %}</th>#}
<th class="text-center">{% trans 'Action' %}</th> <th class="text-center">{% trans 'Action' %}</th>
</tr> </tr>
</thead> </thead>
...@@ -127,6 +127,9 @@ ...@@ -127,6 +127,9 @@
<li class="divider"></li> <li class="divider"></li>
<li id="menu_refresh_hardware_info" class="btn-refresh-hardware" tabindex="-1"><a><i class="fa fa-refresh"></i> {% trans 'Refresh node hardware info' %}</a></li> <li id="menu_refresh_hardware_info" class="btn-refresh-hardware" tabindex="-1"><a><i class="fa fa-refresh"></i> {% trans 'Refresh node hardware info' %}</a></li>
<li id="menu_test_connective" class="btn-test-connective" tabindex="-1"><a><i class="fa fa-chain"></i> {% trans 'Test node connective' %}</a></li> <li id="menu_test_connective" class="btn-test-connective" tabindex="-1"><a><i class="fa fa-chain"></i> {% trans 'Test node connective' %}</a></li>
<li class="divider"></li>
<li id="show_current_asset" class="btn-show-current-asset" style="display: none;" tabindex="-1"><a><i class="fa fa-hand-o-up"></i> {% trans 'Display only current node assets' %}</a></li>
<li id="show_all_asset" class="btn-show-all-asset" style="display: none;" tabindex="-1"><a><i class="fa fa-th"></i> {% trans 'Displays all child node assets' %}</a></li>
</ul> </ul>
</div> </div>
...@@ -157,26 +160,35 @@ function initTable() { ...@@ -157,26 +160,35 @@ function initTable() {
$(td).html('<i class="fa fa-check text-navy"></i>') $(td).html('<i class="fa fa-check text-navy"></i>')
} }
}}, }},
{targets: 5, createdCell: function (td, cellData) {
if (cellData === 'Unknown'){ {#{targets: 5, createdCell: function (td, cellData) {#}
$(td).html('<i class="fa fa-circle text-warning"></i>') {# if (cellData === 'Unknown'){#}
} else if (!cellData) { {# $(td).html('<i class="fa fa-circle text-warning"></i>')#}
$(td).html('<i class="fa fa-circle text-danger"></i>') {# } else if (!cellData) {#}
} else { {# $(td).html('<i class="fa fa-circle text-danger"></i>')#}
$(td).html('<i class="fa fa-circle text-navy"></i>') {# } else {#}
} {# $(td).html('<i class="fa fa-circle text-navy"></i>')#}
}}, {# }#}
{targets: 6, createdCell: function (td, cellData, rowData) { {# }},#}
{targets: 5, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:asset-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace("{{ DEFAULT_PK }}", cellData); var update_btn = '<a href="{% url "assets:asset-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_asset_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_asset_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:asset-list" %}', ajax_url: '{% url "api-assets:asset-list" %}',
{#columns: [#}
{# {data: "id"}, {data: "hostname" }, {data: "ip" },#}
{# {data: "cpu_cores"}, {data: "is_active", orderable: false },#}
{# {data: "is_connective", orderable: false}, {data: "id", orderable: false }#}
{#],#}
columns: [ columns: [
{data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "id"}, {data: "hostname" }, {data: "ip" },
{data: "cpu_cores"}, {data: "is_active", orderable: false }, {data: "cpu_cores"}, {data: "is_active", orderable: false },
{data: "is_connective", orderable: false}, {data: "id", orderable: false } {data: "id", orderable: false }
], ],
op_html: $('#actions').html() op_html: $('#actions').html()
}; };
...@@ -200,6 +212,8 @@ function addTreeNode() { ...@@ -200,6 +212,8 @@ function addTreeNode() {
}; };
newNode.checked = zTree.getSelectedNodes()[0].checked; newNode.checked = zTree.getSelectedNodes()[0].checked;
zTree.addNodes(parentNode, 0, newNode); zTree.addNodes(parentNode, 0, newNode);
var node = zTree.getNodeByParam('id', newNode.id, parentNode)
zTree.editName(node);
} else { } else {
alert("{% trans 'Create node failed' %}") alert("{% trans 'Create node failed' %}")
} }
...@@ -230,9 +244,9 @@ function removeTreeNode() { ...@@ -230,9 +244,9 @@ function removeTreeNode() {
function editTreeNode() { function editTreeNode() {
hideRMenu(); hideRMenu();
var current_node = zTree.getSelectedNodes()[0]; var current_node = zTree.getSelectedNodes()[0];
if (!current_node){ if (!current_node){
return return
} }
if (current_node.value) { if (current_node.value) {
current_node.name = current_node.value; current_node.name = current_node.value;
...@@ -253,6 +267,8 @@ function OnRightClick(event, treeId, treeNode) { ...@@ -253,6 +267,8 @@ function OnRightClick(event, treeId, treeNode) {
function showRMenu(type, x, y) { function showRMenu(type, x, y) {
$("#rMenu ul").show(); $("#rMenu ul").show();
x -= 220; x -= 220;
x += document.body.scrollLeft;
y += document.body.scrollTop+document.documentElement.scrollTop;
rMenu.css({"top":y+"px", "left":x+"px", "visibility":"visible"}); rMenu.css({"top":y+"px", "left":x+"px", "visibility":"visible"});
$("body").bind("mousedown", onBodyMouseDown); $("body").bind("mousedown", onBodyMouseDown);
...@@ -290,6 +306,7 @@ function onRename(event, treeId, treeNode, isCancel){ ...@@ -290,6 +306,7 @@ function onRename(event, treeId, treeNode, isCancel){
function onSelected(event, treeNode) { function onSelected(event, treeNode) {
var url = asset_table.ajax.url(); var url = asset_table.ajax.url();
url = setUrlParam(url, "node_id", treeNode.id); url = setUrlParam(url, "node_id", treeNode.id);
url = setUrlParam(url, "show_current_asset", getCookie('show_current_asset'));
setCookie('node_selected', treeNode.id); setCookie('node_selected', treeNode.id);
asset_table.ajax.url(url); asset_table.ajax.url(url);
asset_table.ajax.reload(); asset_table.ajax.reload();
...@@ -382,12 +399,13 @@ function initTree() { ...@@ -382,12 +399,13 @@ function initTree() {
}; };
var zNodes = []; var zNodes = [];
$.get("{% url 'api-assets:node-list' %}", function(data, status){ var query_params = {'show_current_asset': getCookie('show_current_asset')};
$.get("{% url 'api-assets:node-list' %}", query_params, function(data, status){
$.each(data, function (index, value) { $.each(data, function (index, value) {
value["pId"] = value["parent"]; value["pId"] = value["parent"];
{#if (value["key"] === "0") {#} if (value["key"] === "0") {
value["open"] = true; value["open"] = true;
{# }#} }
value["name"] = value["value"] + ' (' + value['assets_amount'] + ')'; value["name"] = value["value"] + ' (' + value['assets_amount'] + ')';
value['value'] = value['value']; value['value'] = value['value'];
}); });
...@@ -417,6 +435,13 @@ function toggle() { ...@@ -417,6 +435,13 @@ function toggle() {
$(document).ready(function(){ $(document).ready(function(){
initTable(); initTable();
initTree(); initTree();
if(getCookie('show_current_asset') === 'yes'){
$('#show_all_asset').css('display', 'inline-block');
}
else{
$('#show_current_asset').css('display', 'inline-block');
}
}) })
.on('click', '.labels li', function () { .on('click', '.labels li', function () {
var val = $(this).text(); var val = $(this).text();
...@@ -535,6 +560,20 @@ $(document).ready(function(){ ...@@ -535,6 +560,20 @@ $(document).ready(function(){
flash_message: false flash_message: false
}); });
}) })
.on('click', '.btn-show-current-asset', function(){
hideRMenu();
$(this).css('display', 'none');
$('#show_all_asset').css('display', 'inline-block');
setCookie('show_current_asset', 'yes');
location.reload();
})
.on('click', '.btn-show-all-asset', function(){
hideRMenu();
$(this).css('display', 'none');
$('#show_current_asset').css('display', 'inline-block');
setCookie('show_current_asset', '');
location.reload();
})
.on('click', '.btn_asset_delete', function () { .on('click', '.btn_asset_delete', function () {
var $this = $(this); var $this = $(this);
var $data_table = $("#asset_list_table").DataTable(); var $data_table = $("#asset_list_table").DataTable();
......
...@@ -85,6 +85,9 @@ function initTable() { ...@@ -85,6 +85,9 @@ function initTable() {
var update_btn = '<a href="{% url "assets:domain-gateway-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var update_btn = '<a href="{% url "assets:domain-gateway-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-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-delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var test_btn = '<a class="btn btn-xs btn-warning m-l-xs btn-test" data-uid="{{ DEFAULT_PK }}">{% trans "Test connection" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var test_btn = '<a class="btn btn-xs btn-warning m-l-xs btn-test" data-uid="{{ DEFAULT_PK }}">{% trans "Test connection" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
if(rowData.protocol === 'rdp'){
test_btn = '<a class="btn btn-xs btn-warning m-l-xs btn-test" disabled data-uid="{{ DEFAULT_PK }}">{% trans "Test connection" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
}
$(td).html(update_btn + test_btn + del_btn) $(td).html(update_btn + test_btn + del_btn)
}} }}
], ],
...@@ -120,7 +123,6 @@ $(document).ready(function(){ ...@@ -120,7 +123,6 @@ $(document).ready(function(){
success_message: "可连接", success_message: "可连接",
fail_message: "连接失败" fail_message: "连接失败"
}) })
});
})
</script> </script>
{% endblock %} {% endblock %}
...@@ -66,3 +66,28 @@ ...@@ -66,3 +66,28 @@
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
{% block custom_foot_js %}
<script>
var protocol_id = '#' + '{{ form.protocol.id_for_label }}';
var private_key_id = '#' + '{{ form.private_key_file.id_for_label }}';
var port = '#' + '{{ form.port.id_for_label }}';
function protocolChange() {
if ($(protocol_id + " option:selected").text() === 'rdp') {
$(port).val(3389);
$(private_key_id).closest('.form-group').addClass('hidden')
} else {
$(port).val(22);
$(private_key_id).closest('.form-group').removeClass('hidden')
}
}
$(document).ready(function(){
protocolChange();
})
.on('change', protocol_id, function(){
protocolChange();
});
</script>
{% endblock %}
\ No newline at end of file
...@@ -64,14 +64,14 @@ ...@@ -64,14 +64,14 @@
</tr> </tr>
<tr> <tr>
<td>{% trans 'Protocol' %}:</td> <td>{% trans 'Protocol' %}:</td>
<td><b>{{ system_user.protocol }}</b></td> <td><b id="id_protocol_type">{{ system_user.protocol }}</b></td>
</tr> </tr>
<tr> <tr class="only-ssh">
<td>{% trans 'Sudo' %}:</td> <td>{% trans 'Sudo' %}:</td>
<td><b>{{ system_user.sudo }}</b></td> <td><b>{{ system_user.sudo }}</b></td>
</tr> </tr>
{% if system_user.shell %} {% if system_user.shell %}
<tr> <tr class="only-ssh">
<td>{% trans 'Shell' %}:</td> <td>{% trans 'Shell' %}:</td>
<td><b>{{ system_user.shell }}</b></td> <td><b>{{ system_user.shell }}</b></td>
</tr> </tr>
...@@ -107,14 +107,14 @@ ...@@ -107,14 +107,14 @@
</div> </div>
<div class="col-sm-4" style="padding-left: 0;padding-right: 0"> <div class="col-sm-4" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary"> <div class="panel panel-primary ">
<div class="panel-heading"> <div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %} <i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
</div> </div>
<div class="panel-body"> <div class="panel-body">
<table class="table"> <table class="table">
<tbody> <tbody>
<tr class="no-borders-tr"> <tr class="only-ssh">
<td width="50%">{% trans 'Auto push' %}:</td> <td width="50%">{% trans 'Auto push' %}:</td>
<td> <td>
<span class="pull-right"> <span class="pull-right">
...@@ -130,8 +130,8 @@ ...@@ -130,8 +130,8 @@
</span> </span>
</td> </td>
</tr> </tr>
<tr class="no-borders-tr">
{% if system_user.auto_push %} {% if system_user.auto_push %}
<tr class="only-ssh">
<td width="50%">{% trans 'Push system user now' %}:</td> <td width="50%">{% trans 'Push system user now' %}:</td>
<td> <td>
<span style="float: right"> <span style="float: right">
...@@ -139,8 +139,8 @@ ...@@ -139,8 +139,8 @@
</span> </span>
</td> </td>
</tr> </tr>
<tr>
{% endif %} {% endif %}
<tr class="only-ssh">
<td width="50%">{% trans 'Test assets connective' %}:</td> <td width="50%">{% trans 'Test assets connective' %}:</td>
<td> <td>
<span style="float: right"> <span style="float: right">
...@@ -149,6 +149,15 @@ ...@@ -149,6 +149,15 @@
</td> </td>
</tr> </tr>
<tr>
<td width="50%">{% trans 'Clear auth' %}:</td>
<td>
<span style="float: right">
<button type="button" class="btn btn-primary btn-xs btn-clear-auth" style="width: 54px">{% trans 'Clear' %}</button>
</span>
</td>
</tr>
{# <tr>#} {# <tr>#}
{# <td width="50%">{% trans 'Change auth period' %}:</td>#} {# <td width="50%">{% trans 'Change auth period' %}:</td>#}
{# <td>#} {# <td>#}
...@@ -236,6 +245,10 @@ function updateSystemUserNode(nodes) { ...@@ -236,6 +245,10 @@ function updateSystemUserNode(nodes) {
} }
jumpserver.nodes_selected = {}; jumpserver.nodes_selected = {};
$(document).ready(function () { $(document).ready(function () {
if($('#id_protocol_type').text() === 'rdp'){
$('.only-ssh').addClass('hidden')
}
$(".panel-body .table tr:visible:first").addClass('no-borders-tr');
$('.select2').select2() $('.select2').select2()
.on('select2:select', function(evt) { .on('select2:select', function(evt) {
var data = evt.params.data; var data = evt.params.data;
...@@ -296,7 +309,7 @@ $(document).ready(function () { ...@@ -296,7 +309,7 @@ $(document).ready(function () {
var success = function (data) { var success = function (data) {
var task_id = data.task; var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id); var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600') window.open(url, '', 'width=800,height=600,left=400,top=400')
}; };
APIUpdateAttr({ APIUpdateAttr({
url: the_url, url: the_url,
...@@ -318,6 +331,13 @@ $(document).ready(function () { ...@@ -318,6 +331,13 @@ $(document).ready(function () {
success: success, success: success,
flash_message: false flash_message: false
}); });
}).on('click', '.btn-clear-auth', function () {
var the_url = '{% url "api-assets:system-user-auth-info" pk=system_user.id %}';
APIUpdateAttr({
url: the_url,
method: 'DELETE',
success_message: "{% trans 'Clear auth' %}" + " {% trans 'success' %}"
});
}) })
</script> </script>
{% endblock %} {% endblock %}
...@@ -15,10 +15,3 @@ ...@@ -15,10 +15,3 @@
</div> </div>
{% endblock %} {% endblock %}
{% block custom_foot_js %}
<script>
$(document).ready(function () {
$('.select2').select2();
})
</script>
{% endblock %}
\ No newline at end of file
...@@ -96,14 +96,7 @@ class LDAPTestingAPI(APIView): ...@@ -96,14 +96,7 @@ class LDAPTestingAPI(APIView):
class DjangoSettingsAPI(APIView): class DjangoSettingsAPI(APIView):
def get(self, request): def get(self, request):
if not settings.DEBUG: return Response('Danger, Close now')
return Response('Only debug mode support')
configs = {}
for i in dir(settings):
if i.isupper():
configs[i] = str(getattr(settings, i))
return Response(configs)
# -*- coding: utf-8 -*-
#
from django.core.validators import RegexValidator
from django.utils.translation import ugettext_lazy as _
alphanumeric = RegexValidator(r'^[0-9a-zA-Z_@\-\.]*$', _('Special char not allowed'))
\ No newline at end of file
This diff is collapsed.
...@@ -229,7 +229,11 @@ LOGGING = { ...@@ -229,7 +229,11 @@ LOGGING = {
'django_auth_ldap': { 'django_auth_ldap': {
'handlers': ['console', 'ansible_logs'], 'handlers': ['console', 'ansible_logs'],
'level': "INFO", 'level': "INFO",
} },
# 'django.db': {
# 'handlers': ['console', 'file'],
# 'level': 'DEBUG'
# }
} }
} }
...@@ -329,6 +333,9 @@ AUTH_LDAP_GROUP_SEARCH_FILTER = CONFIG.AUTH_LDAP_GROUP_SEARCH_FILTER ...@@ -329,6 +333,9 @@ AUTH_LDAP_GROUP_SEARCH_FILTER = CONFIG.AUTH_LDAP_GROUP_SEARCH_FILTER
AUTH_LDAP_GROUP_SEARCH = LDAPSearch( AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
AUTH_LDAP_GROUP_SEARCH_OU, ldap.SCOPE_SUBTREE, AUTH_LDAP_GROUP_SEARCH_FILTER AUTH_LDAP_GROUP_SEARCH_OU, ldap.SCOPE_SUBTREE, AUTH_LDAP_GROUP_SEARCH_FILTER
) )
AUTH_LDAP_CONNECTION_OPTIONS = {
ldap.OPT_TIMEOUT: 5
}
AUTH_LDAP_ALWAYS_UPDATE_USER = True AUTH_LDAP_ALWAYS_UPDATE_USER = True
AUTH_LDAP_BACKEND = 'django_auth_ldap.backend.LDAPBackend' AUTH_LDAP_BACKEND = 'django_auth_ldap.backend.LDAPBackend'
......
...@@ -72,7 +72,7 @@ class CeleryTaskLogApi(generics.RetrieveAPIView): ...@@ -72,7 +72,7 @@ class CeleryTaskLogApi(generics.RetrieveAPIView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
mark = request.query_params.get("mark") or str(uuid.uuid4()) mark = request.query_params.get("mark") or str(uuid.uuid4())
task = super().get_object() task = self.get_object()
log_path = task.full_log_path log_path = task.full_log_path
if not log_path or not os.path.isfile(log_path): if not log_path or not os.path.isfile(log_path):
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
<a href="{% url 'ops:adhoc-history-detail' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history detail' %} </a> <a href="{% url 'ops:adhoc-history-detail' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history detail' %} </a>
</li> </li>
<li> <li>
<a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.pk %}','', 'width=800,height=600')"><i class="fa fa-laptop"></i> {% trans 'Output' %} </a> <a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.pk %}','', 'width=800,height=600,left=400,top=400')"><i class="fa fa-laptop"></i> {% trans 'Output' %} </a>
</li> </li>
</ul> </ul>
</div> </div>
......
...@@ -2,38 +2,25 @@ ...@@ -2,38 +2,25 @@
<head> <head>
<title>term.js</title> <title>term.js</title>
<script src="{% static 'js/jquery-2.1.1.js' %}"></script> <script src="{% static 'js/jquery-2.1.1.js' %}"></script>
<script src="{% static 'js/plugins/xterm/xterm.js' %}"></script>
<link rel="stylesheet" href="{% static 'js/plugins/xterm/xterm.css' %}" />
<style> <style>
html { body {
background: #000; background-color: black;
} }
h1 { .xterm-rows {
margin-bottom: 20px; {#padding: 15px;#}
font: 20px/1.5 sans-serif; font-family: "Bitstream Vera Sans Mono", Monaco, "Consolas", Courier, monospace;
} font-size: 13px;
.terminal { }
float: left;
font-family: 'Monaco', 'Consolas', "DejaVu Sans Mono", "Liberation Mono", monospace;
font-size: 12px;
color: #f0f0f0;
background-color: #555;
padding: 20px 20px 20px;
}
.terminal-cursor {
color: #000;
background: #f0f0f0;
}
</style> </style>
</head> </head>
<div class="container"> <div id="term" style="height: 100%;width: 100%">
<div id="term">
</div> </div>
</div>
<script src="{% static 'js/term.js' %}"></script>
<script> <script>
var rowHeight = 1; var rowHeight = 18;
var colWidth = 1; var colWidth = 10;
var mark = ''; var mark = '';
var url = "{% url 'api-ops:celery-task-log' pk=object.id %}"; var url = "{% url 'api-ops:celery-task-log' pk=object.id %}";
var term; var term;
...@@ -42,13 +29,16 @@ ...@@ -42,13 +29,16 @@
var interval = 200; var interval = 200;
function calWinSize() { function calWinSize() {
var t = $('.terminal'); var t = $('#marker');
rowHeight = 1.00 * t.height() / 24; {#rowHeight = 1.00 * t.height();#}
colWidth = 1.00 * t.width() / 80; {#colWidth = 1.00 * t.width() / 6;#}
} }
function resize() { function resize() {
var rows = Math.floor(window.innerHeight / rowHeight) - 2; {#console.log(rowHeight, window.innerHeight);#}
var cols = Math.floor(window.innerWidth / colWidth) - 10; {#console.log(colWidth, window.innerWidth);#}
var rows = Math.floor(window.innerHeight / rowHeight) - 1;
var cols = Math.floor(window.innerWidth / colWidth) - 2;
console.log(rows, cols);
term.resize(cols, rows); term.resize(cols, rows);
} }
function requestAndWrite() { function requestAndWrite() {
...@@ -74,21 +64,18 @@ ...@@ -74,21 +64,18 @@
} }
} }
$(document).ready(function () { $(document).ready(function () {
term = new Terminal({ term = new Terminal();
cols: 80, term.open(document.getElementById('term'));
rows: 24, term.resize(80, 24);
useStyle: true, resize();
screenKeys: false,
convertEol: false,
cursorBlink: false
});
term.open();
term.on('data', function (data) { term.on('data', function (data) {
term.write(data.replace('\r', '\r\n')) {#term.write(data.replace('\r', '\r\n'))#}
term.write(data);
}); });
calWinSize(); window.onresize = function () {
resize(); resize()
$('.terminal').detach().appendTo('#term'); };
{#$('.terminal').detach().appendTo('#term');#}
setInterval(function () { setInterval(function () {
requestAndWrite() requestAndWrite()
}, interval) }, interval)
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
<a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a> <a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a>
</li> </li>
<li> <li>
<a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.latest_history.pk %}','', 'width=800,height=600')"><i class="fa fa-laptop"></i> {% trans 'Last run output' %} </a> <a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.latest_history.pk %}','', 'width=800,height=600,left=400,top=400')"><i class="fa fa-laptop"></i> {% trans 'Last run output' %} </a>
</li> </li>
</ul> </ul>
</div> </div>
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
<a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a> <a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a>
</li> </li>
<li> <li>
<a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.latest_history.pk %}','', 'width=800,height=600')"><i class="fa fa-laptop"></i> {% trans 'Last run output' %} </a> <a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.latest_history.pk %}','', 'width=800,height=600,left=400,top=400')"><i class="fa fa-laptop"></i> {% trans 'Last run output' %} </a>
</li> </li>
</ul> </ul>
</div> </div>
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
<a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a> <a href="{% url 'ops:task-history' pk=object.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Run history' %} </a>
</li> </li>
<li> <li>
<a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.latest_history.pk %}','', 'width=800,height=600')"><i class="fa fa-laptop"></i> {% trans 'Last run output' %} </a> <a class="text-center celery-task-log" onclick="window.open('{% url 'ops:celery-task-log' pk=object.latest_history.pk %}','', 'width=800,height=600,left=400,top=400')"><i class="fa fa-laptop"></i> {% trans 'Last run output' %} </a>
</li> </li>
</ul> </ul>
</div> </div>
......
...@@ -115,7 +115,7 @@ $(document).ready(function() { ...@@ -115,7 +115,7 @@ $(document).ready(function() {
var success = function(data) { var success = function(data) {
var task_id = data.task; var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id); var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600') window.open(url, '', 'width=800,height=600,left=400,top=400')
}; };
APIUpdateAttr({ APIUpdateAttr({
url: the_url, url: the_url,
......
...@@ -6,7 +6,7 @@ from rest_framework.views import APIView, Response ...@@ -6,7 +6,7 @@ from rest_framework.views import APIView, Response
from rest_framework.generics import ListAPIView, get_object_or_404, RetrieveUpdateAPIView from rest_framework.generics import ListAPIView, get_object_or_404, RetrieveUpdateAPIView
from rest_framework import viewsets from rest_framework import viewsets
from common.utils import set_or_append_attr_bulk from common.utils import set_or_append_attr_bulk, get_object_or_none
from users.permissions import IsValidUser, IsSuperUser, IsSuperUserOrAppUser from users.permissions import IsValidUser, IsSuperUser, IsSuperUserOrAppUser
from .utils import AssetPermissionUtil from .utils import AssetPermissionUtil
from .models import AssetPermission from .models import AssetPermission
...@@ -41,7 +41,7 @@ class AssetPermissionViewSet(viewsets.ModelViewSet): ...@@ -41,7 +41,7 @@ class AssetPermissionViewSet(viewsets.ModelViewSet):
asset = get_object_or_404(Asset, pk=asset_id) asset = get_object_or_404(Asset, pk=asset_id)
permissions = set(queryset.filter(assets=asset)) permissions = set(queryset.filter(assets=asset))
for node in asset.nodes.all(): for node in asset.nodes.all():
inherit_nodes.update(set(node.ancestor_with_node)) inherit_nodes.update(set(node.ancestor_with_self))
elif node_id: elif node_id:
node = get_object_or_404(Node, pk=node_id) node = get_object_or_404(Node, pk=node_id)
permissions = set(queryset.filter(nodes=node)) permissions = set(queryset.filter(nodes=node))
...@@ -147,8 +147,13 @@ class UserGrantedNodeAssetsApi(ListAPIView): ...@@ -147,8 +147,13 @@ class UserGrantedNodeAssetsApi(ListAPIView):
user = get_object_or_404(User, id=user_id) user = get_object_or_404(User, id=user_id)
else: else:
user = self.request.user user = self.request.user
node = get_object_or_404(Node, id=node_id)
nodes = AssetPermissionUtil.get_user_nodes_with_assets(user) nodes = AssetPermissionUtil.get_user_nodes_with_assets(user)
node = get_object_or_none(Node, id=node_id)
if not node:
unnode = [node for node in nodes if node.name == 'Unnode']
node = unnode[0] if unnode else None
assets = nodes.get(node, []) assets = nodes.get(node, [])
for asset, system_users in assets.items(): for asset, system_users in assets.items():
asset.system_users_granted = system_users asset.system_users_granted = system_users
......
...@@ -7,13 +7,23 @@ from django.utils import timezone ...@@ -7,13 +7,23 @@ from django.utils import timezone
from common.utils import date_expired_default, set_or_append_attr_bulk from common.utils import date_expired_default, set_or_append_attr_bulk
class ValidManager(models.Manager): class AssetPermissionQuerySet(models.QuerySet):
def get_queryset(self): def active(self):
return super().get_queryset().filter(is_active=True) \ return self.filter(is_active=True)
.filter(date_start__lt=timezone.now())\
def valid(self):
return self.active().filter(date_start__lt=timezone.now())\
.filter(date_expired__gt=timezone.now()) .filter(date_expired__gt=timezone.now())
class AssetPermissionManager(models.Manager):
def get_queryset(self):
return AssetPermissionQuerySet(self.model, using=self._db)
def valid(self):
return self.get_queryset().valid()
class AssetPermission(models.Model): class AssetPermission(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
...@@ -23,14 +33,13 @@ class AssetPermission(models.Model): ...@@ -23,14 +33,13 @@ class AssetPermission(models.Model):
nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True, verbose_name=_("Nodes")) nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True, verbose_name=_("Nodes"))
system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_permissions', verbose_name=_("System user")) system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_permissions', verbose_name=_("System user"))
is_active = models.BooleanField(default=True, verbose_name=_('Active')) is_active = models.BooleanField(default=True, verbose_name=_('Active'))
date_start = models.DateTimeField(default=timezone.now, verbose_name=_("Date start")) date_start = models.DateTimeField(default=timezone.now, db_index=True, verbose_name=_("Date start"))
date_expired = models.DateTimeField(default=date_expired_default, verbose_name=_('Date expired')) date_expired = models.DateTimeField(default=date_expired_default, db_index=True, verbose_name=_('Date expired'))
created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by')) created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by'))
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Date created')) date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Date created'))
comment = models.TextField(verbose_name=_('Comment'), blank=True) comment = models.TextField(verbose_name=_('Comment'), blank=True)
objects = models.Manager() objects = AssetPermissionManager()
valid = ValidManager()
def __str__(self): def __str__(self):
return self.name return self.name
......
...@@ -9,7 +9,7 @@ from common.fields import StringManyToManyField ...@@ -9,7 +9,7 @@ from common.fields import StringManyToManyField
class AssetPermissionCreateUpdateSerializer(serializers.ModelSerializer): class AssetPermissionCreateUpdateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = AssetPermission model = AssetPermission
exclude = ('id', 'created_by', 'date_created') exclude = ('created_by', 'date_created')
class AssetPermissionListSerializer(serializers.ModelSerializer): class AssetPermissionListSerializer(serializers.ModelSerializer):
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</div> </div>
</div> </div>
<div class="form-group {% if form.date_expired.errors or form.date_start.errors %} has-error {% endif %}" id="date_5"> <div class="form-group {% if form.date_expired.errors or form.date_start.errors %} has-error {% endif %}" id="date_5">
<label for="{{ form.date_expired.id_for_label }}" class="col-sm-2 control-label">{{ form.date_expired.label }}</label> <label for="{{ form.date_expired.id_for_label }}" class="col-sm-2 control-label">{% trans 'Validity period' %}</label>
<div class="col-sm-9"> <div class="col-sm-9">
<div class="input-daterange input-group" id="datepicker"> <div class="input-daterange input-group" id="datepicker">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span> <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
......
...@@ -78,12 +78,12 @@ var zTree, table, show = 0; ...@@ -78,12 +78,12 @@ var zTree, table, show = 0;
function onSelected(event, treeNode) { function onSelected(event, treeNode) {
setCookie('node_selected', treeNode.id); setCookie('node_selected', treeNode.id);
var url = table.ajax.url(); var url = table.ajax.url();
if (treeNode.is_asset) { if (treeNode.is_node) {
url = setUrlParam(url, 'node', "");
url = setUrlParam(url, 'asset', treeNode.id)
} else {
url = setUrlParam(url, 'asset', ""); url = setUrlParam(url, 'asset', "");
url = setUrlParam(url, 'node', treeNode.id) url = setUrlParam(url, 'node', treeNode.id)
} else {
url = setUrlParam(url, 'node', "");
url = setUrlParam(url, 'asset', treeNode.id)
} }
setCookie('node_selected', treeNode.id); setCookie('node_selected', treeNode.id);
table.ajax.url(url); table.ajax.url(url);
...@@ -113,14 +113,14 @@ function filter(treeId, parentNode, childNodes) { ...@@ -113,14 +113,14 @@ function filter(treeId, parentNode, childNodes) {
$.each(childNodes, function (index, value) { $.each(childNodes, function (index, value) {
value["pId"] = value["parent"]; value["pId"] = value["parent"];
value["name"] = value["value"]; value["name"] = value["value"];
value["isParent"] = value["assets_amount"] !== 0; value["isParent"] = value["is_node"];
value["iconSkin"] = value["is_asset"] ? "file" : null; value["iconSkin"] = value["is_node"] ? null : 'file';
}); });
return childNodes; return childNodes;
} }
function beforeAsync(treeId, treeNode) { function beforeAsync(treeId, treeNode) {
return true; return treeNode.is_node
} }
function makeLabel(data) { function makeLabel(data) {
...@@ -226,7 +226,7 @@ function initTree() { ...@@ -226,7 +226,7 @@ function initTree() {
}, },
async: { async: {
enable: true, enable: true,
url: "{% url 'api-assets:node-children-2' %}?assets=1", url: "{% url 'api-assets:node-children-2' %}?assets=1&all=",
autoParam:["id", "name=n", "level=lv"], autoParam:["id", "name=n", "level=lv"],
dataFilter: filter, dataFilter: filter,
type: 'get' type: 'get'
...@@ -238,18 +238,19 @@ function initTree() { ...@@ -238,18 +238,19 @@ function initTree() {
}; };
var zNodes = []; var zNodes = [];
$.get("{% url 'api-assets:node-children-2' %}", function(data, status){ $.get("{% url 'api-assets:node-children-2' %}?assets=1&all=", function(data, status){
$.each(data, function (index, value) { $.each(data, function (index, value) {
value["pId"] = value["parent"]; value["pId"] = value["parent"];
value["isParent"] = value["assets_amount"] !== 0;
value["name"] = value["value"]; value["name"] = value["value"];
value["open"] = value["key"] === "0"; value["open"] = value["key"] === "0";
value["isParent"] = value["is_node"];
value["iconSkin"] = value["is_node"] ? null : 'file';
}); });
zNodes = data; zNodes = data;
{#$.fn.zTree.init($("#assetTree"), setting);#} {#$.fn.zTree.init($("#assetTree"), setting);#}
$.fn.zTree.init($("#assetTree"), setting, zNodes); $.fn.zTree.init($("#assetTree"), setting, zNodes);
zTree = $.fn.zTree.getZTreeObj("assetTree"); zTree = $.fn.zTree.getZTreeObj("assetTree");
selectQueryNode(); {#selectQueryNode();#}
}); });
} }
...@@ -286,10 +287,10 @@ $(document).ready(function(){ ...@@ -286,10 +287,10 @@ $(document).ready(function(){
var _nodes = []; var _nodes = [];
var _assets = []; var _assets = [];
$.each(nodes, function (id, node) { $.each(nodes, function (id, node) {
if (node.is_asset) { if (node.is_node) {
_assets.push(node.id)
} else {
_nodes.push(node.id) _nodes.push(node.id)
} else {
_assets.push(node.id)
} }
}); });
url += "?assets=" + _assets.join(",") + "&nodes=" + _nodes.join(","); url += "?assets=" + _assets.join(",") + "&nodes=" + _nodes.join(",");
...@@ -303,6 +304,7 @@ $(document).ready(function(){ ...@@ -303,6 +304,7 @@ $(document).ready(function(){
if (row.child.isShown()) { if (row.child.isShown()) {
tr.removeClass('details'); tr.removeClass('details');
$(this).children('i:first-child').removeClass('fa-angle-down').addClass('fa-angle-right');
row.child.hide(); row.child.hide();
// Remove from the 'open' array // Remove from the 'open' array
...@@ -310,7 +312,7 @@ $(document).ready(function(){ ...@@ -310,7 +312,7 @@ $(document).ready(function(){
} }
else { else {
tr.addClass('details'); tr.addClass('details');
$('.toggle i').removeClass('fa-angle-right').addClass('fa-angle-down'); $(this).children('i:first-child').removeClass('fa-angle-right').addClass('fa-angle-down');
row.child(format(row.data())).show(); row.child(format(row.data())).show();
// Add to the 'open' array // Add to the 'open' array
if ( idx === -1 ) { if ( idx === -1 ) {
......
...@@ -8,31 +8,75 @@ import copy ...@@ -8,31 +8,75 @@ import copy
from common.utils import set_or_append_attr_bulk, get_logger from common.utils import set_or_append_attr_bulk, get_logger
from .models import AssetPermission from .models import AssetPermission
from .hands import Node
logger = get_logger(__file__) logger = get_logger(__file__)
class AssetPermissionUtil: class Tree:
def __init__(self):
self.__all_nodes = list(Node.objects.all())
self.__node_asset_map = defaultdict(set)
self.nodes = defaultdict(dict)
self.root = Node.root()
self.init_node_asset_map()
def init_node_asset_map(self):
for node in self.__all_nodes:
assets = node.get_assets().values_list('id', flat=True)
for asset in assets:
self.__node_asset_map[str(asset)].add(node)
def add_asset(self, asset, system_users):
nodes = self.__node_asset_map.get(str(asset.id), [])
self.add_nodes(nodes)
for node in nodes:
self.nodes[node][asset].update(system_users)
def add_node(self, node):
if node in self.nodes:
return
else:
self.nodes[node] = defaultdict(set)
if node.key == self.root.key:
return
parent_key = ':'.join(node.key.split(':')[:-1])
for n in self.__all_nodes:
if n.key == parent_key:
self.add_node(n)
break
def add_nodes(self, nodes):
for node in nodes:
self.add_node(node)
class AssetPermissionUtil:
@staticmethod @staticmethod
def get_user_permissions(user): def get_user_permissions(user):
return AssetPermission.valid.all().filter(users=user) return AssetPermission.objects.all().valid().filter(users=user)
@staticmethod @staticmethod
def get_user_group_permissions(user_group): def get_user_group_permissions(user_group):
return AssetPermission.valid.all().filter(user_groups=user_group) return AssetPermission.objects.all().valid().filter(
user_groups=user_group
)
@staticmethod @staticmethod
def get_asset_permissions(asset): def get_asset_permissions(asset):
return AssetPermission.valid.all().filter(assets=asset) return AssetPermission.objects.all().valid().filter(
assets=asset
)
@staticmethod @staticmethod
def get_node_permissions(node): def get_node_permissions(node):
return AssetPermission.valid.all().filter(nodes=node) return AssetPermission.objects.all().valid().filter(nodes=node)
@staticmethod @staticmethod
def get_system_user_permissions(system_user): def get_system_user_permissions(system_user):
return AssetPermission.objects.all().filter(system_users=system_user) return AssetPermission.objects.valid().all().filter(
system_users=system_user
)
@classmethod @classmethod
def get_user_group_nodes(cls, group): def get_user_group_nodes(cls, group):
...@@ -51,7 +95,7 @@ class AssetPermissionUtil: ...@@ -51,7 +95,7 @@ class AssetPermissionUtil:
assets = defaultdict(set) assets = defaultdict(set)
permissions = cls.get_user_group_permissions(group) permissions = cls.get_user_group_permissions(group)
for perm in permissions: for perm in permissions:
_assets = perm.assets.all() _assets = perm.assets.all().valid()
_system_users = perm.system_users.all() _system_users = perm.system_users.all()
set_or_append_attr_bulk(_assets, 'permission', perm.id) set_or_append_attr_bulk(_assets, 'permission', perm.id)
for asset in _assets: for asset in _assets:
...@@ -63,7 +107,7 @@ class AssetPermissionUtil: ...@@ -63,7 +107,7 @@ class AssetPermissionUtil:
assets = defaultdict(set) assets = defaultdict(set)
nodes = cls.get_user_group_nodes(group) nodes = cls.get_user_group_nodes(group)
for node, _system_users in nodes.items(): for node, _system_users in nodes.items():
_assets = node.get_all_assets() _assets = node.get_all_valid_assets()
set_or_append_attr_bulk(_assets, 'inherit_node', node.id) set_or_append_attr_bulk(_assets, 'inherit_node', node.id)
set_or_append_attr_bulk(_assets, 'permission', getattr(node, 'permission', None)) set_or_append_attr_bulk(_assets, 'permission', getattr(node, 'permission', None))
for asset in _assets: for asset in _assets:
...@@ -82,28 +126,26 @@ class AssetPermissionUtil: ...@@ -82,28 +126,26 @@ class AssetPermissionUtil:
return assets return assets
@classmethod @classmethod
def get_user_group_nodes_with_assets(cls, user): def get_user_group_nodes_with_assets(cls, group):
""" """
:param user: :param group:
:return: {node: {asset: set(su1, su2)}} :return: {node: {asset: set(su1, su2)}}
""" """
nodes = defaultdict(dict) _assets = cls.get_user_group_assets(group)
_assets = cls.get_user_group_assets(user) tree = Tree()
for asset, _system_users in _assets.items(): for asset, _system_users in _assets.items():
_nodes = asset.get_nodes() _nodes = asset.get_nodes()
tree.add_nodes(_nodes)
for node in _nodes: for node in _nodes:
if asset in nodes[node]: tree.nodes[node][asset].update(_system_users)
nodes[node][asset].update(_system_users) return tree.nodes
else:
nodes[node][asset] = _system_users
return nodes
@classmethod @classmethod
def get_user_assets_direct(cls, user): def get_user_assets_direct(cls, user):
assets = defaultdict(set) assets = defaultdict(set)
permissions = list(cls.get_user_permissions(user)) permissions = list(cls.get_user_permissions(user))
for perm in permissions: for perm in permissions:
_assets = perm.assets.all() _assets = perm.assets.all().valid()
_system_users = perm.system_users.all() _system_users = perm.system_users.all()
set_or_append_attr_bulk(_assets, 'permission', perm.id) set_or_append_attr_bulk(_assets, 'permission', perm.id)
for asset in _assets: for asset in _assets:
...@@ -122,12 +164,30 @@ class AssetPermissionUtil: ...@@ -122,12 +164,30 @@ class AssetPermissionUtil:
nodes[node].update(set(_system_users)) nodes[node].update(set(_system_users))
return nodes return nodes
@classmethod
def get_user_nodes_inherit_group(cls, user):
nodes = defaultdict(set)
groups = user.groups.all()
for group in groups:
_nodes = cls.get_user_group_nodes(group)
for node, system_users in _nodes.items():
nodes[node].update(set(system_users))
return nodes
@classmethod
def get_user_nodes(cls, user):
nodes = cls.get_user_nodes_direct(user)
nodes_inherit = cls.get_user_nodes_inherit_group(user)
for node, system_users in nodes_inherit.items():
nodes[node].update(set(system_users))
return nodes
@classmethod @classmethod
def get_user_nodes_assets_direct(cls, user): def get_user_nodes_assets_direct(cls, user):
assets = defaultdict(set) assets = defaultdict(set)
nodes = cls.get_user_nodes_direct(user) nodes = cls.get_user_nodes_direct(user)
for node, _system_users in nodes.items(): for node, _system_users in nodes.items():
_assets = node.get_all_assets() _assets = node.get_all_valid_assets()
set_or_append_attr_bulk(_assets, 'inherit_node', node.id) set_or_append_attr_bulk(_assets, 'inherit_node', node.id)
set_or_append_attr_bulk(_assets, 'permission', getattr(node, 'permission', None)) set_or_append_attr_bulk(_assets, 'permission', getattr(node, 'permission', None))
for asset in _assets: for asset in _assets:
...@@ -164,26 +224,25 @@ class AssetPermissionUtil: ...@@ -164,26 +224,25 @@ class AssetPermissionUtil:
:param user: :param user:
:return: {node: {asset: set(su1, su2)}} :return: {node: {asset: set(su1, su2)}}
""" """
nodes = defaultdict(dict) tree = Tree()
_assets = cls.get_user_assets(user) _assets = cls.get_user_assets(user)
for asset, _system_users in _assets.items(): for asset, _system_users in _assets.items():
_nodes = asset.get_nodes() tree.add_asset(asset, _system_users)
for node in _nodes: # _nodes = asset.get_nodes()
if asset in nodes[node]: # tree.add_nodes(_nodes)
nodes[node][asset].update(_system_users) # for node in _nodes:
else: # tree.nodes[node][asset].update(_system_users)
nodes[node][asset] = _system_users return tree.nodes
return nodes
@classmethod @classmethod
def get_system_user_assets(cls, system_user): def get_system_user_assets(cls, system_user):
assets = set() assets = set()
permissions = cls.get_system_user_permissions(system_user) permissions = cls.get_system_user_permissions(system_user)
for perm in permissions: for perm in permissions:
assets.update(set(perm.assets.all())) assets.update(set(perm.assets.all().valid()))
nodes = perm.nodes.all() nodes = perm.nodes.all()
for node in nodes: for node in nodes:
assets.update(set(node.get_all_assets())) assets.update(set(node.get_all_valid_assets()))
return assets return assets
@classmethod @classmethod
...@@ -228,7 +287,7 @@ class NodePermissionUtil: ...@@ -228,7 +287,7 @@ class NodePermissionUtil:
nodes = copy.deepcopy(nodes_directed) nodes = copy.deepcopy(nodes_directed)
for node, system_users in nodes_directed.items(): for node, system_users in nodes_directed.items():
for child in node.get_family(): for child in node.get_all_children_with_self():
nodes[child].update(system_users) nodes[child].update(system_users)
return nodes return nodes
...@@ -243,7 +302,7 @@ class NodePermissionUtil: ...@@ -243,7 +302,7 @@ class NodePermissionUtil:
nodes_with_assets = dict() nodes_with_assets = dict()
for node, system_users in nodes.items(): for node, system_users in nodes.items():
nodes_with_assets[node] = { nodes_with_assets[node] = {
'assets': node.get_active_assets(), 'assets': node.get_valid_assets(),
'system_users': system_users 'system_users': system_users
} }
return nodes_with_assets return nodes_with_assets
...@@ -274,7 +333,7 @@ class NodePermissionUtil: ...@@ -274,7 +333,7 @@ class NodePermissionUtil:
nodes_with_assets = dict() nodes_with_assets = dict()
for node, system_users in nodes.items(): for node, system_users in nodes.items():
nodes_with_assets[node] = { nodes_with_assets[node] = {
'assets': node.get_active_assets(), 'assets': node.get_valid_assets(),
'system_users': system_users 'system_users': system_users
} }
return nodes_with_assets return nodes_with_assets
......
...@@ -42,7 +42,7 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, CreateView): ...@@ -42,7 +42,7 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, CreateView):
if nodes_id: if nodes_id:
nodes_id = nodes_id.split(",") nodes_id = nodes_id.split(",")
nodes = Node.objects.filter(id__in=nodes_id) nodes = Node.objects.filter(id__in=nodes_id).exclude(id=Node.root().id)
form['nodes'].initial = nodes form['nodes'].initial = nodes
if assets_id: if assets_id:
assets_id = assets_id.split(",") assets_id = assets_id.split(",")
......
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
<div class="footer fixed"> <div class="footer fixed">
<div class="pull-right"> <div class="pull-right">
Version <strong>1.2.1-{% include '_build.html' %}</strong> GPLv2. Version <strong>1.3.1-{% include '_build.html' %}</strong> GPLv2.
<img style="display: none" src="http://www.jumpserver.org/img/evaluate_avatar1.jpg"> <img style="display: none" src="http://www.jumpserver.org/img/evaluate_avatar1.jpg">
</div> </div>
<div> <div>
......
This diff is collapsed.
...@@ -7,19 +7,19 @@ TYPE_ENGINE_MAPPING = { ...@@ -7,19 +7,19 @@ TYPE_ENGINE_MAPPING = {
} }
def get_command_store(): def get_command_storage():
params = settings.COMMAND_STORAGE config = settings.COMMAND_STORAGE
engine_class = import_module(params['ENGINE']) engine_class = import_module(config['ENGINE'])
storage = engine_class.CommandStore(params) storage = engine_class.CommandStore(config)
return storage return storage
def get_terminal_command_store(): def get_terminal_command_storages():
storage_list = {} storage_list = {}
for name, params in settings.TERMINAL_COMMAND_STORAGE.items(): for name, params in settings.TERMINAL_COMMAND_STORAGE.items():
tp = params['TYPE'] tp = params['TYPE']
if tp == 'server': if tp == 'server':
storage = get_command_store() storage = get_command_storage()
else: else:
if not TYPE_ENGINE_MAPPING.get(tp): if not TYPE_ENGINE_MAPPING.get(tp):
continue continue
...@@ -29,9 +29,9 @@ def get_terminal_command_store(): ...@@ -29,9 +29,9 @@ def get_terminal_command_store():
return storage_list return storage_list
def get_multi_command_store(): def get_multi_command_storage():
from .command.multi import CommandStore from .command.multi import CommandStore
storage_list = get_terminal_command_store().values() storage_list = get_terminal_command_storages().values()
storage = CommandStore(storage_list) storage = CommandStore(storage_list)
return storage return storage
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from jms_es_sdk import ESStore from jms_storage.es import ESStorage
from .base import CommandBase from .base import CommandBase
from .models import AbstractSessionCommand from .models import AbstractSessionCommand
class CommandStore(CommandBase, ESStore): class CommandStore(ESStorage, CommandBase):
def __init__(self, params): def __init__(self, params):
hosts = params.get('HOSTS', ['http://localhost']) super().__init__(params)
ESStore.__init__(self, hosts=hosts)
def save(self, command):
return ESStore.save(self, command)
def bulk_save(self, commands):
return ESStore.bulk_save(self, commands)
def filter(self, date_from=None, date_to=None, def filter(self, date_from=None, date_to=None,
user=None, asset=None, system_user=None, user=None, asset=None, system_user=None,
input=None, session=None): input=None, session=None):
data = ESStore.filter( data = super().filter(date_from=date_from, date_to=date_to,
self, date_from=date_from, date_to=date_to, user=user, asset=asset, system_user=system_user,
user=user, asset=asset, system_user=system_user, input=input, session=session)
input=input, session=session
)
return AbstractSessionCommand.from_multi_dict( return AbstractSessionCommand.from_multi_dict(
[item["_source"] for item in data["hits"] if item] [item["_source"] for item in data["hits"] if item]
) )
def count(self, date_from=None, date_to=None,
user=None, asset=None, system_user=None,
input=None, session=None):
amount = ESStore.count(
self, date_from=date_from, date_to=date_to,
user=user, asset=asset, system_user=system_user,
input=input, session=session
)
return amount
...@@ -9,7 +9,7 @@ from rest_framework_bulk.serializers import BulkListSerializer ...@@ -9,7 +9,7 @@ from rest_framework_bulk.serializers import BulkListSerializer
from common.mixins import BulkSerializerMixin from common.mixins import BulkSerializerMixin
from common.utils import get_object_or_none from common.utils import get_object_or_none
from .models import Terminal, Status, Session, Task from .models import Terminal, Status, Session, Task
from .backends import get_multi_command_store from .backends import get_multi_command_storage
class TerminalSerializer(serializers.ModelSerializer): class TerminalSerializer(serializers.ModelSerializer):
...@@ -47,7 +47,7 @@ class TerminalSerializer(serializers.ModelSerializer): ...@@ -47,7 +47,7 @@ class TerminalSerializer(serializers.ModelSerializer):
class SessionSerializer(serializers.ModelSerializer): class SessionSerializer(serializers.ModelSerializer):
command_amount = serializers.SerializerMethodField() command_amount = serializers.SerializerMethodField()
command_store = get_multi_command_store() command_store = get_multi_command_storage()
class Meta: class Meta:
model = Session model = Session
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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