mirror of https://github.com/jumpserver/jumpserver
commit
24bdaecab4
|
@ -2,4 +2,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
__version__ = "1.0.0"
|
||||
__version__ = "1.3.0"
|
||||
|
|
|
@ -50,7 +50,9 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
|
|||
if node_id:
|
||||
node = get_object_or_404(Node, id=node_id)
|
||||
if not node.is_root():
|
||||
queryset = queryset.filter(nodes__key__startswith=node.key).distinct()
|
||||
queryset = queryset.filter(
|
||||
nodes__key__regex='{}(:[0-9]+)*$'.format(node.key),
|
||||
).distinct()
|
||||
return queryset
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ from .. import serializers
|
|||
logger = get_logger(__file__)
|
||||
__all__ = [
|
||||
'NodeViewSet', 'NodeChildrenApi',
|
||||
'NodeAssetsApi', 'NodeWithAssetsApi',
|
||||
'NodeAddAssetsApi', 'NodeRemoveAssetsApi',
|
||||
'NodeAddChildrenApi', 'RefreshNodeHardwareInfoApi',
|
||||
'TestNodeConnectiveApi'
|
||||
|
@ -47,6 +48,34 @@ class NodeViewSet(BulkModelViewSet):
|
|||
serializer.save()
|
||||
|
||||
|
||||
class NodeWithAssetsApi(generics.ListAPIView):
|
||||
permission_classes = (IsSuperUser,)
|
||||
serializers = serializers.NodeSerializer
|
||||
|
||||
def get_node(self):
|
||||
pk = self.kwargs.get('pk') or self.request.query_params.get('node')
|
||||
if not pk:
|
||||
node = Node.root()
|
||||
else:
|
||||
node = get_object_or_404(Node, pk)
|
||||
return node
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = []
|
||||
node = self.get_node()
|
||||
children = node.get_children()
|
||||
assets = node.get_assets()
|
||||
queryset.extend(list(children))
|
||||
|
||||
for asset in assets:
|
||||
node = Node()
|
||||
node.id = asset.id
|
||||
node.parent = node.id
|
||||
node.value = asset.hostname
|
||||
queryset.append(node)
|
||||
return queryset
|
||||
|
||||
|
||||
class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
|
||||
queryset = Node.objects.all()
|
||||
permission_classes = (IsSuperUser,)
|
||||
|
@ -69,14 +98,54 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
|
|||
status=201,
|
||||
)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
if self.request.query_params.get("all"):
|
||||
children = instance.get_all_children()
|
||||
def get_object(self):
|
||||
pk = self.kwargs.get('pk') or self.request.query_params.get('id')
|
||||
if not pk:
|
||||
node = Node.root()
|
||||
else:
|
||||
children = instance.get_children()
|
||||
response = [{"id": node.id, "key": node.key, "value": node.value} for node in children]
|
||||
return Response(response, status=200)
|
||||
node = get_object_or_404(Node, pk=pk)
|
||||
return node
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = []
|
||||
query_all = self.request.query_params.get("all")
|
||||
query_assets = self.request.query_params.get('assets')
|
||||
node = self.get_object()
|
||||
if node == Node.root():
|
||||
queryset.append(node)
|
||||
if query_all:
|
||||
children = node.get_all_children()
|
||||
else:
|
||||
children = node.get_children()
|
||||
|
||||
queryset.extend(list(children))
|
||||
if query_assets:
|
||||
assets = node.get_assets()
|
||||
for asset in assets:
|
||||
node_fake = Node()
|
||||
node_fake.id = asset.id
|
||||
node_fake.parent = node
|
||||
node_fake.value = asset.hostname
|
||||
node_fake.is_asset = True
|
||||
queryset.append(node_fake)
|
||||
return queryset
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
|
||||
class NodeAssetsApi(generics.ListAPIView):
|
||||
permission_classes = (IsSuperUser,)
|
||||
serializer_class = serializers.AssetSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
node_id = self.kwargs.get('pk')
|
||||
query_all = self.request.query_params.get('all')
|
||||
instance = get_object_or_404(Node, pk=node_id)
|
||||
if query_all:
|
||||
return instance.get_all_assets()
|
||||
else:
|
||||
return instance.get_assets()
|
||||
|
||||
|
||||
class NodeAddChildrenApi(generics.UpdateAPIView):
|
||||
|
@ -146,4 +215,3 @@ class TestNodeConnectiveApi(APIView):
|
|||
task_name = _("测试节点下资产是否可连接: {}".format(node.name))
|
||||
task = test_asset_connectability_util.delay(assets, task_name=task_name)
|
||||
return Response({"task": task.id})
|
||||
|
||||
|
|
|
@ -27,13 +27,16 @@ class AssetCreateForm(forms.ModelForm):
|
|||
'class': 'select2', 'data-placeholder': _('Admin user')
|
||||
}),
|
||||
'labels': forms.SelectMultiple(attrs={
|
||||
'class': 'select2', 'data-placeholder': _('Labels')
|
||||
'class': 'select2', 'data-placeholder': _('Label')
|
||||
}),
|
||||
'port': forms.TextInput(),
|
||||
'domain': forms.Select(attrs={
|
||||
'class': 'select2', 'data-placeholder': _('Domain')
|
||||
}),
|
||||
}
|
||||
labels = {
|
||||
'nodes': _("Node"),
|
||||
}
|
||||
help_texts = {
|
||||
'hostname': '* required',
|
||||
'ip': '* required',
|
||||
|
@ -57,19 +60,22 @@ class AssetUpdateForm(forms.ModelForm):
|
|||
]
|
||||
widgets = {
|
||||
'nodes': forms.SelectMultiple(attrs={
|
||||
'class': 'select2', 'data-placeholder': _('Nodes')
|
||||
'class': 'select2', 'data-placeholder': _('Node')
|
||||
}),
|
||||
'admin_user': forms.Select(attrs={
|
||||
'class': 'select2', 'data-placeholder': _('Admin user')
|
||||
}),
|
||||
'labels': forms.SelectMultiple(attrs={
|
||||
'class': 'select2', 'data-placeholder': _('Labels')
|
||||
'class': 'select2', 'data-placeholder': _('Label')
|
||||
}),
|
||||
'port': forms.TextInput(),
|
||||
'domain': forms.Select(attrs={
|
||||
'class': 'select2', 'data-placeholder': _('Domain')
|
||||
}),
|
||||
}
|
||||
labels = {
|
||||
'nodes': _("Node"),
|
||||
}
|
||||
help_texts = {
|
||||
'hostname': '* required',
|
||||
'ip': '* required',
|
||||
|
@ -116,10 +122,10 @@ class AssetBulkUpdateForm(forms.ModelForm):
|
|||
]
|
||||
widgets = {
|
||||
'labels': forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _('Select labels')}
|
||||
attrs={'class': 'select2', 'data-placeholder': _('Label')}
|
||||
),
|
||||
'nodes': forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _('Select nodes')}
|
||||
attrs={'class': 'select2', 'data-placeholder': _('Node')}
|
||||
),
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ class Asset(models.Model):
|
|||
comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
|
||||
|
||||
def __str__(self):
|
||||
return self.hostname
|
||||
return '{0.hostname}({0.ip})'.format(self)
|
||||
|
||||
@property
|
||||
def is_valid(self):
|
||||
|
@ -101,6 +101,10 @@ class Asset(models.Model):
|
|||
else:
|
||||
return False
|
||||
|
||||
def get_nodes(self):
|
||||
from .node import Node
|
||||
return self.nodes.all() or [Node.root()]
|
||||
|
||||
@property
|
||||
def hardware_info(self):
|
||||
if self.cpu_count:
|
||||
|
|
|
@ -16,6 +16,8 @@ class Node(models.Model):
|
|||
child_mark = models.IntegerField(default=0)
|
||||
date_create = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
is_asset = False
|
||||
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
|
@ -73,6 +75,9 @@ class Node(models.Model):
|
|||
assets = Asset.objects.filter(nodes__in=nodes)
|
||||
return assets
|
||||
|
||||
def has_assets(self):
|
||||
return self.get_all_assets()
|
||||
|
||||
def get_all_active_assets(self):
|
||||
return self.get_all_assets().filter(is_active=True)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#
|
||||
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.db import models
|
||||
|
@ -100,14 +101,15 @@ class SystemUser(AssetUser):
|
|||
)
|
||||
|
||||
nodes = models.ManyToManyField('assets.Node', blank=True, verbose_name=_("Nodes"))
|
||||
assets = models.ManyToManyField('assets.Asset', blank=True, verbose_name=_("Assets"))
|
||||
priority = models.IntegerField(default=10, verbose_name=_("Priority"))
|
||||
protocol = models.CharField(max_length=16, choices=PROTOCOL_CHOICES, default='ssh', verbose_name=_('Protocol'))
|
||||
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
|
||||
sudo = models.TextField(default='/sbin/ifconfig', verbose_name=_('Sudo'))
|
||||
sudo = models.TextField(default='/bin/whoami', verbose_name=_('Sudo'))
|
||||
shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell'))
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
return '{0.name}({0.username})'.format(self)
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
|
@ -119,11 +121,8 @@ class SystemUser(AssetUser):
|
|||
'auto_push': self.auto_push,
|
||||
}
|
||||
|
||||
@property
|
||||
def assets(self):
|
||||
assets = set()
|
||||
for node in self.nodes.all():
|
||||
assets.update(set(node.get_all_assets()))
|
||||
def get_assets(self):
|
||||
assets = set(self.assets.all())
|
||||
return assets
|
||||
|
||||
@property
|
||||
|
@ -168,6 +167,3 @@ class SystemUser(AssetUser):
|
|||
except IntegrityError:
|
||||
print('Error continue')
|
||||
continue
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ class NodeSerializer(serializers.ModelSerializer):
|
|||
|
||||
class Meta:
|
||||
model = Node
|
||||
fields = ['id', 'key', 'value', 'parent', 'assets_amount']
|
||||
fields = ['id', 'key', 'value', 'parent', 'assets_amount', 'is_asset']
|
||||
list_serializer_class = BulkListSerializer
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -34,7 +34,7 @@ class SystemUserSerializer(serializers.ModelSerializer):
|
|||
|
||||
@staticmethod
|
||||
def get_assets_amount(obj):
|
||||
return len(obj.assets)
|
||||
return len(obj.get_assets())
|
||||
|
||||
|
||||
class SystemUserAuthSerializer(AuthSerializer):
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from collections import defaultdict
|
||||
from django.db.models.signals import post_save, m2m_changed
|
||||
from django.dispatch import receiver
|
||||
|
||||
from common.utils import get_logger
|
||||
from .models import Asset, SystemUser, Node
|
||||
from .tasks import update_assets_hardware_info_util, \
|
||||
test_asset_connectability_util, push_system_user_to_node, \
|
||||
push_node_system_users_to_asset
|
||||
test_asset_connectability_util, push_system_user_to_assets
|
||||
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
@ -31,7 +30,6 @@ def set_asset_root_node(asset):
|
|||
|
||||
@receiver(post_save, sender=Asset, dispatch_uid="my_unique_identifier")
|
||||
def on_asset_created_or_update(sender, instance=None, created=False, **kwargs):
|
||||
set_asset_root_node(instance)
|
||||
if created:
|
||||
logger.info("Asset `{}` create signal received".format(instance))
|
||||
update_asset_hardware_info_on_created(instance)
|
||||
|
@ -41,25 +39,39 @@ def on_asset_created_or_update(sender, instance=None, created=False, **kwargs):
|
|||
@receiver(post_save, sender=SystemUser, dispatch_uid="my_unique_identifier")
|
||||
def on_system_user_update(sender, instance=None, created=True, **kwargs):
|
||||
if instance and not created:
|
||||
for node in instance.nodes.all():
|
||||
push_system_user_to_node(instance, node)
|
||||
logger.info("System user `{}` update signal received".format(instance))
|
||||
assets = instance.assets.all()
|
||||
push_system_user_to_assets.delay(instance, assets)
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=SystemUser.nodes.through)
|
||||
def on_system_user_node_change(sender, instance=None, **kwargs):
|
||||
def on_system_user_nodes_change(sender, instance=None, **kwargs):
|
||||
if instance and kwargs["action"] == "post_add":
|
||||
for pk in kwargs['pk_set']:
|
||||
node = kwargs['model'].objects.get(pk=pk)
|
||||
push_system_user_to_node(instance, node)
|
||||
assets = set()
|
||||
nodes = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
|
||||
for node in nodes:
|
||||
assets.update(set(node.get_all_assets()))
|
||||
instance.assets.add(*tuple(assets))
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=SystemUser.assets.through)
|
||||
def on_system_user_assets_change(sender, instance=None, **kwargs):
|
||||
if instance and kwargs["action"] == "post_add":
|
||||
assets = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
|
||||
push_system_user_to_assets(instance, assets)
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=Asset.nodes.through)
|
||||
def on_asset_node_changed(sender, instance=None, **kwargs):
|
||||
if isinstance(instance, Asset) and kwargs['action'] == 'post_add':
|
||||
logger.debug("Asset node change signal received")
|
||||
for pk in kwargs['pk_set']:
|
||||
node = kwargs['model'].objects.get(pk=pk)
|
||||
push_node_system_users_to_asset(node, [instance])
|
||||
nodes = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
|
||||
system_users_assets = defaultdict(set)
|
||||
system_users = SystemUser.objects.filter(nodes__in=nodes)
|
||||
for system_user in system_users:
|
||||
system_users_assets[system_user].update({instance})
|
||||
for system_user, assets in system_users_assets.items():
|
||||
system_user.assets.add(*tuple(assets))
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=Asset.nodes.through)
|
||||
|
@ -67,5 +79,6 @@ def on_node_assets_changed(sender, instance=None, **kwargs):
|
|||
if isinstance(instance, Node) and kwargs['action'] == 'post_add':
|
||||
logger.debug("Node assets change signal received")
|
||||
assets = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
|
||||
push_node_system_users_to_asset(instance, assets)
|
||||
|
||||
system_users = SystemUser.objects.filter(nodes=instance)
|
||||
for system_user in system_users:
|
||||
system_user.assets.add(*tuple(assets))
|
||||
|
|
|
@ -276,7 +276,7 @@ def test_system_user_connectability_util(system_user, task_name):
|
|||
:return:
|
||||
"""
|
||||
from ops.utils import update_or_create_ansible_task
|
||||
assets = system_user.assets
|
||||
assets = system_user.get_assets()
|
||||
hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()]
|
||||
tasks = const.TEST_SYSTEM_USER_CONN_TASKS
|
||||
if not hosts:
|
||||
|
@ -386,52 +386,17 @@ def push_system_user_util(system_users, assets, task_name):
|
|||
return task.run()
|
||||
|
||||
|
||||
def get_node_push_system_user_task_name(system_user, node):
|
||||
|
||||
# return _("Push system user to node: {} => {}").format(
|
||||
return _("推送系统用户到节点资产: {} => {}").format(
|
||||
system_user.name,
|
||||
node.value
|
||||
)
|
||||
|
||||
|
||||
@shared_task
|
||||
def push_system_user_to_node(system_user, node):
|
||||
logger.info("Start push system user node: {} => {}".format(system_user.name, node.value))
|
||||
assets = node.get_all_assets()
|
||||
task_name = get_node_push_system_user_task_name(system_user, node)
|
||||
push_system_user_util([system_user], assets, task_name)
|
||||
|
||||
|
||||
@shared_task
|
||||
def push_system_user_related_nodes(system_user):
|
||||
if not system_user.is_need_push():
|
||||
msg = "push system user `{}` passed, may be not auto push or ssh " \
|
||||
"protocol is not ssh".format(system_user.name)
|
||||
logger.info(msg)
|
||||
return
|
||||
|
||||
nodes = system_user.nodes.all()
|
||||
for node in nodes:
|
||||
push_system_user_to_node(system_user, node)
|
||||
|
||||
|
||||
@shared_task
|
||||
def push_system_user_to_assets_manual(system_user):
|
||||
push_system_user_related_nodes(system_user)
|
||||
assets = system_user.get_assets()
|
||||
task_name = "推送系统用户到入资产: {}".format(system_user.name)
|
||||
return push_system_user_util([system_user], assets, task_name=task_name)
|
||||
|
||||
|
||||
def push_node_system_users_to_asset(node, assets):
|
||||
system_users = []
|
||||
nodes = node.ancestor_with_node
|
||||
# 获取该节点所有父节点有的系统用户, 然后推送
|
||||
for n in nodes:
|
||||
system_users.extend(list(n.systemuser_set.all()))
|
||||
|
||||
if system_users:
|
||||
# task_name = _("Push system users to node: {}").format(node.value)
|
||||
task_name = _("推送节点系统用户到新加入资产中: {}").format(node.value)
|
||||
push_system_user_util.delay(system_users, assets, task_name)
|
||||
@shared_task
|
||||
def push_system_user_to_assets(system_user, assets):
|
||||
task_name = _("推送系统用户到入资产: {}").format(system_user.name)
|
||||
return push_system_user_util.delay([system_user], assets, task_name)
|
||||
|
||||
|
||||
# @shared_task
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
<div class="form-group {% if form.errors.labels %} has-error {% endif %}">
|
||||
<label for="{{ form.labels.id_for_label }}" class="col-md-2 control-label">{% trans 'Label' %}</label>
|
||||
<div class="col-md-9">
|
||||
<select name="labels" class="select2 labels" data-placeholder="{% trans 'Select labels' %}" style="width: 100%" multiple="" tabindex="4" id="{{ form.labels.id_for_label }}">
|
||||
<select name="labels" class="select2 labels" data-placeholder="{% trans 'Label' %}" style="width: 100%" multiple="" tabindex="4" id="{{ form.labels.id_for_label }}">
|
||||
{% for name, labels in form.labels.field.queryset|group_labels %}
|
||||
<optgroup label="{{ name }}">
|
||||
{% for label in labels %}
|
||||
|
|
|
@ -41,9 +41,9 @@
|
|||
{% block content %}
|
||||
<div class="wrapper wrapper-content">
|
||||
<div class="row">
|
||||
<div class="col-lg-3" id="split-left">
|
||||
<div class="col-lg-3" id="split-left" style="padding-left: 3px">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
|
||||
<div class="file-manager ">
|
||||
<div id="assetTree" class="ztree">
|
||||
</div>
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<div class="form-group">
|
||||
<label for="{{ form.labels.id_for_label }}" class="col-md-2 control-label">{% trans 'Label' %}</label>
|
||||
<div class="col-md-9">
|
||||
<select name="labels" class="select2 labels" data-placeholder="Select labels" style="width: 100%" multiple="" tabindex="4" id="{{ form.labels.id_for_label }}">
|
||||
<select name="labels" class="select2 labels" data-placeholder="{% trans 'Label' %}" style="width: 100%" multiple="" tabindex="4" id="{{ form.labels.id_for_label }}">
|
||||
{% for name, labels in form.labels.field.queryset|group_labels %}
|
||||
<optgroup label="{{ name }}">
|
||||
{% for label in labels %}
|
||||
|
|
|
@ -1,81 +1,171 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||
|
||||
{% endblock %}
|
||||
{% block content_left_head %}{% endblock %}
|
||||
|
||||
{% block table_search %}
|
||||
<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet">
|
||||
<script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script>
|
||||
<script src="{% static 'js/jquery.form.min.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block table_container %}
|
||||
<table class="table table-striped table-bordered table-hover " id="asset_list_table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center"><input type="checkbox" class="ipt_check_all"></th>
|
||||
<th class="text-center">{% trans 'Hostname' %}</th>
|
||||
<th class="text-center">{% trans 'IP' %}</th>
|
||||
<th class="text-center">{% trans 'Port' %}</th>
|
||||
<th class="text-center">{% trans 'Hardware' %}</th>
|
||||
<th class="text-center">{% trans 'Active' %}</th>
|
||||
<th class="text-center">{% trans 'Connective' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content">
|
||||
<div class="row">
|
||||
<div class="col-lg-3" id="split-left" style="padding-left: 3px">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
|
||||
<div class="file-manager ">
|
||||
<div id="assetTree" class="ztree">
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-9 animated fadeInRight" id="split-right">
|
||||
<div class="tree-toggle">
|
||||
<div class="btn btn-sm btn-primary tree-toggle-btn" onclick="toggle()">
|
||||
<i class="fa fa-angle-left fa-x" id="toggle-icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mail-box-header">
|
||||
<div class="btn-group" style="float: right">
|
||||
<button data-toggle="dropdown" class="btn btn-default btn-sm dropdown-toggle">{% trans 'Label' %} <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu labels">
|
||||
{% for label in labels %}
|
||||
<li><a style="font-weight: bolder">{{ label.name }}:{{ label.value }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<table class="table table-striped table-bordered table-hover " id="user_assets_table" style="width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center"><input type="checkbox" class="ipt_check_all"></th>
|
||||
<th class="text-center">{% trans 'Hostname' %}</th>
|
||||
<th class="text-center">{% trans 'IP' %}</th>
|
||||
<th class="text-center">{% trans 'Active' %}</th>
|
||||
<th class="text-center">{% trans 'System users' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/jquery.form.min.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
<script>
|
||||
var zTree, rMenu, asset_table;
|
||||
var inited = false;
|
||||
var url;
|
||||
function initTable() {
|
||||
if (inited){
|
||||
return
|
||||
} else {
|
||||
inited = true;
|
||||
}
|
||||
var options = {
|
||||
ele: $('#asset_list_table'),
|
||||
ele: $('#user_assets_table'),
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
|
||||
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData) {
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 6, createdCell: function (td, cellData) {
|
||||
if (cellData == 'Unknown'){
|
||||
$(td).html('<i class="fa fa-circle text-warning"></i>')
|
||||
} else if (!cellData) {
|
||||
$(td).html('<i class="fa fa-circle text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-circle text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{# {targets: 9, createdCell: function (td, cellData, rowData) {#}
|
||||
{# var conn_btn = '<a href="{% url "terminal:web-terminal" %}?id={{ DEFAULT_PK }}" class="btn btn-xs btn-info">{% trans "Connect" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);#}
|
||||
{# $(td).html(conn_btn)#}
|
||||
{# }}#}
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
var users = [];
|
||||
$.each(cellData, function (id, data) {
|
||||
users.push(data.name);
|
||||
});
|
||||
$(td).html(users.join(', '))
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-assets:user-asset-list" %}',
|
||||
ajax_url: url,
|
||||
columns: [
|
||||
{data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "port" },
|
||||
{data: "hardware_info"}, {data: "is_active" }, {data: "is_connective"}
|
||||
],
|
||||
op_html: $('#actions').html()
|
||||
{data: "id"}, {data: "hostname" }, {data: "ip" },
|
||||
{data: "is_active", orderable: false },
|
||||
{data: "system_users_granted", orderable: false}
|
||||
]
|
||||
};
|
||||
return jumpserver.initDataTable(options);
|
||||
asset_table = jumpserver.initDataTable(options);
|
||||
return asset_table
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
function onSelected(event, treeNode) {
|
||||
console.log("select");
|
||||
url = '{% url "api-perms:my-node-assets" node_id=DEFAULT_PK %}';
|
||||
url = url.replace("{{ DEFAULT_PK }}", treeNode.id);
|
||||
initTable();
|
||||
});
|
||||
setCookie('node_selected', treeNode.id);
|
||||
asset_table.ajax.url(url);
|
||||
asset_table.ajax.reload();
|
||||
}
|
||||
|
||||
function selectQueryNode() {
|
||||
var query_node_id = $.getUrlParam("node");
|
||||
var cookie_node_id = getCookie('node_selected');
|
||||
var node;
|
||||
var node_id;
|
||||
|
||||
if (query_node_id !== null) {
|
||||
node_id = query_node_id
|
||||
} else if (cookie_node_id !== null) {
|
||||
node_id = cookie_node_id;
|
||||
}
|
||||
|
||||
node = zTree.getNodesByParam("id", node_id, null);
|
||||
if (node){
|
||||
zTree.selectNode(node[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function initTree() {
|
||||
var setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
callback: {
|
||||
onSelected: onSelected
|
||||
}
|
||||
};
|
||||
|
||||
var zNodes = [];
|
||||
$.get("{% url 'api-perms:my-nodes' %}", function(data, status){
|
||||
$.each(data, function (index, value) {
|
||||
value["pId"] = value["parent"];
|
||||
if (value["key"] === "0") {
|
||||
value["open"] = true;
|
||||
}
|
||||
value["name"] = value["value"]
|
||||
});
|
||||
zNodes = data;
|
||||
$.fn.zTree.init($("#assetTree"), setting, zNodes);
|
||||
zTree = $.fn.zTree.getZTreeObj("assetTree");
|
||||
rMenu = $("#rMenu");
|
||||
selectQueryNode();
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
initTree();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
|
@ -36,7 +36,9 @@ urlpatterns = [
|
|||
url(r'^v1/system-user/(?P<pk>[0-9a-zA-Z\-]{36})/connective/$',
|
||||
api.SystemUserTestConnectiveApi.as_view(), name='system-user-connective'),
|
||||
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/children/$', api.NodeChildrenApi.as_view(), name='node-children'),
|
||||
url(r'^v1/nodes/children/$', api.NodeChildrenApi.as_view(), name='node-children-2'),
|
||||
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/children/add/$', api.NodeAddChildrenApi.as_view(), name='node-add-children'),
|
||||
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', api.NodeAssetsApi.as_view(), name='node-assets'),
|
||||
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/add/$', api.NodeAddAssetsApi.as_view(), name='node-add-assets'),
|
||||
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/remove/$', api.NodeRemoveAssetsApi.as_view(), name='node-remove-assets'),
|
||||
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/refresh-hardware-info/$', api.RefreshNodeHardwareInfoApi.as_view(), name='node-refresh-hardware-info'),
|
||||
|
|
|
@ -43,3 +43,7 @@ class StringIDField(serializers.Field):
|
|||
def to_representation(self, value):
|
||||
return {"pk": value.pk, "name": value.__str__()}
|
||||
|
||||
|
||||
class StringManyToManyField(serializers.RelatedField):
|
||||
def to_representation(self, value):
|
||||
return value.__str__()
|
|
@ -232,6 +232,14 @@ def setattr_bulk(seq, key, value):
|
|||
return map(set_attr, seq)
|
||||
|
||||
|
||||
def set_or_append_attr_bulk(seq, key, value):
|
||||
for obj in seq:
|
||||
ori = getattr(obj, key, None)
|
||||
if ori:
|
||||
value += " " + ori
|
||||
setattr(obj, key, value)
|
||||
|
||||
|
||||
def content_md5(data):
|
||||
"""计算data的MD5值,经过Base64编码并返回str类型。
|
||||
|
||||
|
@ -350,11 +358,17 @@ def get_short_uuid_str():
|
|||
return str(uuid.uuid4()).split('-')[-1]
|
||||
|
||||
|
||||
def is_uuid(s):
|
||||
if UUID_PATTERN.match(s):
|
||||
return True
|
||||
def is_uuid(seq):
|
||||
if isinstance(seq, str):
|
||||
if UUID_PATTERN.match(seq):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
for s in seq:
|
||||
if not is_uuid(s):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def get_signer():
|
||||
|
@ -378,3 +392,4 @@ class TeeObj:
|
|||
|
||||
def close(self):
|
||||
self.file_obj.close()
|
||||
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -3,13 +3,14 @@
|
|||
|
||||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework.views import APIView, Response
|
||||
from rest_framework.generics import ListAPIView, get_object_or_404
|
||||
from rest_framework.generics import ListAPIView, get_object_or_404, RetrieveUpdateAPIView
|
||||
from rest_framework import viewsets
|
||||
|
||||
from common.utils import set_or_append_attr_bulk
|
||||
from users.permissions import IsValidUser, IsSuperUser, IsSuperUserOrAppUser
|
||||
from .utils import NodePermissionUtil
|
||||
from .models import NodePermission
|
||||
from .hands import AssetGrantedSerializer, User, UserGroup, Asset, \
|
||||
from .utils import AssetPermissionUtil
|
||||
from .models import AssetPermission
|
||||
from .hands import AssetGrantedSerializer, User, UserGroup, Asset, Node, \
|
||||
NodeGrantedSerializer, SystemUser, NodeSerializer
|
||||
from . import serializers
|
||||
|
||||
|
@ -18,7 +19,7 @@ class AssetPermissionViewSet(viewsets.ModelViewSet):
|
|||
"""
|
||||
资产授权列表的增删改查api
|
||||
"""
|
||||
queryset = NodePermission.objects.all()
|
||||
queryset = AssetPermission.objects.all()
|
||||
serializer_class = serializers.AssetPermissionCreateUpdateSerializer
|
||||
permission_classes = (IsSuperUser,)
|
||||
|
||||
|
@ -29,12 +30,28 @@ class AssetPermissionViewSet(viewsets.ModelViewSet):
|
|||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
node_id = self.request.query_params.get('node_id')
|
||||
asset_id = self.request.query_params.get('asset')
|
||||
node_id = self.request.query_params.get('node')
|
||||
inherit_nodes = set()
|
||||
if not asset_id and not node_id:
|
||||
return queryset
|
||||
|
||||
if node_id:
|
||||
queryset = queryset.filter(node__id=node_id)
|
||||
permissions = set()
|
||||
if asset_id:
|
||||
asset = get_object_or_404(Asset, pk=asset_id)
|
||||
permissions = set(queryset.filter(assets=asset))
|
||||
for node in asset.nodes.all():
|
||||
inherit_nodes.update(set(node.ancestor_with_node))
|
||||
elif node_id:
|
||||
node = get_object_or_404(Node, pk=node_id)
|
||||
permissions = set(queryset.filter(nodes=node))
|
||||
inherit_nodes = node.ancestor
|
||||
|
||||
return queryset
|
||||
for n in inherit_nodes:
|
||||
_permissions = queryset.filter(nodes=n)
|
||||
set_or_append_attr_bulk(_permissions, "inherit", n.value)
|
||||
permissions.update(_permissions)
|
||||
return permissions
|
||||
|
||||
|
||||
class UserGrantedAssetsApi(ListAPIView):
|
||||
|
@ -53,7 +70,7 @@ class UserGrantedAssetsApi(ListAPIView):
|
|||
else:
|
||||
user = self.request.user
|
||||
|
||||
for k, v in NodePermissionUtil.get_user_assets(user).items():
|
||||
for k, v in AssetPermissionUtil.get_user_assets(user).items():
|
||||
if k.is_unixlike():
|
||||
system_users_granted = [s for s in v if s.protocol == 'ssh']
|
||||
else:
|
||||
|
@ -78,38 +95,11 @@ class UserGrantedNodesApi(ListAPIView):
|
|||
user = get_object_or_404(User, id=user_id)
|
||||
else:
|
||||
user = self.request.user
|
||||
nodes = NodePermissionUtil.get_user_nodes(user)
|
||||
nodes = AssetPermissionUtil.get_user_nodes_with_assets(user)
|
||||
return nodes.keys()
|
||||
|
||||
|
||||
class UserGrantedNodesWithAssetsApi(ListAPIView):
|
||||
"""
|
||||
授权用户的资产组,注:这里的资产组并非是授权列表中授权的,
|
||||
而是把所有资产取出来,然后反查出所有资产组,然后合并得到,
|
||||
结果里也包含资产组下授权的资产
|
||||
数据结构如下:
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"value": "node",
|
||||
... 其它属性
|
||||
"assets_granted": [
|
||||
{
|
||||
"id": 1,
|
||||
"hostname": "testserver",
|
||||
"ip": "192.168.1.1",
|
||||
"port": 22,
|
||||
"system_users_granted": [
|
||||
"id": 1,
|
||||
"name": "web",
|
||||
"username": "web",
|
||||
"protocol": "ssh",
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"""
|
||||
permission_classes = (IsSuperUserOrAppUser,)
|
||||
serializer_class = NodeGrantedSerializer
|
||||
|
||||
|
@ -121,18 +111,16 @@ class UserGrantedNodesWithAssetsApi(ListAPIView):
|
|||
else:
|
||||
user = get_object_or_404(User, id=user_id)
|
||||
|
||||
nodes = NodePermissionUtil.get_user_nodes_with_assets(user)
|
||||
assets = {}
|
||||
for k, v in NodePermissionUtil.get_user_assets(user).items():
|
||||
if k.is_unixlike():
|
||||
system_users_granted = [s for s in v if s.protocol == 'ssh']
|
||||
else:
|
||||
system_users_granted = [s for s in v if s.protocol == 'rdp']
|
||||
assets[k] = system_users_granted
|
||||
for node, v in nodes.items():
|
||||
for asset in v['assets']:
|
||||
asset.system_users_granted = assets[asset]
|
||||
node.assets_granted = v['assets']
|
||||
nodes = AssetPermissionUtil.get_user_nodes_with_assets(user)
|
||||
for node, _assets in nodes.items():
|
||||
assets = _assets.keys()
|
||||
for k, v in _assets.items():
|
||||
if k.is_unixlike():
|
||||
system_users_granted = [s for s in v if s.protocol == 'ssh']
|
||||
else:
|
||||
system_users_granted = [s for s in v if s.protocol == 'rdp']
|
||||
k.system_users_granted = system_users_granted
|
||||
node.assets_granted = assets
|
||||
queryset.append(node)
|
||||
return queryset
|
||||
|
||||
|
@ -142,6 +130,31 @@ class UserGrantedNodesWithAssetsApi(ListAPIView):
|
|||
return super().get_permissions()
|
||||
|
||||
|
||||
class UserGrantedNodeAssetsApi(ListAPIView):
|
||||
permission_classes = (IsSuperUserOrAppUser,)
|
||||
serializer_class = AssetGrantedSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
user_id = self.kwargs.get('pk', '')
|
||||
node_id = self.kwargs.get('node_id')
|
||||
|
||||
if user_id:
|
||||
user = get_object_or_404(User, id=user_id)
|
||||
else:
|
||||
user = self.request.user
|
||||
node = get_object_or_404(Node, id=node_id)
|
||||
nodes = AssetPermissionUtil.get_user_nodes_with_assets(user)
|
||||
assets = nodes.get(node, [])
|
||||
for asset, system_users in assets.items():
|
||||
asset.system_users_granted = system_users
|
||||
return assets
|
||||
|
||||
def get_permissions(self):
|
||||
if self.kwargs.get('pk') is None:
|
||||
self.permission_classes = (IsValidUser,)
|
||||
return super().get_permissions()
|
||||
|
||||
|
||||
class UserGroupGrantedAssetsApi(ListAPIView):
|
||||
permission_classes = (IsSuperUser,)
|
||||
serializer_class = AssetGrantedSerializer
|
||||
|
@ -154,7 +167,7 @@ class UserGroupGrantedAssetsApi(ListAPIView):
|
|||
return queryset
|
||||
|
||||
user_group = get_object_or_404(UserGroup, id=user_group_id)
|
||||
assets = NodePermissionUtil.get_user_group_assets(user_group)
|
||||
assets = AssetPermissionUtil.get_user_group_assets(user_group)
|
||||
for k, v in assets.items():
|
||||
k.system_users_granted = v
|
||||
queryset.append(k)
|
||||
|
@ -171,8 +184,8 @@ class UserGroupGrantedNodesApi(ListAPIView):
|
|||
|
||||
if group_id:
|
||||
group = get_object_or_404(UserGroup, id=group_id)
|
||||
nodes = NodePermissionUtil.get_user_group_nodes(group)
|
||||
queryset = nodes.keys()
|
||||
nodes = AssetPermissionUtil.get_user_group_nodes_with_assets(group)
|
||||
return nodes.keys()
|
||||
return queryset
|
||||
|
||||
|
||||
|
@ -188,15 +201,33 @@ class UserGroupGrantedNodesWithAssetsApi(ListAPIView):
|
|||
return queryset
|
||||
|
||||
user_group = get_object_or_404(UserGroup, id=user_group_id)
|
||||
nodes = NodePermissionUtil.get_user_group_nodes_with_assets(user_group)
|
||||
for node, v in nodes.items():
|
||||
for asset in v['assets']:
|
||||
asset.system_users_granted = v['system_users']
|
||||
node.assets_granted = v['assets']
|
||||
nodes = AssetPermissionUtil.get_user_group_nodes_with_assets(user_group)
|
||||
for node, _assets in nodes.items():
|
||||
assets = _assets.keys()
|
||||
for asset, system_users in _assets.items():
|
||||
asset.system_users_granted = system_users
|
||||
node.assets_granted = assets
|
||||
queryset.append(node)
|
||||
return queryset
|
||||
|
||||
|
||||
class UserGroupGrantedNodeAssetsApi(ListAPIView):
|
||||
permission_classes = (IsSuperUserOrAppUser,)
|
||||
serializer_class = AssetGrantedSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
user_group_id = self.kwargs.get('pk', '')
|
||||
node_id = self.kwargs.get('node_id')
|
||||
|
||||
user_group = get_object_or_404(UserGroup, id=user_group_id)
|
||||
node = get_object_or_404(Node, id=node_id)
|
||||
nodes = AssetPermissionUtil.get_user_group_nodes_with_assets(user_group)
|
||||
assets = nodes.get(node, [])
|
||||
for asset, system_users in assets.items():
|
||||
asset.system_users_granted = system_users
|
||||
return assets
|
||||
|
||||
|
||||
class ValidateUserAssetPermissionView(APIView):
|
||||
permission_classes = (IsSuperUserOrAppUser,)
|
||||
|
||||
|
@ -210,8 +241,82 @@ class ValidateUserAssetPermissionView(APIView):
|
|||
asset = get_object_or_404(Asset, id=asset_id)
|
||||
system_user = get_object_or_404(SystemUser, id=system_id)
|
||||
|
||||
assets_granted = NodePermissionUtil.get_user_assets(user)
|
||||
assets_granted = AssetPermissionUtil.get_user_assets(user)
|
||||
if system_user in assets_granted.get(asset, []):
|
||||
return Response({'msg': True}, status=200)
|
||||
else:
|
||||
return Response({'msg': False}, status=403)
|
||||
|
||||
|
||||
class AssetPermissionRemoveUserApi(RetrieveUpdateAPIView):
|
||||
"""
|
||||
将用户从授权中移除,Detail页面会调用
|
||||
"""
|
||||
permission_classes = (IsSuperUser,)
|
||||
serializer_class = serializers.AssetPermissionUpdateUserSerializer
|
||||
queryset = AssetPermission.objects.all()
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
perm = self.get_object()
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if serializer.is_valid():
|
||||
users = serializer.validated_data.get('users')
|
||||
if users:
|
||||
perm.users.remove(*tuple(users))
|
||||
return Response({"msg": "ok"})
|
||||
else:
|
||||
return Response({"error": serializer.errors})
|
||||
|
||||
|
||||
class AssetPermissionAddUserApi(RetrieveUpdateAPIView):
|
||||
permission_classes = (IsSuperUser,)
|
||||
serializer_class = serializers.AssetPermissionUpdateUserSerializer
|
||||
queryset = AssetPermission.objects.all()
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
perm = self.get_object()
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if serializer.is_valid():
|
||||
users = serializer.validated_data.get('users')
|
||||
if users:
|
||||
perm.users.add(*tuple(users))
|
||||
return Response({"msg": "ok"})
|
||||
else:
|
||||
return Response({"error": serializer.errors})
|
||||
|
||||
|
||||
class AssetPermissionRemoveAssetApi(RetrieveUpdateAPIView):
|
||||
"""
|
||||
将用户从授权中移除,Detail页面会调用
|
||||
"""
|
||||
permission_classes = (IsSuperUser,)
|
||||
serializer_class = serializers.AssetPermissionUpdateAssetSerializer
|
||||
queryset = AssetPermission.objects.all()
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
perm = self.get_object()
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if serializer.is_valid():
|
||||
assets = serializer.validated_data.get('assets')
|
||||
if assets:
|
||||
perm.assets.remove(*tuple(assets))
|
||||
return Response({"msg": "ok"})
|
||||
else:
|
||||
return Response({"error": serializer.errors})
|
||||
|
||||
|
||||
class AssetPermissionAddAssetApi(RetrieveUpdateAPIView):
|
||||
permission_classes = (IsSuperUser,)
|
||||
serializer_class = serializers.AssetPermissionUpdateAssetSerializer
|
||||
queryset = AssetPermission.objects.all()
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
perm = self.get_object()
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if serializer.is_valid():
|
||||
assets = serializer.validated_data.get('assets')
|
||||
if assets:
|
||||
perm.assets.add(*tuple(assets))
|
||||
return Response({"msg": "ok"})
|
||||
else:
|
||||
return Response({"error": serializer.errors})
|
||||
|
|
|
@ -4,27 +4,64 @@ from __future__ import absolute_import, unicode_literals
|
|||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .models import NodePermission
|
||||
from .hands import User
|
||||
from .models import AssetPermission
|
||||
|
||||
|
||||
class AssetPermissionForm(forms.ModelForm):
|
||||
users = forms.ModelMultipleChoiceField(
|
||||
queryset=User.objects.exclude(role=User.ROLE_APP),
|
||||
label=_("User"),
|
||||
widget=forms.SelectMultiple(
|
||||
attrs={
|
||||
'class': 'select2',
|
||||
'data-placeholder': _('Select users')
|
||||
}
|
||||
),
|
||||
required=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = NodePermission
|
||||
fields = [
|
||||
'node', 'user_group', 'system_user', 'is_active',
|
||||
'date_expired', 'comment',
|
||||
]
|
||||
model = AssetPermission
|
||||
exclude = (
|
||||
'id', 'date_created', 'created_by'
|
||||
)
|
||||
widgets = {
|
||||
'node': forms.Select(
|
||||
attrs={'style': 'display:none'}
|
||||
'users': forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _("User")}
|
||||
),
|
||||
'user_group': forms.Select(
|
||||
'user_groups': forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _("User group")}
|
||||
),
|
||||
'system_user': forms.Select(
|
||||
'assets': forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _("Asset")}
|
||||
),
|
||||
'nodes': forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _("Node")}
|
||||
),
|
||||
'system_users': forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _('System user')}
|
||||
),
|
||||
}
|
||||
labels = {
|
||||
'nodes': _("Node"),
|
||||
}
|
||||
|
||||
def clean_system_user(self):
|
||||
return self.cleaned_data['system_user']
|
||||
def clean_user_groups(self):
|
||||
users = self.cleaned_data.get('users')
|
||||
user_groups = self.cleaned_data.get('user_groups')
|
||||
|
||||
if not users and not user_groups:
|
||||
raise forms.ValidationError(
|
||||
_("User or group at least one required"))
|
||||
return self.cleaned_data["user_groups"]
|
||||
|
||||
def clean_asset_groups(self):
|
||||
assets = self.cleaned_data.get('assets')
|
||||
asset_groups = self.cleaned_data.get('asset_groups')
|
||||
|
||||
if not assets and not asset_groups:
|
||||
raise forms.ValidationError(
|
||||
_("Asset or group at least one required"))
|
||||
|
||||
return self.cleaned_data["asset_groups"]
|
||||
|
|
|
@ -4,70 +4,63 @@ from django.db import models
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
|
||||
from common.utils import date_expired_default
|
||||
from common.utils import date_expired_default, set_or_append_attr_bulk
|
||||
|
||||
|
||||
class ValidManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(is_active=True) \
|
||||
.filter(date_start__lt=timezone.now())\
|
||||
.filter(date_expired__gt=timezone.now())
|
||||
|
||||
|
||||
class AssetPermission(models.Model):
|
||||
from users.models import User, UserGroup
|
||||
from assets.models import Asset, AssetGroup, SystemUser, Cluster
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
|
||||
users = models.ManyToManyField(User, related_name='asset_permissions', blank=True, verbose_name=_("User"))
|
||||
user_groups = models.ManyToManyField(UserGroup, related_name='asset_permissions', blank=True, verbose_name=_("User group"))
|
||||
assets = models.ManyToManyField(Asset, related_name='granted_by_permissions', blank=True, verbose_name=_("Asset"))
|
||||
asset_groups = models.ManyToManyField(AssetGroup, related_name='granted_by_permissions', blank=True, verbose_name=_("Asset group"))
|
||||
system_users = models.ManyToManyField(SystemUser, related_name='granted_by_permissions', verbose_name=_("System user"))
|
||||
users = models.ManyToManyField('users.User', related_name='asset_permissions', blank=True, verbose_name=_("User"))
|
||||
user_groups = models.ManyToManyField('users.UserGroup', related_name='asset_permissions', blank=True, verbose_name=_("User group"))
|
||||
assets = models.ManyToManyField('assets.Asset', related_name='granted_by_permissions', blank=True, verbose_name=_("Asset"))
|
||||
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"))
|
||||
is_active = models.BooleanField(default=True, verbose_name=_('Active'))
|
||||
date_start = models.DateTimeField(default=timezone.now, verbose_name=_("Date start"))
|
||||
date_expired = models.DateTimeField(default=date_expired_default, verbose_name=_('Date expired'))
|
||||
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'))
|
||||
comment = models.TextField(verbose_name=_('Comment'), blank=True)
|
||||
|
||||
objects = models.Manager()
|
||||
valid = ValidManager()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def id_str(self):
|
||||
return str(self.id)
|
||||
|
||||
@property
|
||||
def is_valid(self):
|
||||
if self.date_expired > timezone.now() and self.is_active:
|
||||
if self.date_expired > timezone.now() > self.date_start and self.is_active:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_granted_users(self):
|
||||
return list(set(self.users.all()) | self.get_granted_user_groups_member())
|
||||
|
||||
def get_granted_user_groups_member(self):
|
||||
users = set()
|
||||
for user_group in self.user_groups.all():
|
||||
for user in user_group.users.all():
|
||||
setattr(user, 'is_inherit_from_user_groups', True)
|
||||
setattr(user, 'inherit_from_user_groups',
|
||||
getattr(user, 'inherit_from_user_groups', set()).add(user_group))
|
||||
users.add(user)
|
||||
def get_all_users(self):
|
||||
users = set(self.users.all())
|
||||
for group in self.user_groups.all():
|
||||
_users = group.users.all()
|
||||
set_or_append_attr_bulk(_users, 'inherit', group.name)
|
||||
users.update(set(_users))
|
||||
return users
|
||||
|
||||
def get_granted_assets(self):
|
||||
return list(set(self.assets.all()) | self.get_granted_asset_groups_member())
|
||||
|
||||
def get_granted_asset_groups_member(self):
|
||||
assets = set()
|
||||
for asset_group in self.asset_groups.all():
|
||||
for asset in asset_group.assets.all():
|
||||
setattr(asset, 'is_inherit_from_asset_groups', True)
|
||||
setattr(asset, 'inherit_from_asset_groups',
|
||||
getattr(asset, 'inherit_from_user_groups', set()).add(asset_group))
|
||||
assets.add(asset)
|
||||
def get_all_assets(self):
|
||||
assets = set(self.assets.all())
|
||||
for node in self.nodes.all():
|
||||
_assets = node.get_all_assets()
|
||||
set_or_append_attr_bulk(_assets, 'inherit', node.value)
|
||||
assets.update(set(_assets))
|
||||
return assets
|
||||
|
||||
def check_system_user_in_assets(self):
|
||||
errors = {}
|
||||
assets = self.get_granted_assets()
|
||||
clusters = set([asset.cluster for asset in assets])
|
||||
for system_user in self.system_users.all():
|
||||
cluster_remain = clusters - set(system_user.cluster.all())
|
||||
if cluster_remain:
|
||||
errors[system_user] = cluster_remain
|
||||
return errors
|
||||
|
||||
|
||||
class NodePermission(models.Model):
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
|
|
|
@ -1,31 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
from common.utils import get_object_or_none
|
||||
from common.fields import StringIDField
|
||||
from .models import AssetPermission, NodePermission
|
||||
from .models import AssetPermission
|
||||
from common.fields import StringManyToManyField
|
||||
|
||||
|
||||
class AssetPermissionCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = NodePermission
|
||||
fields = [
|
||||
'id', 'node', 'user_group', 'system_user',
|
||||
'is_active', 'date_expired'
|
||||
]
|
||||
model = AssetPermission
|
||||
exclude = ('id', 'created_by', 'date_created')
|
||||
|
||||
|
||||
class AssetPermissionListSerializer(serializers.ModelSerializer):
|
||||
node = StringIDField(read_only=True)
|
||||
user_group = StringIDField(read_only=True)
|
||||
system_user = StringIDField(read_only=True)
|
||||
users = StringManyToManyField(many=True, read_only=True)
|
||||
user_groups = StringManyToManyField(many=True, read_only=True)
|
||||
assets = StringManyToManyField(many=True, read_only=True)
|
||||
nodes = StringManyToManyField(many=True, read_only=True)
|
||||
system_users = StringManyToManyField(many=True, read_only=True)
|
||||
inherit = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = NodePermission
|
||||
model = AssetPermission
|
||||
fields = '__all__'
|
||||
|
||||
@staticmethod
|
||||
def get_inherit(obj):
|
||||
if hasattr(obj, 'inherit'):
|
||||
return obj.inherit
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class AssetPermissionUpdateUserSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
@ -40,14 +45,3 @@ class AssetPermissionUpdateAssetSerializer(serializers.ModelSerializer):
|
|||
model = AssetPermission
|
||||
fields = ['id', 'assets']
|
||||
|
||||
|
||||
class UserAssetPermissionCreateUpdateSerializer(AssetPermissionCreateUpdateSerializer):
|
||||
is_inherited = serializers.SerializerMethodField()
|
||||
|
||||
@staticmethod
|
||||
def get_is_inherited(obj):
|
||||
if getattr(obj, 'inherited', ''):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
|
|
@ -1,18 +1,42 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
from django.db.models.signals import m2m_changed
|
||||
from django.dispatch import receiver
|
||||
|
||||
from common.utils import get_logger
|
||||
from .models import NodePermission
|
||||
from .models import AssetPermission
|
||||
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
@receiver(post_save, sender=NodePermission, dispatch_uid="my_unique_identifier")
|
||||
def on_asset_permission_create_or_update(sender, instance=None, **kwargs):
|
||||
if instance and instance.node and instance.system_user:
|
||||
instance.system_user.nodes.add(instance.node)
|
||||
@receiver(m2m_changed, sender=AssetPermission.nodes.through)
|
||||
def on_permission_nodes_changed(sender, instance=None, **kwargs):
|
||||
if isinstance(instance, AssetPermission) and kwargs['action'] == 'post_add':
|
||||
logger.debug("Asset permission nodes change signal received")
|
||||
nodes = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
|
||||
system_users = instance.system_users.all()
|
||||
for system_user in system_users:
|
||||
system_user.nodes.add(*tuple(nodes))
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=AssetPermission.assets.through)
|
||||
def on_permission_assets_changed(sender, instance=None, **kwargs):
|
||||
if isinstance(instance, AssetPermission) and kwargs['action'] == 'post_add':
|
||||
logger.debug("Asset permission assets change signal received")
|
||||
assets = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
|
||||
system_users = instance.system_users.all()
|
||||
for system_user in system_users:
|
||||
system_user.assets.add(*tuple(assets))
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=AssetPermission.system_users.through)
|
||||
def on_permission_system_users_changed(sender, instance=None, **kwargs):
|
||||
if isinstance(instance, AssetPermission) and kwargs['action'] == 'post_add':
|
||||
logger.debug("Asset permission system_users change signal received")
|
||||
system_users = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
|
||||
assets = instance.assets.all()
|
||||
nodes = instance.nodes.all()
|
||||
for system_user in system_users:
|
||||
system_user.nodes.add(*tuple(nodes))
|
||||
system_user.assets.add(*tuple(assets))
|
||||
|
|
|
@ -57,12 +57,12 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for asset in page_obj %}
|
||||
{% for asset in object_list %}
|
||||
<tr>
|
||||
<td>{{ asset.hostname }}</td>
|
||||
<td>{{ asset.ip }}</td>
|
||||
<td>
|
||||
<button title="{{ asset.inherit_from_asset_groups }}" data-gid="{{ asset.id }}" class="btn btn-danger btn-xs btn-remove-asset {% if asset.is_inherit_from_asset_groups %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
||||
<button title="{{ asset.inherit }}" data-gid="{{ asset.id }}" class="btn btn-danger btn-xs btn-remove-asset {% if asset.inherit %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -105,7 +105,7 @@
|
|||
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Add asset group to this permission' %}
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Add node to this permission' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table group_edit">
|
||||
|
@ -113,25 +113,25 @@
|
|||
<form>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<select data-placeholder="{% trans 'Select asset groups' %}" class="select2 group" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for asset_group in asset_groups_remain %}
|
||||
<option value="{{ asset_group.id }}" id="opt_{{ asset_group.id }}">{{ asset_group.name }}</option>
|
||||
<select data-placeholder="{% trans 'Select nodes' %}" class="select2 group" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for node in nodes_remain %}
|
||||
<option value="{{ node.id }}" id="opt_{{ node.id }}">{{ node.value }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<button type="button" class="btn btn-info btn-sm" id="btn-add-group">{% trans 'Join' %}</button>
|
||||
<button type="button" class="btn btn-info btn-sm" id="btn-add-node">{% trans 'Join' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
|
||||
{% for asset_group in asset_groups %}
|
||||
{% for node in asset_permission.nodes.all %}
|
||||
<tr>
|
||||
<td ><b class="bdg_user_group" data-gid={{ asset_group.id }}>{{ asset_group.name }}</b></td>
|
||||
<td ><b class="bdg_user_group" data-gid={{ node.id }}>{{ node.value }}</b></td>
|
||||
<td>
|
||||
<button class="btn btn-danger btn-xs btn-remove-group" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
||||
<button class="btn btn-danger btn-xs btn-remove-node" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -179,10 +179,10 @@ function removeAssets(assets) {
|
|||
});
|
||||
}
|
||||
|
||||
function updateGroup(groups) {
|
||||
function updateNodes(nodes) {
|
||||
var the_url = "{% url 'api-perms:asset-permission-detail' pk=asset_permission.id %}";
|
||||
var body = {
|
||||
asset_groups: groups
|
||||
nodes: nodes
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
|
@ -231,17 +231,17 @@ $(document).ready(function () {
|
|||
var assets = [asset_id];
|
||||
removeAssets(assets)
|
||||
})
|
||||
.on('click', '#btn-add-group', function () {
|
||||
.on('click', '#btn-add-node', function () {
|
||||
if (Object.keys(jumpserver.nodes_selected).length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var groups = $('.bdg_group').map(function() {
|
||||
var nodes = $('.bdg_group').map(function() {
|
||||
return $(this).data('gid');
|
||||
}).get();
|
||||
|
||||
$.map(jumpserver.nodes_selected, function(group_name, index) {
|
||||
groups.push(index);
|
||||
nodes.push(index);
|
||||
$('#opt_' + index).remove();
|
||||
$('.group_edit tbody').append(
|
||||
'<tr>' +
|
||||
|
@ -251,17 +251,17 @@ $(document).ready(function () {
|
|||
)
|
||||
});
|
||||
|
||||
updateGroup(groups);
|
||||
updateNodes(nodes);
|
||||
})
|
||||
.on('click', '.btn-remove-group', function () {
|
||||
.on('click', '.btn-remove-node', function () {
|
||||
var $this = $(this);
|
||||
var $tr = $this.closest('tr');
|
||||
var groups = $('.bdg_group').map(function() {
|
||||
var nodes = $('.bdg_group').map(function() {
|
||||
if ($(this).data('gid') !== $this.data('gid')){
|
||||
return $(this).data('gid');
|
||||
}
|
||||
}).get();
|
||||
updateGroup(groups);
|
||||
updateNodes(nodes);
|
||||
$tr.remove()
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -28,23 +28,19 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
{% if form.non_field_errors %}
|
||||
<div class="alert alert-danger">
|
||||
{{ form.non_field_errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<form method="post" class="form-horizontal" action="" >
|
||||
{% csrf_token %}
|
||||
<h3>{% trans 'Basic' %}</h3>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="id_name">{% trans 'Node' %}</label>
|
||||
<div class="col-md-9">
|
||||
<input type="text" class="form-control" readonly value="{{ form.node.initial }}">
|
||||
</div>
|
||||
</div>
|
||||
{{ form.node }}
|
||||
{% bootstrap_field form.user_group layout="horizontal" %}
|
||||
{% bootstrap_field form.system_user layout="horizontal" %}
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'User' %}</h3>
|
||||
{% bootstrap_field form.users layout="horizontal" %}
|
||||
{% bootstrap_field form.user_groups layout="horizontal" %}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Asset' %}</h3>
|
||||
{% bootstrap_field form.assets layout="horizontal" %}
|
||||
{% bootstrap_field form.nodes layout="horizontal" %}
|
||||
{% bootstrap_field form.system_users layout="horizontal" %}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Other' %}</h3>
|
||||
<div class="form-group">
|
||||
|
@ -53,17 +49,19 @@
|
|||
{{ form.is_active }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group {% if form.date_expired.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>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group date">
|
||||
<div class="input-daterange input-group" id="datepicker">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
<input id="{{ form.date_expired.id_for_label }}" name="{{ form.date_expired.html_name }}" type="text" class="form-control" value="{{ form.date_expired.value|date:'Y-m-d'|default:form.date_expired.value }}">
|
||||
<input type="text" class="input-sm form-control" name="date_start" value="{{ form.date_start.value|date:'Y-m-d' }}">
|
||||
<span class="input-group-addon">to</span>
|
||||
<input type="text" class="input-sm form-control" name="date_expired" value="{{ form.date_expired.value|date:'Y-m-d' }}">
|
||||
</div>
|
||||
<span class="help-block ">{{ form.date_expired.errors }}</span>
|
||||
<span class="help-block ">{{ form.date_start.errors }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% bootstrap_field form.comment layout="horizontal" %}
|
||||
|
||||
<div class="form-group">
|
||||
|
@ -84,15 +82,14 @@
|
|||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
|
||||
$('.input-group.date').datepicker({
|
||||
$('#datepicker').datepicker({
|
||||
format: "yyyy-mm-dd",
|
||||
todayBtn: "linked",
|
||||
keyboardNavigation: false,
|
||||
forceParse: false,
|
||||
calendarWeeks: true,
|
||||
autoclose: true
|
||||
})
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -15,19 +15,19 @@
|
|||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active">
|
||||
<a href="{% url 'perms:asset-permission-detail' pk=asset_permission.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
|
||||
<a href="{% url 'perms:asset-permission-detail' pk=object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'perms:asset-permission-user-list' pk=asset_permission.id %}" class="text-center">
|
||||
<a href="{% url 'perms:asset-permission-user-list' pk=object.id %}" class="text-center">
|
||||
<i class="fa fa-bar-chart-o"></i> {% trans 'Users and user groups' %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'perms:asset-permission-asset-list' pk=asset_permission.id %}" class="text-center">
|
||||
<a href="{% url 'perms:asset-permission-asset-list' pk=object.id %}" class="text-center">
|
||||
<i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset groups' %}</a>
|
||||
</li>
|
||||
<li class="pull-right">
|
||||
<a class="btn btn-outline btn-default" href="{% url 'perms:asset-permission-update' pk=asset_permission.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
|
||||
<a class="btn btn-outline btn-default" href="{% url 'perms:asset-permission-update' pk=object.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
|
||||
</li>
|
||||
<li class="pull-right">
|
||||
<a class="btn btn-outline btn-danger btn-delete-perm">
|
||||
|
@ -40,7 +40,7 @@
|
|||
<div class="col-sm-7" style="padding-left: 0;">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label"><b>{{ asset_permission.name }}</b></span>
|
||||
<span class="label"><b>{{ object.name }}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
|
@ -60,43 +60,47 @@
|
|||
<tbody>
|
||||
<tr class="no-borders-tr">
|
||||
<td>{% trans 'Name' %}:</td>
|
||||
<td><b>{{ asset_permission.name }}</b></td>
|
||||
<td><b>{{ object.name }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'User count' %}:</td>
|
||||
<td><b>{{ asset_permission.users.count }}</b></td>
|
||||
<td><b>{{ object.users.count }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'User group count' %}:</td>
|
||||
<td><b>{{ asset_permission.users.count }}</b></td>
|
||||
<td><b>{{ object.users.count }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset count' %}:</td>
|
||||
<td><b>{{ asset_permission.assets.count }}</b></td>
|
||||
<td><b>{{ object.assets.count }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Asset group count' %}:</td>
|
||||
<td><b>{{ asset_permission.asset_groups.count }}</b></td>
|
||||
<td>{% trans 'Node count' %}:</td>
|
||||
<td><b>{{ object.nodes.count }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'System user count' %}:</td>
|
||||
<td><b>{{ asset_permission.system_users.count }}</b></td>
|
||||
<td><b>{{ object.system_users.count }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date start' %}:</td>
|
||||
<td><b>{{ object.date_start }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date expired' %}:</td>
|
||||
<td><b>{{ asset_permission.date_expired }}</b></td>
|
||||
<td><b>{{ object.date_expired }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date created' %}:</td>
|
||||
<td><b>{{ asset_permission.date_created }}</b></td>
|
||||
<td><b>{{ object.date_created }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Created by' %}:</td>
|
||||
<td><b>{{ asset_permission.created_by }}</b></td>
|
||||
<td><b>{{ object.created_by }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Comment' %}:</td>
|
||||
<td><b>{{ asset_permission.comment }}</b></td>
|
||||
<td><b>{{ object.comment }}</b></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -117,7 +121,7 @@
|
|||
<td><span style="float: right">
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" {% if asset_permission.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
|
||||
<input type="checkbox" {% if object.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
|
||||
<label class="onoffswitch-label" for="is_active">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
|
@ -155,7 +159,7 @@
|
|||
</tr>
|
||||
</form>
|
||||
|
||||
{% for system_user in system_users %}
|
||||
{% for system_user in object.system_users.all %}
|
||||
<tr {% if forloop.counter == 1 %} class="no-borders-tr" {% endif %} >
|
||||
<td ><b class="bdg-system-user" data-uid={{ system_user.id }}>{{ system_user.name }}</b></td>
|
||||
<td>
|
||||
|
@ -179,7 +183,7 @@
|
|||
jumpserver.system_users_selected = {};
|
||||
|
||||
function updateSystemUser(system_users) {
|
||||
var the_url = "{% url 'api-perms:asset-permission-detail' pk=asset_permission.id %}";
|
||||
var the_url = "{% url 'api-perms:asset-permission-detail' pk=object.id %}";
|
||||
var body = {
|
||||
system_users: Object.assign([], system_users)
|
||||
};
|
||||
|
@ -203,7 +207,7 @@ $(document).ready(function () {
|
|||
.on('click', '.btn-delete-perm', function () {
|
||||
var $this = $(this);
|
||||
var name = "{{ asset_permission.name }}";
|
||||
var uid = "{{ asset_permission.id }}";
|
||||
var uid = "{{ object.id }}";
|
||||
var the_url = '{% url "api-perms:asset-permission-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
|
||||
var redirect_url = "{% url 'perms:asset-permission-list' %}";
|
||||
objectDelete($this, name, the_url, redirect_url);
|
||||
|
@ -238,7 +242,7 @@ $(document).ready(function () {
|
|||
updateSystemUser(system_users);
|
||||
$tr.remove()
|
||||
}).on('click', '#is_active', function () {
|
||||
var the_url = '{% url "api-perms:asset-permission-detail" pk=asset_permission.id %}';
|
||||
var the_url = '{% url "api-perms:asset-permission-detail" pk=object.id %}';
|
||||
var checked = $(this).prop('checked');
|
||||
var body = {
|
||||
'is_active': checked
|
||||
|
|
|
@ -3,41 +3,29 @@
|
|||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
||||
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||
<link href="{% static 'css/plugins/jstree/style.min.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet">
|
||||
<script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script>
|
||||
<style type="text/css">
|
||||
div#rMenu {
|
||||
position:absolute;
|
||||
visibility:hidden;
|
||||
text-align: left;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
float: left;
|
||||
padding: 5px 0;
|
||||
margin: 2px 0 0;
|
||||
list-style: none;
|
||||
background-clip: padding-box;
|
||||
<style>
|
||||
.toggle {
|
||||
cursor: pointer;
|
||||
}
|
||||
div#rMenu li{
|
||||
margin: 1px 0;
|
||||
cursor: pointer;
|
||||
{#list-style: none outside none;#}
|
||||
.detail-key {
|
||||
width: 70px;
|
||||
}
|
||||
.dropdown a:hover {
|
||||
background-color: #f1f1f1
|
||||
}
|
||||
</style>
|
||||
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content">
|
||||
<div class="row">
|
||||
<div class="col-lg-3" id="split-left">
|
||||
<div class="col-lg-3" id="split-left" style="padding-left: 3px">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
|
||||
<div class="file-manager ">
|
||||
<div id="assetTree" class="ztree">
|
||||
</div>
|
||||
|
@ -61,16 +49,16 @@
|
|||
<table class="table table-striped table-bordered table-hover" id="permission_list_table" style="width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">
|
||||
<input type="checkbox" id="check_all" class="ipt_check_all" >
|
||||
</th>
|
||||
<th class="text-center">{% trans 'Node' %}</th>
|
||||
<th class="text-center">{% trans 'User group' %}</th>
|
||||
<th class="text-center">{% trans 'System user' %}</th>
|
||||
<th class="text-center">{% trans 'Is active' %}</th>
|
||||
<th class="text-center">{% trans 'Date expired' %}</th>
|
||||
<th class="text-center">{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
<th></th>
|
||||
<th>{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'User' %}</th>
|
||||
<th class="text-center">{% trans 'User group' %}</th>
|
||||
<th class="text-center">{% trans 'Asset' %}</th>
|
||||
<th class="text-center">{% trans 'Node'%}</th>
|
||||
<th class="text-center">{% trans 'System user' %}</th>
|
||||
<th class="text-center">{% trans 'Active' %}</th>
|
||||
<th class="text-center" >{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
|
@ -82,64 +70,21 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
|
||||
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
|
||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
||||
<script>
|
||||
var zTree, rMenu, table, show = 0;
|
||||
function initTable() {
|
||||
var options = {
|
||||
ele: $('#permission_list_table'),
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData) {
|
||||
var html = '<a href="{% url 'assets:asset-list' %}?node=99899">' + cellData.name + '</a>';
|
||||
$(td).html(html.replace("99899", cellData.pk));
|
||||
}},
|
||||
{targets: 2, createdCell: function (td, cellData) {
|
||||
var html = '<a href="{% url "users:user-group-detail" pk=DEFAULT_PK %}">' + cellData.name + '</a>';
|
||||
$(td).html(html.replace("{{ DEFAULT_PK }}", cellData.pk))
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
var html = '<a href="{% url 'assets:system-user-detail' pk=DEFAULT_PK %}">' + cellData.name + '</a>';
|
||||
$(td).html(html.replace("{{ DEFAULT_PK }}", cellData.pk));
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData) {
|
||||
var date_expired = cellData.split(" ");
|
||||
if (date_expired && date_expired.length === 3) {
|
||||
$(td).html(date_expired[0]);
|
||||
} else {
|
||||
$(td).html(cellData);
|
||||
}
|
||||
}},
|
||||
{targets: 6, createdCell: function (td, cellData, rowData) {
|
||||
var name = rowData.user_group.name + "=>" + rowData.system_user.name + "=>" + rowData.node.name;
|
||||
var update_btn = '<a href="{% url "perms:asset-permission-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-del" data-uid="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>'
|
||||
.replace('{{ DEFAULT_PK }}', cellData)
|
||||
.replace('99991938', name);
|
||||
$(td).html(update_btn + del_btn);
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-perms:asset-permission-list" %}',
|
||||
columns: [
|
||||
{data: "id"}, {data: "node"}, {data: "user_group" }, {data: "system_user"},
|
||||
{data: "is_active"}, {data: "date_expired"}, {data: "id"}
|
||||
],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
table = jumpserver.initDataTable(options);
|
||||
return table
|
||||
}
|
||||
|
||||
var zTree, table, show = 0;
|
||||
|
||||
function onSelected(event, treeNode) {
|
||||
setCookie('node_selected', treeNode.id);
|
||||
var url = table.ajax.url();
|
||||
url = setUrlParam(url, "node_id", treeNode.id);
|
||||
if (treeNode.is_asset) {
|
||||
url = setUrlParam(url, 'node', "");
|
||||
url = setUrlParam(url, 'asset', treeNode.id)
|
||||
} else {
|
||||
url = setUrlParam(url, 'asset', "");
|
||||
url = setUrlParam(url, 'node', treeNode.id)
|
||||
}
|
||||
setCookie('node_selected', treeNode.id);
|
||||
table.ajax.url(url);
|
||||
table.ajax.reload();
|
||||
|
@ -160,9 +105,114 @@ function selectQueryNode() {
|
|||
node = zTree.getNodesByParam("id", node_id, null);
|
||||
if (node){
|
||||
zTree.selectNode(node[0]);
|
||||
node.open = true;
|
||||
}
|
||||
}
|
||||
|
||||
function filter(treeId, parentNode, childNodes) {
|
||||
$.each(childNodes, function (index, value) {
|
||||
value["pId"] = value["parent"];
|
||||
value["name"] = value["value"];
|
||||
value["isParent"] = value["assets_amount"] !== 0;
|
||||
value["iconSkin"] = value["is_asset"] ? "file" : null;
|
||||
});
|
||||
return childNodes;
|
||||
}
|
||||
|
||||
function beforeAsync(treeId, treeNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function makeLabel(data) {
|
||||
return "<label class='detail-key'><b>" + data[0] + ": </b></label>" + data[1] + "</br>"
|
||||
}
|
||||
|
||||
function format(d) {
|
||||
var data = "";
|
||||
if (d.users.length > 0 ) {
|
||||
data += makeLabel(["{% trans 'User' %}", d.users.join(", ")])
|
||||
}
|
||||
if (d.user_groups.length > 0) {
|
||||
data += makeLabel(["{% trans 'User group' %}", d.user_groups.join(", ")])
|
||||
}
|
||||
if (d.assets.length > 0) {
|
||||
data += makeLabel(["{% trans 'Asset' %}", d.assets.join(", ")])
|
||||
}
|
||||
if (d.nodes.length > 0) {
|
||||
data += makeLabel(["{% trans 'Node' %}", d.nodes.join(", ")])
|
||||
}
|
||||
if (d.system_users.length > 0) {
|
||||
data += makeLabel(["{% trans 'System user' %}", d.system_users.join(", ")])
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
function initTable() {
|
||||
var options = {
|
||||
ele: $('#permission_list_table'),
|
||||
toggle: true,
|
||||
columnDefs: [
|
||||
{targets: 0, createdCell: function (td, cellData, rowData) {
|
||||
$(td).addClass("toggle");
|
||||
$(td).html("<i class='fa fa-angle-right'></i>");
|
||||
}},
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "perms:asset-permission-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
||||
}},
|
||||
{targets: 2, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 6, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 7, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 8, createdCell: function (td, cellData, rowData) {
|
||||
var update_btn = '<a href="{% url "perms:asset-permission-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-del" data-uid="{{ DEFAULT_PK }}" mark=1 data-name="99991938">{% trans "Delete" %}</a>'
|
||||
.replace('{{ DEFAULT_PK }}', cellData)
|
||||
.replace('99991938', rowData.name);
|
||||
if (rowData.inherit) {
|
||||
del_btn = del_btn.replace("mark", "disabled")
|
||||
}
|
||||
$(td).html(update_btn + del_btn);
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-perms:asset-permission-list" %}',
|
||||
columns: [
|
||||
{data: "id"}, {data: "name"}, {data: "users"},
|
||||
{data: "user_groups"}, {data: "assets"},
|
||||
{data: "nodes"}, {data: "system_users"},
|
||||
{data: "is_active", orderable: false}, {data: "id", orderable: false}
|
||||
],
|
||||
select: {},
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
table = jumpserver.initDataTable(options);
|
||||
return table
|
||||
}
|
||||
|
||||
|
||||
function initTree() {
|
||||
var setting = {
|
||||
view: {
|
||||
|
@ -174,25 +224,32 @@ function initTree() {
|
|||
enable: true
|
||||
}
|
||||
},
|
||||
async: {
|
||||
enable: true,
|
||||
url: "{% url 'api-assets:node-children-2' %}?assets=1",
|
||||
autoParam:["id", "name=n", "level=lv"],
|
||||
dataFilter: filter,
|
||||
type: 'get'
|
||||
},
|
||||
callback: {
|
||||
onSelected: onSelected
|
||||
onSelected: onSelected,
|
||||
beforeAsync: beforeAsync
|
||||
}
|
||||
};
|
||||
|
||||
var zNodes = [];
|
||||
$.get("{% url 'api-assets:node-list' %}", function(data, status){
|
||||
$.get("{% url 'api-assets:node-children-2' %}", function(data, status){
|
||||
$.each(data, function (index, value) {
|
||||
value["pId"] = value["parent"];
|
||||
{#if (value["key"] === "0") {#}
|
||||
value["open"] = true;
|
||||
{# }#}
|
||||
value["name"] = value["value"]
|
||||
value["isParent"] = value["assets_amount"] !== 0;
|
||||
value["name"] = value["value"];
|
||||
value["open"] = value["key"] === "0";
|
||||
});
|
||||
zNodes = data;
|
||||
{#$.fn.zTree.init($("#assetTree"), setting);#}
|
||||
$.fn.zTree.init($("#assetTree"), setting, zNodes);
|
||||
zTree = $.fn.zTree.getZTreeObj("assetTree");
|
||||
rMenu = $("#rMenu");
|
||||
selectQueryNode();
|
||||
selectQueryNode();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -226,12 +283,41 @@ $(document).ready(function(){
|
|||
.on('click', '.btn-create-permission', function () {
|
||||
var url = "{% url 'perms:asset-permission-create' %}";
|
||||
var nodes = zTree.getSelectedNodes();
|
||||
var current_node;
|
||||
if (nodes && nodes.length ===1 ){
|
||||
current_node = nodes[0];
|
||||
url += "?node_id=" + current_node.id;
|
||||
}
|
||||
var _nodes = [];
|
||||
var _assets = [];
|
||||
$.each(nodes, function (id, node) {
|
||||
if (node.is_asset) {
|
||||
_assets.push(node.id)
|
||||
} else {
|
||||
_nodes.push(node.id)
|
||||
}
|
||||
});
|
||||
url += "?assets=" + _assets.join(",") + "&nodes=" + _nodes.join(",");
|
||||
window.open(url, '_self');
|
||||
}).on('click', '.toggle', function (e) {
|
||||
e.preventDefault();
|
||||
var detailRows = [];
|
||||
var tr = $(this).closest('tr');
|
||||
var row = table.row(tr);
|
||||
var idx = $.inArray(tr.attr('id'), detailRows);
|
||||
|
||||
if (row.child.isShown()) {
|
||||
tr.removeClass('details');
|
||||
row.child.hide();
|
||||
|
||||
// Remove from the 'open' array
|
||||
detailRows.splice(idx, 1);
|
||||
}
|
||||
else {
|
||||
tr.addClass('details');
|
||||
$('.toggle i').removeClass('fa-angle-right').addClass('fa-angle-down');
|
||||
row.child(format(row.data())).show();
|
||||
// Add to the 'open' array
|
||||
if ( idx === -1 ) {
|
||||
detailRows.push(tr.attr('id'));
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
|
@ -57,12 +57,12 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in page_obj %}
|
||||
{% for user in object_list %}
|
||||
<tr>
|
||||
<td>{{ user.name }}</td>
|
||||
<td>{{ user.username }}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger btn-xs btn-remove-user {% if user.is_inherit_from_user_groups %} disabled {% endif %}" data-gid="{{ user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
||||
<button class="btn btn-danger btn-xs btn-remove-user {% if user.inherit %} disabled {% endif %}" data-gid="{{ user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -127,7 +127,7 @@
|
|||
</tr>
|
||||
</form>
|
||||
|
||||
{% for user_group in user_groups %}
|
||||
{% for user_group in asset_permission.user_groups.all %}
|
||||
<tr>
|
||||
<td ><b class="bdg_group" data-gid={{ user_group.id }}>{{ user_group.name }}</b></td>
|
||||
<td>
|
||||
|
|
|
@ -11,17 +11,50 @@ router.register('v1/asset-permissions', api.AssetPermissionViewSet, 'asset-permi
|
|||
|
||||
urlpatterns = [
|
||||
# 查询某个用户授权的资产和资产组
|
||||
url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', api.UserGrantedAssetsApi.as_view(), name='user-assets'),
|
||||
url(r'^v1/user/assets/$', api.UserGrantedAssetsApi.as_view(), name='my-assets'),
|
||||
url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$', api.UserGrantedNodesApi.as_view(), name='user-nodes'),
|
||||
url(r'^v1/user/nodes/$', api.UserGrantedNodesApi.as_view(), name='my-nodes'),
|
||||
url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$', api.UserGrantedNodesWithAssetsApi.as_view(), name='user-nodes-assets'),
|
||||
url(r'^v1/user/nodes-assets/$', api.UserGrantedNodesWithAssetsApi.as_view(), name='my-nodes-assets'),
|
||||
url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$',
|
||||
api.UserGrantedAssetsApi.as_view(), name='user-assets'),
|
||||
url(r'^v1/user/assets/$', api.UserGrantedAssetsApi.as_view(),
|
||||
name='my-assets'),
|
||||
url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$',
|
||||
api.UserGrantedNodesApi.as_view(), name='user-nodes'),
|
||||
url(r'^v1/user/nodes/$', api.UserGrantedNodesApi.as_view(),
|
||||
name='my-nodes'),
|
||||
url(
|
||||
r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$',
|
||||
api.UserGrantedNodeAssetsApi.as_view(), name='user-node-assets'),
|
||||
url(r'^v1/user/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$',
|
||||
api.UserGrantedNodeAssetsApi.as_view(), name='my-node-assets'),
|
||||
url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$',
|
||||
api.UserGrantedNodesWithAssetsApi.as_view(), name='user-nodes-assets'),
|
||||
url(r'^v1/user/nodes-assets/$', api.UserGrantedNodesWithAssetsApi.as_view(),
|
||||
name='my-nodes-assets'),
|
||||
|
||||
# 查询某个用户组授权的资产和资产组
|
||||
url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', api.UserGroupGrantedAssetsApi.as_view(), name='user-group-assets'),
|
||||
url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$', api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes'),
|
||||
url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$', api.UserGroupGrantedNodesWithAssetsApi.as_view(), name='user-group-nodes-assets'),
|
||||
url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$',
|
||||
api.UserGroupGrantedAssetsApi.as_view(), name='user-group-assets'),
|
||||
url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$',
|
||||
api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes'),
|
||||
url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$',
|
||||
api.UserGroupGrantedNodesWithAssetsApi.as_view(),
|
||||
name='user-group-nodes-assets'),
|
||||
url(
|
||||
r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$',
|
||||
api.UserGroupGrantedNodeAssetsApi.as_view(),
|
||||
name='user-group-node-assets'),
|
||||
|
||||
# 用户和资产授权变更
|
||||
url(r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/user/remove/$',
|
||||
api.AssetPermissionRemoveUserApi.as_view(),
|
||||
name='asset-permission-remove-user'),
|
||||
url(r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/user/add/$',
|
||||
api.AssetPermissionAddUserApi.as_view(),
|
||||
name='asset-permission-add-user'),
|
||||
url(r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/asset/remove/$',
|
||||
api.AssetPermissionRemoveAssetApi.as_view(),
|
||||
name='asset-permission-remove-asset'),
|
||||
url(r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/asset/add/$',
|
||||
api.AssetPermissionAddAssetApi.as_view(),
|
||||
name='asset-permission-add-asset'),
|
||||
|
||||
# 验证用户是否有某个资产和系统用户的权限
|
||||
url(r'v1/asset-permission/user/validate/$', api.ValidateUserAssetPermissionView.as_view(), name='validate-user-asset-permission'),
|
||||
|
|
|
@ -9,10 +9,10 @@ urlpatterns = [
|
|||
url(r'^asset-permission$', views.AssetPermissionListView.as_view(), name='asset-permission-list'),
|
||||
url(r'^asset-permission/create$', views.AssetPermissionCreateView.as_view(), name='asset-permission-create'),
|
||||
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/update$', views.AssetPermissionUpdateView.as_view(), name='asset-permission-update'),
|
||||
# url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})$', views.AssetPermissionDetailView.as_view(),name='asset-permission-detail'),
|
||||
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})$', views.AssetPermissionDetailView.as_view(),name='asset-permission-detail'),
|
||||
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/delete$', views.AssetPermissionDeleteView.as_view(), name='asset-permission-delete'),
|
||||
# url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/user$', views.AssetPermissionUserView.as_view(), name='asset-permission-user-list'),
|
||||
# url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/asset$', views.AssetPermissionAssetView.as_view(), name='asset-permission-asset-list'),
|
||||
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/user$', views.AssetPermissionUserView.as_view(), name='asset-permission-user-list'),
|
||||
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/asset$', views.AssetPermissionAssetView.as_view(), name='asset-permission-asset-list'),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -2,17 +2,204 @@
|
|||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
import collections
|
||||
from collections import defaultdict
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext as _
|
||||
import copy
|
||||
|
||||
from common.utils import setattr_bulk, get_logger
|
||||
from .models import NodePermission
|
||||
from common.utils import set_or_append_attr_bulk, get_logger
|
||||
from .models import AssetPermission
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
class AssetPermissionUtil:
|
||||
|
||||
@staticmethod
|
||||
def get_user_permissions(user):
|
||||
return AssetPermission.valid.all().filter(users=user)
|
||||
|
||||
@staticmethod
|
||||
def get_user_group_permissions(user_group):
|
||||
return AssetPermission.valid.all().filter(user_groups=user_group)
|
||||
|
||||
@staticmethod
|
||||
def get_asset_permissions(asset):
|
||||
return AssetPermission.valid.all().filter(assets=asset)
|
||||
|
||||
@staticmethod
|
||||
def get_node_permissions(node):
|
||||
return AssetPermission.valid.all().filter(nodes=node)
|
||||
|
||||
@staticmethod
|
||||
def get_system_user_permissions(system_user):
|
||||
return AssetPermission.objects.all().filter(system_users=system_user)
|
||||
|
||||
@classmethod
|
||||
def get_user_group_nodes(cls, group):
|
||||
nodes = defaultdict(set)
|
||||
permissions = cls.get_user_group_permissions(group)
|
||||
for perm in permissions:
|
||||
_nodes = perm.nodes.all()
|
||||
_system_users = perm.system_users.all()
|
||||
set_or_append_attr_bulk(_nodes, 'permission', perm.id)
|
||||
for node in _nodes:
|
||||
nodes[node].update(set(_system_users))
|
||||
return nodes
|
||||
|
||||
@classmethod
|
||||
def get_user_group_assets_direct(cls, group):
|
||||
assets = defaultdict(set)
|
||||
permissions = cls.get_user_group_permissions(group)
|
||||
for perm in permissions:
|
||||
_assets = perm.assets.all()
|
||||
_system_users = perm.system_users.all()
|
||||
set_or_append_attr_bulk(_assets, 'permission', perm.id)
|
||||
for asset in _assets:
|
||||
assets[asset].update(set(_system_users))
|
||||
return assets
|
||||
|
||||
@classmethod
|
||||
def get_user_group_nodes_assets(cls, group):
|
||||
assets = defaultdict(set)
|
||||
nodes = cls.get_user_group_nodes(group)
|
||||
for node, _system_users in nodes.items():
|
||||
_assets = node.get_all_assets()
|
||||
set_or_append_attr_bulk(_assets, 'inherit_node', node.id)
|
||||
set_or_append_attr_bulk(_assets, 'permission', getattr(node, 'permission', None))
|
||||
for asset in _assets:
|
||||
assets[asset].update(set(_system_users))
|
||||
return assets
|
||||
|
||||
@classmethod
|
||||
def get_user_group_assets(cls, group):
|
||||
assets = defaultdict(set)
|
||||
_assets = cls.get_user_group_assets_direct(group)
|
||||
_nodes_assets = cls.get_user_group_nodes_assets(group)
|
||||
for asset, _system_users in _assets.items():
|
||||
assets[asset].update(set(_system_users))
|
||||
for asset, _system_users in _nodes_assets.items():
|
||||
assets[asset].update(set(_system_users))
|
||||
return assets
|
||||
|
||||
@classmethod
|
||||
def get_user_group_nodes_with_assets(cls, user):
|
||||
"""
|
||||
:param user:
|
||||
:return: {node: {asset: set(su1, su2)}}
|
||||
"""
|
||||
nodes = defaultdict(dict)
|
||||
_assets = cls.get_user_group_assets(user)
|
||||
for asset, _system_users in _assets.items():
|
||||
_nodes = asset.get_nodes()
|
||||
for node in _nodes:
|
||||
if asset in nodes[node]:
|
||||
nodes[node][asset].update(_system_users)
|
||||
else:
|
||||
nodes[node][asset] = _system_users
|
||||
return nodes
|
||||
|
||||
@classmethod
|
||||
def get_user_assets_direct(cls, user):
|
||||
assets = defaultdict(set)
|
||||
permissions = list(cls.get_user_permissions(user))
|
||||
for perm in permissions:
|
||||
_assets = perm.assets.all()
|
||||
_system_users = perm.system_users.all()
|
||||
set_or_append_attr_bulk(_assets, 'permission', perm.id)
|
||||
for asset in _assets:
|
||||
assets[asset].update(set(_system_users))
|
||||
return assets
|
||||
|
||||
@classmethod
|
||||
def get_user_nodes_direct(cls, user):
|
||||
nodes = defaultdict(set)
|
||||
permissions = cls.get_user_permissions(user)
|
||||
for perm in permissions:
|
||||
_nodes = perm.nodes.all()
|
||||
_system_users = perm.system_users.all()
|
||||
set_or_append_attr_bulk(_nodes, 'permission', perm.id)
|
||||
for node in _nodes:
|
||||
nodes[node].update(set(_system_users))
|
||||
return nodes
|
||||
|
||||
@classmethod
|
||||
def get_user_nodes_assets_direct(cls, user):
|
||||
assets = defaultdict(set)
|
||||
nodes = cls.get_user_nodes_direct(user)
|
||||
for node, _system_users in nodes.items():
|
||||
_assets = node.get_all_assets()
|
||||
set_or_append_attr_bulk(_assets, 'inherit_node', node.id)
|
||||
set_or_append_attr_bulk(_assets, 'permission', getattr(node, 'permission', None))
|
||||
for asset in _assets:
|
||||
assets[asset].update(set(_system_users))
|
||||
return assets
|
||||
|
||||
@classmethod
|
||||
def get_user_assets_inherit_group(cls, user):
|
||||
assets = defaultdict(set)
|
||||
for group in user.groups.all():
|
||||
_assets = cls.get_user_group_assets(group)
|
||||
set_or_append_attr_bulk(_assets, 'inherit_group', group.id)
|
||||
for asset, _system_users in _assets.items():
|
||||
assets[asset].update(_system_users)
|
||||
return assets
|
||||
|
||||
@classmethod
|
||||
def get_user_assets(cls, user):
|
||||
assets = defaultdict(set)
|
||||
_assets_direct = cls.get_user_assets_direct(user)
|
||||
_nodes_assets_direct = cls.get_user_nodes_assets_direct(user)
|
||||
_assets_inherit_group = cls.get_user_assets_inherit_group(user)
|
||||
for asset, _system_users in _assets_direct.items():
|
||||
assets[asset].update(_system_users)
|
||||
for asset, _system_users in _nodes_assets_direct.items():
|
||||
assets[asset].update(_system_users)
|
||||
for asset, _system_users in _assets_inherit_group.items():
|
||||
assets[asset].update(_system_users)
|
||||
return assets
|
||||
|
||||
@classmethod
|
||||
def get_user_nodes_with_assets(cls, user):
|
||||
"""
|
||||
:param user:
|
||||
:return: {node: {asset: set(su1, su2)}}
|
||||
"""
|
||||
nodes = defaultdict(dict)
|
||||
_assets = cls.get_user_assets(user)
|
||||
for asset, _system_users in _assets.items():
|
||||
_nodes = asset.get_nodes()
|
||||
for node in _nodes:
|
||||
if asset in nodes[node]:
|
||||
nodes[node][asset].update(_system_users)
|
||||
else:
|
||||
nodes[node][asset] = _system_users
|
||||
return nodes
|
||||
|
||||
@classmethod
|
||||
def get_system_user_assets(cls, system_user):
|
||||
assets = set()
|
||||
permissions = cls.get_system_user_permissions(system_user)
|
||||
for perm in permissions:
|
||||
assets.update(set(perm.assets.all()))
|
||||
nodes = perm.nodes.all()
|
||||
for node in nodes:
|
||||
assets.update(set(node.get_all_assets()))
|
||||
return assets
|
||||
|
||||
@classmethod
|
||||
def get_node_system_users(cls, node):
|
||||
system_users = set()
|
||||
permissions = cls.get_node_permissions(node)
|
||||
for perm in permissions:
|
||||
system_users.update(perm.system_users.all())
|
||||
return system_users
|
||||
|
||||
|
||||
# Abandon
|
||||
class NodePermissionUtil:
|
||||
"""
|
||||
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def get_user_group_permissions(user_group):
|
||||
|
|
|
@ -3,20 +3,22 @@
|
|||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views.generic import ListView, CreateView, UpdateView
|
||||
from django.views.generic.edit import DeleteView
|
||||
from django.views.generic import ListView, CreateView, UpdateView, DetailView
|
||||
from django.views.generic.edit import DeleteView, SingleObjectMixin
|
||||
from django.urls import reverse_lazy
|
||||
from django.conf import settings
|
||||
|
||||
from common.utils import get_object_or_none
|
||||
from .hands import AdminUserRequiredMixin, Node
|
||||
from .models import AssetPermission, NodePermission
|
||||
from common.mixins import AdminUserRequiredMixin
|
||||
from .hands import Node, Asset, SystemUser, User, UserGroup
|
||||
from .models import AssetPermission
|
||||
from .forms import AssetPermissionForm
|
||||
|
||||
|
||||
class AssetPermissionListView(AdminUserRequiredMixin, ListView):
|
||||
model = NodePermission
|
||||
context_object_name = 'asset_permission_list'
|
||||
model = AssetPermission
|
||||
template_name = 'perms/asset_permission_list.html'
|
||||
paginate_by = settings.DISPLAY_PER_PAGE
|
||||
user = user_group = asset = node = system_user = q = ""
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
|
@ -28,18 +30,24 @@ class AssetPermissionListView(AdminUserRequiredMixin, ListView):
|
|||
|
||||
|
||||
class AssetPermissionCreateView(AdminUserRequiredMixin, CreateView):
|
||||
model = NodePermission
|
||||
model = AssetPermission
|
||||
form_class = AssetPermissionForm
|
||||
template_name = 'perms/asset_permission_create_update.html'
|
||||
success_url = reverse_lazy('perms:asset-permission-list')
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class=form_class)
|
||||
node_id = self.request.GET.get("node_id")
|
||||
node = get_object_or_none(Node, id=node_id)
|
||||
if not node:
|
||||
node = Node.root()
|
||||
form['node'].initial = node
|
||||
nodes_id = self.request.GET.get("nodes")
|
||||
assets_id = self.request.GET.get("assets")
|
||||
|
||||
if nodes_id:
|
||||
nodes_id = nodes_id.split(",")
|
||||
nodes = Node.objects.filter(id__in=nodes_id)
|
||||
form['nodes'].initial = nodes
|
||||
if assets_id:
|
||||
assets_id = assets_id.split(",")
|
||||
assets = Asset.objects.filter(id__in=assets_id)
|
||||
form['assets'].initial = assets
|
||||
return form
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
@ -52,16 +60,11 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, CreateView):
|
|||
|
||||
|
||||
class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||
model = NodePermission
|
||||
model = AssetPermission
|
||||
form_class = AssetPermissionForm
|
||||
template_name = 'perms/asset_permission_create_update.html'
|
||||
success_url = reverse_lazy("perms:asset-permission-list")
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class=form_class)
|
||||
form['node'].initial = form.instance.node
|
||||
return form
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': _('Perms'),
|
||||
|
@ -71,9 +74,84 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
|
|||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
|
||||
model = AssetPermission
|
||||
form_class = AssetPermissionForm
|
||||
template_name = 'perms/asset_permission_detail.html'
|
||||
success_url = reverse_lazy("perms:asset-permission-list")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': _('Perms'),
|
||||
'action': _('Update asset permission'),
|
||||
'system_users_remain': SystemUser.objects.exclude(
|
||||
granted_by_permissions=self.object
|
||||
),
|
||||
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView):
|
||||
model = AssetPermission
|
||||
template_name = 'delete_confirm.html'
|
||||
success_url = reverse_lazy('perms:asset-permission-list')
|
||||
|
||||
|
||||
class AssetPermissionUserView(AdminUserRequiredMixin,
|
||||
SingleObjectMixin,
|
||||
ListView):
|
||||
template_name = 'perms/asset_permission_user.html'
|
||||
context_object_name = 'asset_permission'
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
object = None
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object(queryset=AssetPermission.objects.all())
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.object.get_all_users()
|
||||
return queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': _('Perms'),
|
||||
'action': _('Asset permission user list'),
|
||||
'users_remain': User.objects.exclude(asset_permissions=self.object)
|
||||
.exclude(role=User.ROLE_APP),
|
||||
'user_groups_remain': UserGroup.objects.exclude(
|
||||
asset_permissions=self.object
|
||||
)
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetPermissionAssetView(AdminUserRequiredMixin,
|
||||
SingleObjectMixin,
|
||||
ListView):
|
||||
template_name = 'perms/asset_permission_asset.html'
|
||||
context_object_name = 'asset_permission'
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
object = None
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object(queryset=AssetPermission.objects.all())
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.object.get_all_assets()
|
||||
return queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
assets_granted = self.get_queryset()
|
||||
context = {
|
||||
'app': _('Perms'),
|
||||
'action': _('Asset permission asset list'),
|
||||
'assets_remain': Asset.objects.exclude(id__in=[a.id for a in assets_granted]),
|
||||
'nodes_remain': Node.objects.exclude(granted_by_permissions=self.object),
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
|
@ -212,49 +212,49 @@ website: http://code.google.com/p/jquerytree/
|
|||
height: 20px;
|
||||
}
|
||||
.ztree li span.button.root_open::before {
|
||||
content: "\f078";
|
||||
content: "\f107";
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
}
|
||||
.ztree li span.button.root_close::before {
|
||||
content: "\f054";
|
||||
content: "\f105";
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
}
|
||||
.ztree li span.button.roots_open::before {
|
||||
content: "\f078";
|
||||
content: "\f107";
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
}
|
||||
.ztree li span.button.roots_close::before {
|
||||
content: "\f054";
|
||||
content: "\f105";
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
}
|
||||
.ztree li span.button.center_open::before {
|
||||
content: "\f078";
|
||||
content: "\f107";
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
}
|
||||
.ztree li span.button.center_close::before {
|
||||
content: "\f054";
|
||||
content: "\f105";
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
}
|
||||
.ztree li span.button.bottom_open::before {
|
||||
content: "\f078";
|
||||
content: "\f107";
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
}
|
||||
.ztree li span.button.bottom_close::before {
|
||||
content: "\f054";
|
||||
content: "\f105";
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
|
@ -300,7 +300,31 @@ website: http://code.google.com/p/jquerytree/
|
|||
color: #676a6c;
|
||||
}
|
||||
.ztree li span.button.ico_docu::before {
|
||||
content: "\f114";
|
||||
content: "\f07b";
|
||||
font-family: FontAwesome;
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
color: #676a6c;
|
||||
}
|
||||
.ztree li span.button.file_ico_docu::before {
|
||||
content: "\f022";
|
||||
font-family: FontAwesome;
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
color: #676a6c;
|
||||
}
|
||||
.ztree li span.button.linux_ico_docu::before {
|
||||
content: "\f17c";
|
||||
font-family: FontAwesome;
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
display: inline-block;
|
||||
color: #676a6c;
|
||||
}
|
||||
.ztree li span.button.windows_ico_docu::before {
|
||||
content: "\f17a";
|
||||
font-family: FontAwesome;
|
||||
padding-top: 10px;
|
||||
padding-left: 2px;
|
||||
|
|
|
@ -39,11 +39,11 @@ website: http://code.google.com/p/jquerytree/
|
|||
margin:0; padding:5px; color:@color-normal; background-color: @color-bg;
|
||||
li {
|
||||
padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0;
|
||||
ul {
|
||||
ul {
|
||||
margin: 0px; padding:0 0 0 18px;
|
||||
}
|
||||
ul.line { }
|
||||
a {padding-right:3px; margin:0; cursor:pointer; height:@h; color:@color-normal; background-color: transparent;
|
||||
a {padding-right:3px; margin:0; cursor:pointer; height:@h; color:@color-normal; background-color: transparent;
|
||||
text-decoration:none; vertical-align:top; display: inline-block;
|
||||
input.rename {height:14px; width:80px; padding:0; margin:0;
|
||||
color: @color-bg; background-color: @color-normal;
|
||||
|
@ -64,11 +64,11 @@ website: http://code.google.com/p/jquerytree/
|
|||
span.button {line-height:0; margin:0; padding: 0; width:@w; height:@h; display: inline-block; vertical-align:top;
|
||||
border:0px solid; cursor: pointer;outline:none;
|
||||
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
|
||||
|
||||
|
||||
&::before{color: @color-normal; font-family: FontAwesome; padding-top:@pad-top;}
|
||||
&.chk { margin:0px; cursor: auto; width: 12px;
|
||||
display: inline-block;padding-top:@pad-top;padding-left:@pad-left;
|
||||
|
||||
|
||||
&.checkbox_false_full::before {content: @fa-square-o;}
|
||||
&.checkbox_false_full_focus::before {content: @fa-square-o; color:@color-highlight;}
|
||||
&.checkbox_false_part::before {content: @fa-square-o;color: @color-partial;}
|
||||
|
@ -82,7 +82,7 @@ website: http://code.google.com/p/jquerytree/
|
|||
&.checkbox_true_part::before {content: @fa-check-square-o;color: @color-partial}
|
||||
&.checkbox_true_part_focus::before {content: @fa-check-square-o;color: @color-partfocus;}
|
||||
&.checkbox_true_disable::before {content: @fa-check-square-o;color: @color-disabled}
|
||||
|
||||
|
||||
&.radio_false_full::before {content: @fa-circle-o;}
|
||||
&.radio_false_full_focus::before {content: @fa-circle-o;color: @color-highlight}
|
||||
&.radio_false_part::before {content: @fa-circle-o;color: @color-partial}
|
||||
|
@ -93,17 +93,17 @@ website: http://code.google.com/p/jquerytree/
|
|||
&.radio_true_part::before {content: @fa-dot-circle-o;color: @color-partial}
|
||||
&.radio_true_part_focus::before {content: @fa-dot-circle-o;color: @color-partial;}
|
||||
&.radio_true_disable::before {content: @fa-circle-thin;color: @color-disabled}
|
||||
|
||||
|
||||
}
|
||||
&.switch {width:@w; height:@h}
|
||||
&.root_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.root_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.roots_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.roots_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.center_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.center_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.bottom_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.bottom_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.root_open::before{content: @fa-angle-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.root_close::before{content: @fa-angle-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.roots_open::before{content: @fa-angle-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.roots_close::before{content: @fa-angle-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.center_open::before{content: @fa-angle-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.center_close::before{content: @fa-angle-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.bottom_open::before{content: @fa-angle-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.bottom_close::before{content: @fa-angle-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
|
||||
&.noline_open{}
|
||||
&.noline_close{}
|
||||
&.root_docu{ background:none;}
|
||||
|
@ -111,11 +111,15 @@ website: http://code.google.com/p/jquerytree/
|
|||
&.center_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
|
||||
&.bottom_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
|
||||
&.noline_docu{ background:none;}
|
||||
|
||||
|
||||
&.ico_open::before {content: @fa-folder-open;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
|
||||
&.ico_close::before {content: @fa-folder;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
|
||||
&.ico_docu::before{content: @fa-folder-o;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
|
||||
|
||||
&.ico_docu::before{content: @fa-folder;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
|
||||
|
||||
&.file_ico_docu::before{content: @fa-list-alt;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
|
||||
&.linux_ico_docu::before{content: @fa-linux;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
|
||||
&.windows_ico_docu::before{content: @fa-windows;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
|
||||
|
||||
&.edit {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;}
|
||||
&.edit::before{content: @fa-pencil-square-o;font-family: FontAwesome;}
|
||||
|
||||
|
|
|
@ -62,7 +62,6 @@ function GetTableDataBox() {
|
|||
}
|
||||
}
|
||||
for (i in id_list) {
|
||||
console.log(tabProduct);
|
||||
tableData.push(GetRowData(tabProduct.rows[id_list[i]]));
|
||||
}
|
||||
|
||||
|
@ -240,6 +239,13 @@ $.fn.serializeObject = function()
|
|||
});
|
||||
return o;
|
||||
};
|
||||
|
||||
function makeLabel(data) {
|
||||
return "<label class='detail-key'><b>" + data[0] + ": </b></label>" + data[1] + "</br>"
|
||||
}
|
||||
|
||||
|
||||
|
||||
var jumpserver = {};
|
||||
jumpserver.checked = false;
|
||||
jumpserver.selected = {};
|
||||
|
@ -281,7 +287,7 @@ jumpserver.initDataTable = function (options) {
|
|||
buttons: [],
|
||||
columnDefs: columnDefs,
|
||||
ajax: {
|
||||
url: options.ajax_url ,
|
||||
url: options.ajax_url,
|
||||
dataSrc: ""
|
||||
},
|
||||
columns: options.columns || [],
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block table_search %}
|
||||
<form id="search_form" method="get" action="" class="pull-right form-inline">
|
||||
<form id="search_form" method="get" action="" class="pull-right form-inline" style="padding-bottom: 8px">
|
||||
<div class="form-group" id="date">
|
||||
<div class="input-daterange input-group" id="datepicker">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
|
@ -64,7 +64,7 @@
|
|||
</form>
|
||||
{% endblock %}
|
||||
{% block table_container %}
|
||||
<table class="footable table table-stripped toggle-arrow-tiny" data-page="false">
|
||||
<table class="footable table table-stripped table-bordered toggle-arrow-tiny" data-page="false" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-toggle="true">ID</th>
|
||||
|
|
|
@ -26,11 +26,15 @@ logger = get_logger(__name__)
|
|||
|
||||
class UserViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||
queryset = User.objects.exclude(role="App")
|
||||
# queryset = User.objects.all().exclude(role="App").order_by("date_joined")
|
||||
serializer_class = UserSerializer
|
||||
permission_classes = (IsSuperUserOrAppUser, IsAuthenticated)
|
||||
permission_classes = (IsSuperUser,)
|
||||
filter_fields = ('username', 'email', 'name', 'id')
|
||||
|
||||
def get_permissions(self):
|
||||
if self.action == "retrieve":
|
||||
self.permission_classes = (IsSuperUserOrAppUser,)
|
||||
return super().get_permissions()
|
||||
|
||||
|
||||
class ChangeUserPasswordApi(generics.RetrieveUpdateAPIView):
|
||||
permission_classes = (IsSuperUser,)
|
||||
|
@ -57,7 +61,6 @@ class UserResetPasswordApi(generics.UpdateAPIView):
|
|||
def perform_update(self, serializer):
|
||||
# Note: we are not updating the user object here.
|
||||
# We just do the reset-password stuff.
|
||||
import uuid
|
||||
from .utils import send_reset_password_mail
|
||||
user = self.get_object()
|
||||
user.password_raw = str(uuid.uuid4())
|
||||
|
@ -68,6 +71,7 @@ class UserResetPasswordApi(generics.UpdateAPIView):
|
|||
class UserResetPKApi(generics.UpdateAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
from .utils import send_reset_ssh_key_mail
|
||||
|
@ -91,6 +95,7 @@ class UserUpdatePKApi(generics.UpdateAPIView):
|
|||
class UserGroupViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||
queryset = UserGroup.objects.all()
|
||||
serializer_class = UserGroupSerializer
|
||||
permission_classes = (IsSuperUser,)
|
||||
|
||||
|
||||
class UserGroupUpdateUserApi(generics.RetrieveUpdateAPIView):
|
||||
|
|
|
@ -6,7 +6,6 @@ from django.utils.translation import gettext_lazy as _
|
|||
from captcha.fields import CaptchaField
|
||||
|
||||
from common.utils import validate_ssh_public_key
|
||||
from perms.models import AssetPermission
|
||||
from .models import User, UserGroup
|
||||
|
||||
|
||||
|
@ -253,30 +252,30 @@ class UserGroupForm(forms.ModelForm):
|
|||
}
|
||||
|
||||
|
||||
class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
|
||||
def save(self, commit=True):
|
||||
self.instance = super(UserGroupPrivateAssetPermissionForm, self)\
|
||||
.save(commit=commit)
|
||||
self.instance.user_groups = [self.user_group]
|
||||
self.instance.save()
|
||||
return self.instance
|
||||
|
||||
class Meta:
|
||||
model = AssetPermission
|
||||
fields = [
|
||||
'assets', 'asset_groups', 'system_users', 'name',
|
||||
]
|
||||
widgets = {
|
||||
'assets': forms.SelectMultiple(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select assets')}),
|
||||
'asset_groups': forms.SelectMultiple(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset groups')}),
|
||||
'system_users': forms.SelectMultiple(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select system users')}),
|
||||
}
|
||||
# class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
|
||||
# def save(self, commit=True):
|
||||
# self.instance = super(UserGroupPrivateAssetPermissionForm, self)\
|
||||
# .save(commit=commit)
|
||||
# self.instance.user_groups = [self.user_group]
|
||||
# self.instance.save()
|
||||
# return self.instance
|
||||
#
|
||||
# class Meta:
|
||||
# model = AssetPermission
|
||||
# fields = [
|
||||
# 'assets', 'asset_groups', 'system_users', 'name',
|
||||
# ]
|
||||
# widgets = {
|
||||
# 'assets': forms.SelectMultiple(
|
||||
# attrs={'class': 'select2',
|
||||
# 'data-placeholder': _('Select assets')}),
|
||||
# 'asset_groups': forms.SelectMultiple(
|
||||
# attrs={'class': 'select2',
|
||||
# 'data-placeholder': _('Select asset groups')}),
|
||||
# 'system_users': forms.SelectMultiple(
|
||||
# attrs={'class': 'select2',
|
||||
# 'data-placeholder': _('Select system users')}),
|
||||
# }
|
||||
|
||||
|
||||
class FileForm(forms.Form):
|
||||
|
|
|
@ -30,6 +30,11 @@ class User(AbstractUser):
|
|||
(ROLE_USER, _('User')),
|
||||
(ROLE_APP, _('Application'))
|
||||
)
|
||||
OTP_LEVEL_CHOICES = (
|
||||
(0, _('Disable')),
|
||||
(1, _('Enable')),
|
||||
(2, _("Force enable")),
|
||||
)
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
username = models.CharField(max_length=128, unique=True, verbose_name=_('Username'))
|
||||
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
||||
|
@ -39,8 +44,8 @@ class User(AbstractUser):
|
|||
avatar = models.ImageField(upload_to="avatar", null=True, verbose_name=_('Avatar'))
|
||||
wechat = models.CharField(max_length=128, blank=True, verbose_name=_('Wechat'))
|
||||
phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone'))
|
||||
enable_otp = models.BooleanField(default=False, verbose_name=_('Enable OTP'))
|
||||
secret_key_otp = models.CharField(max_length=16, blank=True)
|
||||
otp_level = models.SmallIntegerField(default=0, choices=OTP_LEVEL_CHOICES, verbose_name=_('Enable OTP'))
|
||||
otp_secret_key = models.CharField(max_length=16, blank=True)
|
||||
# Todo: Auto generate key, let user download
|
||||
_private_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Private key'))
|
||||
_public_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Public key'))
|
||||
|
@ -50,7 +55,7 @@ class User(AbstractUser):
|
|||
created_by = models.CharField(max_length=30, default='', verbose_name=_('Created by'))
|
||||
|
||||
def __str__(self):
|
||||
return self.username
|
||||
return '{0.name}({0.username})'.format(self)
|
||||
|
||||
@property
|
||||
def password_raw(self):
|
||||
|
@ -202,6 +207,20 @@ class User(AbstractUser):
|
|||
def generate_reset_token(self):
|
||||
return signer.sign_t({'reset': str(self.id), 'email': self.email}, expires_in=3600)
|
||||
|
||||
@property
|
||||
def otp_enabled(self):
|
||||
return self.otp_level > 0
|
||||
|
||||
def enabled_otp(self):
|
||||
self.otp_level = 1
|
||||
|
||||
def force_enable_otp(self):
|
||||
self.otp_level = 2
|
||||
|
||||
@property
|
||||
def otp_force_enabled(self):
|
||||
return self.otp_level == 2
|
||||
|
||||
def to_json(self):
|
||||
return OrderedDict({
|
||||
'id': self.id,
|
||||
|
@ -222,7 +241,7 @@ class User(AbstractUser):
|
|||
def create_app_user(cls, name, comment):
|
||||
app = cls.objects.create(
|
||||
username=name, name=name, email='{}@local.domain'.format(name),
|
||||
is_active=False, role='App', enable_otp=False, comment=comment,
|
||||
is_active=False, role='App', comment=comment,
|
||||
is_first_login=False, created_by='System'
|
||||
)
|
||||
access_key = app.create_access_key()
|
||||
|
|
|
@ -2,19 +2,29 @@
|
|||
#
|
||||
|
||||
from django.dispatch import receiver
|
||||
from django.db.models.signals import post_save
|
||||
# from django.db.models.signals import post_save
|
||||
|
||||
from common.utils import get_logger
|
||||
from .models import User
|
||||
from .signals import post_user_create
|
||||
# from .models import User
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def on_user_created(sender, instance=None, created=False, **kwargs):
|
||||
if created:
|
||||
logger.debug("Receive user `{}` create signal".format(instance.name))
|
||||
from .utils import send_user_created_mail
|
||||
logger.info(" - Sending welcome mail ...".format(instance.name))
|
||||
if instance.email:
|
||||
send_user_created_mail(instance)
|
||||
# @receiver(post_save, sender=User)
|
||||
# def on_user_created(sender, instance=None, created=False, **kwargs):
|
||||
# if created:
|
||||
# logger.debug("Receive user `{}` create signal".format(instance.name))
|
||||
# from .utils import send_user_created_mail
|
||||
# logger.info(" - Sending welcome mail ...".format(instance.name))
|
||||
# if instance.email:
|
||||
# send_user_created_mail(instance)
|
||||
|
||||
|
||||
@receiver(post_user_create)
|
||||
def on_user_create(sender, user=None, **kwargs):
|
||||
logger.debug("Receive user `{}` create signal".format(user.name))
|
||||
from .utils import send_user_created_mail
|
||||
logger.info(" - Sending welcome mail ...".format(user.name))
|
||||
if user.email:
|
||||
send_user_created_mail(user)
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
<th class="text-center">{% trans 'Hostname' %}</th>
|
||||
<th class="text-center">{% trans 'IP' %}</th>
|
||||
<th class="text-center">{% trans 'Active' %}</th>
|
||||
<th class="text-center">{% trans 'Reachable' %}</th>
|
||||
<th class="text-center">{% trans 'System users' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -63,6 +63,8 @@
|
|||
<script>
|
||||
var zTree;
|
||||
var inited = false;
|
||||
var url;
|
||||
var asset_table;
|
||||
|
||||
function initTable() {
|
||||
if (inited){
|
||||
|
@ -86,31 +88,28 @@ function initTable() {
|
|||
}
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
if (cellData === 'Unknown'){
|
||||
$(td).html('<i class="fa fa-circle text-warning"></i>')
|
||||
} else if (!cellData) {
|
||||
$(td).html('<i class="fa fa-circle text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-circle text-navy"></i>')
|
||||
}
|
||||
var users = [];
|
||||
$.each(cellData, function (id, data) {
|
||||
users.push(data.name);
|
||||
});
|
||||
$(td).html(users.join(', '))
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-assets:asset-list" %}',
|
||||
ajax_url: url,
|
||||
columns: [
|
||||
{data: "id"}, {data: "hostname" }, {data: "ip" },
|
||||
{data: "is_active", orderable: false },
|
||||
{data: "is_connective", orderable: false}
|
||||
{data: "system_users_granted", orderable: false}
|
||||
]
|
||||
};
|
||||
asset_table = jumpserver.initServerSideDataTable(options);
|
||||
return asset_table
|
||||
return jumpserver.initDataTable(options);
|
||||
}
|
||||
|
||||
function onSelected(event, treeNode) {
|
||||
initTable();
|
||||
var url = asset_table.ajax.url();
|
||||
url = setUrlParam(url, "node_id", treeNode.id);
|
||||
url = '{% url "api-perms:user-node-assets" pk=object.id node_id=DEFAULT_PK %}';
|
||||
url = url.replace("{{ DEFAULT_PK }}", treeNode.id);
|
||||
setCookie('node_selected', treeNode.id);
|
||||
asset_table = initTable();
|
||||
asset_table.ajax.url(url);
|
||||
asset_table.ajax.reload();
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
<script>
|
||||
var zTree;
|
||||
var inited = false;
|
||||
var url;
|
||||
|
||||
function initTable() {
|
||||
if (inited){
|
||||
|
@ -86,31 +87,29 @@ function initTable() {
|
|||
}
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
if (cellData === 'Unknown'){
|
||||
$(td).html('<i class="fa fa-circle text-warning"></i>')
|
||||
} else if (!cellData) {
|
||||
$(td).html('<i class="fa fa-circle text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-circle text-navy"></i>')
|
||||
}
|
||||
var users = [];
|
||||
$.each(cellData, function (id, data) {
|
||||
users.push(data.name);
|
||||
});
|
||||
$(td).html(users.join(', '))
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-assets:asset-list" %}',
|
||||
ajax_url: url,
|
||||
columns: [
|
||||
{data: "id"}, {data: "hostname" }, {data: "ip" },
|
||||
{data: "is_active", orderable: false },
|
||||
{data: "is_connective", orderable: false}
|
||||
{data: "system_users_granted", orderable: false}
|
||||
]
|
||||
};
|
||||
asset_table = jumpserver.initServerSideDataTable(options);
|
||||
asset_table = jumpserver.initDataTable(options);
|
||||
return asset_table
|
||||
}
|
||||
|
||||
function onSelected(event, treeNode) {
|
||||
initTable();
|
||||
var url = asset_table.ajax.url();
|
||||
url = setUrlParam(url, "node_id", treeNode.id);
|
||||
url = '{% url "api-perms:user-group-node-assets" pk=object.id node_id=DEFAULT_PK %}';
|
||||
url = url.replace("{{ DEFAULT_PK }}", treeNode.id);
|
||||
setCookie('node_selected', treeNode.id);
|
||||
asset_table = initTable();
|
||||
asset_table.ajax.url(url);
|
||||
asset_table.ajax.reload();
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">{% trans 'OTP' %}</td>
|
||||
<td>{{ user.enable_otp|yesno:"Yes,No,Unkown" }}</td>
|
||||
<td>{{ user.otp_enabled|yesno:"Yes,No,Unkown" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">{% trans 'Public key' %}</td>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
from django import forms
|
||||
from django.shortcuts import render
|
||||
from django.contrib.auth import login as auth_login, logout as auth_logout
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
|
@ -20,10 +19,9 @@ from django.views.generic.base import TemplateView
|
|||
from django.views.generic.edit import FormView
|
||||
from formtools.wizard.views import SessionWizardView
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
|
||||
from common.utils import get_object_or_none
|
||||
from common.mixins import DatetimeSearchMixin
|
||||
from common.mixins import DatetimeSearchMixin, AdminUserRequiredMixin
|
||||
from ..models import User, LoginLog
|
||||
from ..utils import send_reset_password_mail
|
||||
from ..tasks import write_login_log_async
|
||||
|
@ -194,8 +192,6 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
|
|||
for field in form:
|
||||
if field.value():
|
||||
setattr(user, field.name, field.value())
|
||||
if field.name == 'enable_otp':
|
||||
user.enable_otp = field.value()
|
||||
user.is_first_login = False
|
||||
user.is_public_key_valid = True
|
||||
user.save()
|
||||
|
@ -228,7 +224,7 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
|
|||
return form
|
||||
|
||||
|
||||
class LoginLogListView(DatetimeSearchMixin, ListView):
|
||||
class LoginLogListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
|
||||
template_name = 'users/login_log_list.html'
|
||||
model = LoginLog
|
||||
paginate_by = settings.DISPLAY_PER_PAGE
|
||||
|
|
|
@ -79,6 +79,7 @@ class UserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
|||
user = form.save(commit=False)
|
||||
user.created_by = self.request.user.username or 'System'
|
||||
user.save()
|
||||
post_user_create.send(self.__class__, user=user)
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
|
||||
python ../apps/manage.py shell << EOF
|
||||
from perms.models import *
|
||||
|
||||
for old in NodePermission.objects.all():
|
||||
perm = asset_perm_model.objects.using(db_alias).create(
|
||||
name="{}-{}-{}".format(
|
||||
old.node.value,
|
||||
old.user_group.name,
|
||||
old.system_user.name
|
||||
),
|
||||
is_active=old.is_active,
|
||||
date_expired=old.date_expired,
|
||||
created_by=old.date_expired,
|
||||
date_created=old.date_created,
|
||||
comment=old.comment,
|
||||
)
|
||||
perm.user_groups.add(old.user_group)
|
||||
perm.nodes.add(old.node)
|
||||
perm.system_users.add(old.system_user)
|
||||
EOF
|
||||
|
Loading…
Reference in New Issue