mirror of https://github.com/jumpserver/jumpserver
[Update] 修改permission actions
commit
8e9b3f134b
|
@ -112,12 +112,16 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
|
|||
is_root = False
|
||||
|
||||
def get_queryset(self):
|
||||
self.check_need_refresh_nodes()
|
||||
node_key = self.request.query_params.get('key')
|
||||
util = NodeUtil()
|
||||
# 是否包含自己
|
||||
with_self = False
|
||||
if not node_key:
|
||||
node_key = Node.root().key
|
||||
with_self = True
|
||||
self.node = util.get_node_by_key(node_key)
|
||||
queryset = self.node.get_children(with_self=True)
|
||||
queryset = self.node.get_children(with_self=with_self)
|
||||
queryset = [node.as_tree_node() for node in queryset]
|
||||
queryset = sorted(queryset)
|
||||
return queryset
|
||||
|
@ -133,14 +137,11 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
|
|||
|
||||
def filter_queryset(self, queryset):
|
||||
queryset = self.filter_assets(queryset)
|
||||
queryset = self.filter_refresh_nodes(queryset)
|
||||
return queryset
|
||||
|
||||
def filter_refresh_nodes(self, queryset):
|
||||
def check_need_refresh_nodes(self):
|
||||
if self.request.query_params.get('refresh', '0') == '1':
|
||||
Node.expire_nodes_assets_amount()
|
||||
Node.expire_nodes_full_value()
|
||||
return queryset
|
||||
Node.refresh_nodes()
|
||||
|
||||
|
||||
class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _
|
|||
from common.utils import get_logger
|
||||
from orgs.mixins import OrgModelForm
|
||||
|
||||
from ..models import Asset, Protocol
|
||||
from ..models import Asset, Protocol, Node
|
||||
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
@ -33,6 +33,12 @@ class ProtocolForm(forms.ModelForm):
|
|||
class AssetCreateForm(OrgModelForm):
|
||||
PROTOCOL_CHOICES = Protocol.PROTOCOL_CHOICES
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
if not self.data:
|
||||
nodes_field = self.fields['nodes']
|
||||
nodes_field._queryset = Node.get_queryset()
|
||||
|
||||
class Meta:
|
||||
model = Asset
|
||||
fields = [
|
||||
|
|
|
@ -186,9 +186,6 @@ class FullValueMixin:
|
|||
def expire_nodes_full_value(cls, nodes=None):
|
||||
key = cls._full_value_cache_key.format('*')
|
||||
cache.delete_pattern(key+'*')
|
||||
from ..utils import NodeUtil
|
||||
util = NodeUtil()
|
||||
util.set_full_value()
|
||||
|
||||
|
||||
class AssetsAmountMixin:
|
||||
|
@ -216,7 +213,7 @@ class AssetsAmountMixin:
|
|||
def assets_amount(self, value):
|
||||
self._assets_amount = value
|
||||
cache_key = self._assets_amount_cache_key.format(self.key)
|
||||
cache.set(cache_key, value, 3600 * 24)
|
||||
cache.set(cache_key, value)
|
||||
|
||||
def expire_assets_amount(self):
|
||||
ancestor_keys = self.get_ancestor_keys(with_self=True)
|
||||
|
@ -226,11 +223,15 @@ class AssetsAmountMixin:
|
|||
|
||||
@classmethod
|
||||
def expire_nodes_assets_amount(cls, nodes=None):
|
||||
from ..utils import NodeUtil
|
||||
key = cls._assets_amount_cache_key.format('*')
|
||||
cache.delete_pattern(key)
|
||||
|
||||
@classmethod
|
||||
def refresh_nodes(cls):
|
||||
from ..utils import NodeUtil
|
||||
util = NodeUtil(with_assets_amount=True)
|
||||
util.set_assets_amount()
|
||||
util.set_full_value()
|
||||
|
||||
|
||||
class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
|
||||
|
@ -375,9 +376,7 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
|
|||
|
||||
def as_tree_node(self):
|
||||
from common.tree import TreeNode
|
||||
from ..serializers import NodeSerializer
|
||||
name = '{} ({})'.format(self.value, self.assets_amount)
|
||||
node_serializer = NodeSerializer(instance=self)
|
||||
data = {
|
||||
'id': self.key,
|
||||
'name': name,
|
||||
|
@ -386,7 +385,12 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
|
|||
'isParent': True,
|
||||
'open': self.is_root(),
|
||||
'meta': {
|
||||
'node': node_serializer.data,
|
||||
'node': {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"value": self.value,
|
||||
"key": self.key,
|
||||
},
|
||||
'type': 'node'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from rest_framework import serializers
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from orgs.mixins import BulkOrgResourceModelSerializer
|
||||
from ..models import Asset, Node
|
||||
|
@ -25,11 +26,11 @@ class NodeSerializer(BulkOrgResourceModelSerializer):
|
|||
|
||||
def validate_value(self, data):
|
||||
instance = self.instance if self.instance else Node.root()
|
||||
children = instance.parent.get_children().exclude(key=instance.key)
|
||||
values = [child.value for child in children]
|
||||
if data in values:
|
||||
children = instance.parent.get_children()
|
||||
children_values = [node.value for node in children if node != instance]
|
||||
if data in children_values:
|
||||
raise serializers.ValidationError(
|
||||
'The same level node name cannot be the same'
|
||||
_('The same level node name cannot be the same')
|
||||
)
|
||||
return data
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ function initTable2() {
|
|||
columns: [
|
||||
{data: "id"}, {data: "hostname" }, {data: "ip" }
|
||||
],
|
||||
lengthMenu: [[10, 25, 50], [10, 25, 50]],
|
||||
pageLength: 10
|
||||
};
|
||||
asset_table2 = jumpserver.initServerSideDataTable(options);
|
||||
|
|
|
@ -0,0 +1,358 @@
|
|||
{% load static %}
|
||||
{% load i18n %}
|
||||
<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet">
|
||||
{# <link href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.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%;#}
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
{#float: left;#}
|
||||
padding: 0 0;
|
||||
margin: 2px 0 0;
|
||||
list-style: none;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_processing {
|
||||
opacity: .9;
|
||||
border: none;
|
||||
}
|
||||
div#rMenu li{
|
||||
margin: 1px 0;
|
||||
cursor: pointer;
|
||||
list-style: none outside none;
|
||||
}
|
||||
.dropdown a:hover {
|
||||
background-color: #f1f1f1
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
|
||||
<div class="file-manager" id="tree-node-id">
|
||||
<div id="{% block treeID %}nodeTree{% endblock %}" class="ztree">
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="rMenu">
|
||||
<ul class="dropdown-menu menu-actions">
|
||||
<li class="divider"></li>
|
||||
<li id="m_create" tabindex="-1" onclick="addTreeNode();"><a><i class="fa fa-plus-square-o"></i> {% trans 'Add node' %}</a></li>
|
||||
<li id="m_del" tabindex="-1" onclick="editTreeNode();"><a><i class="fa fa-pencil-square-o"></i> {% trans 'Rename node' %}</a></li>
|
||||
<li id="m_del" tabindex="-1" onclick="removeTreeNode();"><a><i class="fa fa-minus-square"></i> {% trans 'Delete node' %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<script>
|
||||
var zTree, rMenu = null;
|
||||
var current_node_id = null;
|
||||
var current_node = null;
|
||||
var showMenu = false;
|
||||
|
||||
|
||||
var treeUrl = '{% url 'api-assets:node-children-tree' %}?assets=0';
|
||||
// options:
|
||||
// {
|
||||
// "onSelected": func,
|
||||
// "showAssets": false,
|
||||
// "beforeAsync": func()
|
||||
// "showMenu": false,
|
||||
// "otherMenu": "",
|
||||
// "showAssets": false,
|
||||
// }
|
||||
function initNodeTree(options) {
|
||||
var setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
async: {
|
||||
enable: true,
|
||||
url: treeUrl,
|
||||
autoParam: ["id=key", "name=n", "level=lv"],
|
||||
type: 'get'
|
||||
},
|
||||
edit: {
|
||||
enable: true,
|
||||
showRemoveBtn: false,
|
||||
showRenameBtn: false,
|
||||
drag: {
|
||||
isCopy: true,
|
||||
isMove: true
|
||||
}
|
||||
},
|
||||
callback: {
|
||||
onRightClick: OnRightClick,
|
||||
beforeClick: beforeClick,
|
||||
onRename: onRename,
|
||||
onSelected: options.onSelected || defaultCallback("On selected"),
|
||||
beforeDrag: beforeDrag,
|
||||
onDrag: onDrag,
|
||||
beforeDrop: beforeDrop,
|
||||
onDrop: onDrop,
|
||||
beforeAsync: options.beforeAsync || defaultCallback("Before async")
|
||||
}
|
||||
};
|
||||
if (options.showAssets) {
|
||||
treeUrl = setUrlParam(treeUrl, 'assets', '1')
|
||||
}
|
||||
|
||||
$.get(treeUrl, function(data, status){
|
||||
zNodes = data;
|
||||
zTree = $.fn.zTree.init($("#nodeTree"), setting, zNodes);
|
||||
rootNodeAddDom(zTree, function () {
|
||||
treeUrl = setUrlParam(treeUrl, 'refresh', '1');
|
||||
initTree();
|
||||
treeUrl = setUrlParam(treeUrl, 'refresh', '0')
|
||||
});
|
||||
});
|
||||
|
||||
if (options.showMenu) {
|
||||
showMenu = true;
|
||||
rMenu = $("#rMenu");
|
||||
}
|
||||
if (options.otherMenu) {
|
||||
$(".menu-actions").append(options.otherMenu)
|
||||
}
|
||||
return zTree
|
||||
}
|
||||
|
||||
function addTreeNode() {
|
||||
hideRMenu();
|
||||
var parentNode = zTree.getSelectedNodes()[0];
|
||||
if (!parentNode){
|
||||
return
|
||||
}
|
||||
var url = "{% url 'api-assets:node-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", parentNode.meta.node.id);
|
||||
$.post(url, {}, function (data, status){
|
||||
if (status === "success") {
|
||||
var newNode = {
|
||||
id: data["key"],
|
||||
name: data["value"],
|
||||
pId: parentNode.id,
|
||||
meta: {
|
||||
"node": data
|
||||
}
|
||||
};
|
||||
newNode.checked = zTree.getSelectedNodes()[0].checked;
|
||||
zTree.addNodes(parentNode, 0, newNode);
|
||||
var node = zTree.getNodeByParam('id', newNode.id, parentNode);
|
||||
zTree.editName(node);
|
||||
} else {
|
||||
alert("{% trans 'Create node failed' %}")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function removeTreeNode() {
|
||||
hideRMenu();
|
||||
var current_node = zTree.getSelectedNodes()[0];
|
||||
if (!current_node){
|
||||
return
|
||||
}
|
||||
if (current_node.children && current_node.children.length > 0) {
|
||||
toastr.error("{% trans 'Have child node, cancel' %}");
|
||||
} else if (current_node.meta.node.assets_amount !== 0) {
|
||||
toastr.error("{% trans 'Have assets, cancel' %}");
|
||||
} else {
|
||||
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
|
||||
$.ajax({
|
||||
url: url,
|
||||
method: "DELETE",
|
||||
success: function () {
|
||||
zTree.removeNode(current_node);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function editTreeNode() {
|
||||
hideRMenu();
|
||||
var current_node = zTree.getSelectedNodes()[0];
|
||||
if (!current_node){
|
||||
return
|
||||
}
|
||||
if (current_node) {
|
||||
current_node.name = current_node.meta.node.value;
|
||||
}
|
||||
zTree.editName(current_node);
|
||||
}
|
||||
|
||||
function OnRightClick(event, treeId, treeNode) {
|
||||
if (!showMenu) {
|
||||
return
|
||||
}
|
||||
if (!treeNode && event.target.tagName.toLowerCase() !== "button" && $(event.target).parents("a").length === 0) {
|
||||
zTree.cancelSelectedNode();
|
||||
showRMenu("root", event.clientX, event.clientY);
|
||||
} else if (treeNode && !treeNode.noR) {
|
||||
zTree.selectNode(treeNode);
|
||||
showRMenu("node", event.clientX, event.clientY);
|
||||
}
|
||||
}
|
||||
|
||||
function showRMenu(type, x, y) {
|
||||
var offset = $("#tree-node-id").offset();
|
||||
x -= offset.left;
|
||||
y -= offset.top;
|
||||
x += document.body.scrollLeft;
|
||||
y += document.body.scrollTop + document.documentElement.scrollTop;
|
||||
rMenu.css({"top":y+"px", "left":x+"px", "visibility":"visible"});
|
||||
$("#rMenu ul").show();
|
||||
$("body").bind("mousedown", onBodyMouseDown);
|
||||
}
|
||||
|
||||
function beforeClick(treeId, treeNode, clickFlag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function hideRMenu() {
|
||||
if (rMenu) rMenu.css({"visibility": "hidden"});
|
||||
$("body").unbind("mousedown", onBodyMouseDown);
|
||||
}
|
||||
|
||||
function onBodyMouseDown(event){
|
||||
if (!(event.target.id === "rMenu" || $(event.target).parents("#rMenu").length>0)) {
|
||||
rMenu.css({"visibility" : "hidden"});
|
||||
}
|
||||
}
|
||||
|
||||
function onRename(event, treeId, treeNode, isCancel){
|
||||
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
|
||||
var data = {"value": treeNode.name};
|
||||
if (isCancel){
|
||||
return
|
||||
}
|
||||
APIUpdateAttr({
|
||||
url: url,
|
||||
body: JSON.stringify(data),
|
||||
method: "PATCH",
|
||||
success_message: "{% trans 'Rename success' %}",
|
||||
success: function () {
|
||||
treeNode.name = treeNode.name + ' (' + treeNode.meta.node.assets_amount + ')';
|
||||
zTree.updateNode(treeNode);
|
||||
console.log("Success: " + treeNode.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function beforeDrag() {
|
||||
return true
|
||||
}
|
||||
|
||||
function beforeDrop(treeId, treeNodes, targetNode, moveType) {
|
||||
var treeNodesNames = [];
|
||||
$.each(treeNodes, function (index, value) {
|
||||
treeNodesNames.push(value.name);
|
||||
});
|
||||
|
||||
var msg = "你想移动节点: `" + treeNodesNames.join(",") + "` 到 `" + targetNode.name + "` 下吗?";
|
||||
return confirm(msg);
|
||||
}
|
||||
|
||||
function onDrag(event, treeId, treeNodes) {
|
||||
}
|
||||
|
||||
function onDrop(event, treeId, treeNodes, targetNode, moveType) {
|
||||
var treeNodesIds = [];
|
||||
$.each(treeNodes, function (index, value) {
|
||||
treeNodesIds.push(value.meta.node.id);
|
||||
});
|
||||
|
||||
var the_url = "{% url 'api-assets:node-add-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", targetNode.meta.node.id);
|
||||
var body = {nodes: treeNodesIds};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
method: "PUT",
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
}
|
||||
|
||||
function defaultCallback(action) {
|
||||
function logging() {
|
||||
console.log(action)
|
||||
}
|
||||
return logging
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
})
|
||||
.on('click', '.btn-refresh-hardware', function () {
|
||||
var url = "{% url 'api-assets:node-refresh-hardware-info' pk=DEFAULT_PK %}";
|
||||
var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
|
||||
function success(data) {
|
||||
rMenu.css({"visibility" : "hidden"});
|
||||
var task_id = data.task;
|
||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600')
|
||||
}
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
method: "GET",
|
||||
success: success,
|
||||
flash_message: false
|
||||
});
|
||||
|
||||
})
|
||||
.on('click', '.btn-test-connective', function () {
|
||||
var url = "{% url 'api-assets:node-test-connective' pk=DEFAULT_PK %}";
|
||||
if (!current_node_id) {
|
||||
return null;
|
||||
}
|
||||
var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
|
||||
function success(data) {
|
||||
rMenu.css({"visibility" : "hidden"});
|
||||
var task_id = data.task;
|
||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600')
|
||||
}
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
method: "GET",
|
||||
success: success,
|
||||
flash_message: false
|
||||
});
|
||||
})
|
||||
.on('click', '.btn-show-current-asset', function(){
|
||||
hideRMenu();
|
||||
$(this).css('display', 'none');
|
||||
$('#show_all_asset').css('display', 'inline-block');
|
||||
setCookie('show_current_asset', '1');
|
||||
location.reload()
|
||||
})
|
||||
.on('click', '.btn-show-all-asset', function(){
|
||||
hideRMenu();
|
||||
$(this).css('display', 'none');
|
||||
$('#show_current_asset').css('display', 'inline-block');
|
||||
setCookie('show_current_asset', '');
|
||||
location.reload();
|
||||
})
|
||||
.on('click', '.btn-test-connective', function () {
|
||||
hideRMenu();
|
||||
|
||||
})
|
||||
.on('click', '#menu_refresh_assets_amount', function () {
|
||||
hideRMenu();
|
||||
var url = "{% url 'api-assets:refresh-assets-amount' %}";
|
||||
APIUpdateAttr({
|
||||
'url': url,
|
||||
'method': 'GET'
|
||||
});
|
||||
window.location.reload();
|
||||
})
|
||||
</script>
|
|
@ -49,15 +49,7 @@
|
|||
<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>
|
||||
{% include 'assets/_node_tree.html' %}
|
||||
</div>
|
||||
<div class="col-lg-9 animated fadeInRight" id="split-right">
|
||||
<div class="tree-toggle">
|
||||
|
@ -132,26 +124,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="rMenu">
|
||||
<ul class="dropdown-menu">
|
||||
<li class="divider"></li>
|
||||
<li id="m_create" tabindex="-1" onclick="addTreeNode();"><a><i class="fa fa-plus-square-o"></i> {% trans 'Add node' %}</a></li>
|
||||
<li id="m_del" tabindex="-1" onclick="editTreeNode();"><a><i class="fa fa-pencil-square-o"></i> {% trans 'Rename node' %}</a></li>
|
||||
<li id="m_del" tabindex="-1" onclick="removeTreeNode();"><a><i class="fa fa-minus-square"></i> {% trans 'Delete node' %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="menu_asset_add" class="btn-add-asset" data-toggle="modal" data-target="#asset_list_modal" tabindex="0"><a><i class="fa fa-copy"></i> {% trans 'Add assets to node' %}</a></li>
|
||||
<li id="menu_asset_move" class="btn-move-asset" data-toggle="modal" data-target="#asset_list_modal" tabindex="0"><a><i class="fa fa-cut"></i> {% trans 'Move assets to node' %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="menu_refresh_hardware_info" class="btn-refresh-hardware" tabindex="-1"><a><i class="fa fa-refresh"></i> {% trans 'Refresh node hardware info' %}</a></li>
|
||||
<li id="menu_test_connective" class="btn-test-connective" tabindex="-1"><a><i class="fa fa-chain"></i> {% trans 'Test node connective' %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="menu_refresh_assets_amount" class="btn-refresh-assets-amount" tabindex="-1"><a><i class="fa fa-refresh"></i> {% trans 'Refresh all node assets amount' %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="show_current_asset" class="btn-show-current-asset" style="display: none;" tabindex="-1"><a><i class="fa fa-hand-o-up"></i> {% trans 'Display only current node assets' %}</a></li>
|
||||
<li id="show_all_asset" class="btn-show-all-asset" style="display: none;" tabindex="-1"><a><i class="fa fa-th"></i> {% trans 'Displays all child node assets' %}</a></li>
|
||||
{# <li id="fresh_tree" class="btn-refresh-tree" tabindex="-1"><a><i class="fa fa-refresh"></i> {% trans 'Refresh' %}</a></li>#}
|
||||
</ul>
|
||||
</div>
|
||||
{% include 'assets/_node_tree.html' %}
|
||||
{% include 'assets/_asset_update_modal.html' %}
|
||||
{% include 'assets/_asset_import_modal.html' %}
|
||||
{% include 'assets/_asset_list_modal.html' %}
|
||||
|
@ -159,11 +132,11 @@
|
|||
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
var zTree, rMenu, asset_table, show = 0;
|
||||
var asset_table, show = 0;
|
||||
var update_node_action = "";
|
||||
var current_node_id = null;
|
||||
var current_node = null;
|
||||
var testDatetime = "{% trans 'Test datetime: ' %}";
|
||||
|
||||
function initTable() {
|
||||
var options = {
|
||||
ele: $('#asset_list_table'),
|
||||
|
@ -209,240 +182,25 @@ function initTable() {
|
|||
asset_table = jumpserver.initServerSideDataTable(options);
|
||||
return asset_table
|
||||
}
|
||||
|
||||
function addTreeNode() {
|
||||
hideRMenu();
|
||||
var parentNode = zTree.getSelectedNodes()[0];
|
||||
if (!parentNode){
|
||||
return
|
||||
}
|
||||
var url = "{% url 'api-assets:node-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", parentNode.meta.node.id);
|
||||
$.post(url, {}, function (data, status){
|
||||
if (status === "success") {
|
||||
var newNode = {
|
||||
id: data["key"],
|
||||
name: data["value"],
|
||||
pId: parentNode.id,
|
||||
meta: {
|
||||
"node": data
|
||||
}
|
||||
};
|
||||
newNode.checked = zTree.getSelectedNodes()[0].checked;
|
||||
zTree.addNodes(parentNode, 0, newNode);
|
||||
var node = zTree.getNodeByParam('id', newNode.id, parentNode);
|
||||
zTree.editName(node);
|
||||
} else {
|
||||
alert("{% trans 'Create node failed' %}")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function removeTreeNode() {
|
||||
hideRMenu();
|
||||
var current_node = zTree.getSelectedNodes()[0];
|
||||
if (!current_node){
|
||||
return
|
||||
}
|
||||
if (current_node.children && current_node.children.length > 0) {
|
||||
toastr.error("{% trans 'Have child node, cancel' %}");
|
||||
} else if (current_node.meta.node.assets_amount !== 0) {
|
||||
toastr.error("{% trans 'Have assets, cancel' %}");
|
||||
} else {
|
||||
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
|
||||
$.ajax({
|
||||
url: url,
|
||||
method: "DELETE",
|
||||
success: function () {
|
||||
zTree.removeNode(current_node);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function editTreeNode() {
|
||||
hideRMenu();
|
||||
var current_node = zTree.getSelectedNodes()[0];
|
||||
if (!current_node){
|
||||
return
|
||||
}
|
||||
if (current_node) {
|
||||
current_node.name = current_node.meta.node.value;
|
||||
}
|
||||
zTree.editName(current_node);
|
||||
}
|
||||
|
||||
function OnRightClick(event, treeId, treeNode) {
|
||||
if (!treeNode && event.target.tagName.toLowerCase() !== "button" && $(event.target).parents("a").length === 0) {
|
||||
zTree.cancelSelectedNode();
|
||||
showRMenu("root", event.clientX, event.clientY);
|
||||
} else if (treeNode && !treeNode.noR) {
|
||||
zTree.selectNode(treeNode);
|
||||
showRMenu("node", event.clientX, event.clientY);
|
||||
}
|
||||
}
|
||||
|
||||
function showRMenu(type, x, y) {
|
||||
$("#rMenu ul").show();
|
||||
x -= 220;
|
||||
x += document.body.scrollLeft;
|
||||
y += document.body.scrollTop+document.documentElement.scrollTop;
|
||||
rMenu.css({"top":y+"px", "left":x+"px", "visibility":"visible"});
|
||||
|
||||
$("body").bind("mousedown", onBodyMouseDown);
|
||||
}
|
||||
|
||||
function beforeClick(treeId, treeNode, clickFlag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function hideRMenu() {
|
||||
if (rMenu) rMenu.css({"visibility": "hidden"});
|
||||
$("body").unbind("mousedown", onBodyMouseDown);
|
||||
}
|
||||
|
||||
function onBodyMouseDown(event){
|
||||
if (!(event.target.id === "rMenu" || $(event.target).parents("#rMenu").length>0)) {
|
||||
rMenu.css({"visibility" : "hidden"});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function onRename(event, treeId, treeNode, isCancel){
|
||||
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
|
||||
var data = {"value": treeNode.name};
|
||||
if (isCancel){
|
||||
return
|
||||
}
|
||||
APIUpdateAttr({
|
||||
url: url,
|
||||
body: JSON.stringify(data),
|
||||
method: "PATCH",
|
||||
success_message: "{% trans 'Rename success' %}",
|
||||
fail_message: "{% trans 'Rename failed, do not change the root node name' %}",
|
||||
success: function () {
|
||||
treeNode.name = treeNode.name + ' (' + treeNode.meta.node.assets_amount + ')'
|
||||
zTree.updateNode(treeNode);
|
||||
console.log("Success: " + treeNode.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onSelected(event, treeNode) {
|
||||
current_node = treeNode;
|
||||
current_node_id = treeNode.meta.node.id;
|
||||
zTree.expandNode(current_node, true);
|
||||
var url = asset_table.ajax.url();
|
||||
url = setUrlParam(url, "node_id", current_node_id);
|
||||
url = setUrlParam(url, "show_current_asset", getCookie('show_current_asset'));
|
||||
setCookie('node_selected', treeNode.node_id);
|
||||
asset_table.ajax.url(url);
|
||||
asset_table.ajax.reload();
|
||||
}
|
||||
|
||||
function selectQueryNode() {
|
||||
// TODO: 是否应该添加
|
||||
// 暂时忽略之前选中的内容
|
||||
return
|
||||
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("node_id", node_id, null);
|
||||
if (node){
|
||||
zTree.selectNode(node[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function beforeDrag() {
|
||||
return true
|
||||
}
|
||||
|
||||
function beforeDrop(treeId, treeNodes, targetNode, moveType) {
|
||||
var treeNodesNames = [];
|
||||
$.each(treeNodes, function (index, value) {
|
||||
treeNodesNames.push(value.name);
|
||||
});
|
||||
|
||||
var msg = "你想移动节点: `" + treeNodesNames.join(",") + "` 到 `" + targetNode.name + "` 下吗?";
|
||||
return confirm(msg);
|
||||
}
|
||||
|
||||
function onDrag(event, treeId, treeNodes) {
|
||||
}
|
||||
|
||||
function onDrop(event, treeId, treeNodes, targetNode, moveType) {
|
||||
var treeNodesIds = [];
|
||||
$.each(treeNodes, function (index, value) {
|
||||
treeNodesIds.push(value.meta.node.id);
|
||||
});
|
||||
|
||||
var the_url = "{% url 'api-assets:node-add-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", targetNode.meta.node.id);
|
||||
var body = {nodes: treeNodesIds};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
method: "PUT",
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
}
|
||||
|
||||
function initTree() {
|
||||
if (zTree) {
|
||||
return
|
||||
}
|
||||
var url = '{% url 'api-assets:node-children-tree' %}?assets=0&all=';
|
||||
var showCurrentAsset = getCookie('show_current_asset');
|
||||
if (!showCurrentAsset) {
|
||||
url += '1'
|
||||
}
|
||||
var setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
async: {
|
||||
enable: true,
|
||||
url: url,
|
||||
autoParam: ["id=key", "name=n", "level=lv"],
|
||||
type: 'get'
|
||||
},
|
||||
edit: {
|
||||
enable: true,
|
||||
showRemoveBtn: false,
|
||||
showRenameBtn: false,
|
||||
drag: {
|
||||
isCopy: true,
|
||||
isMove: true
|
||||
}
|
||||
},
|
||||
callback: {
|
||||
onRightClick: OnRightClick,
|
||||
beforeClick: beforeClick,
|
||||
onRename: onRename,
|
||||
onSelected: onSelected,
|
||||
beforeDrag: beforeDrag,
|
||||
onDrag: onDrag,
|
||||
beforeDrop: beforeDrop,
|
||||
onDrop: onDrop
|
||||
}
|
||||
};
|
||||
|
||||
var zNodes = [];
|
||||
zTree = $.fn.zTree.init($("#assetTree"), setting, zNodes);
|
||||
rMenu = $("#rMenu");
|
||||
initNodeTree({
|
||||
onSelected: onNodeSelected,
|
||||
showMenu: true,
|
||||
otherMenu: `
|
||||
<li class="divider"></li>
|
||||
<li id="menu_asset_add" class="btn-add-asset" data-toggle="modal" data-target="#asset_list_modal" tabindex="0"><a><i class="fa fa-copy"></i> {% trans 'Add assets to node' %}</a></li>
|
||||
<li id="menu_asset_move" class="btn-move-asset" data-toggle="modal" data-target="#asset_list_modal" tabindex="0"><a><i class="fa fa-cut"></i> {% trans 'Move assets to node' %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="menu_refresh_hardware_info" class="btn-refresh-hardware" tabindex="-1"><a><i class="fa fa-refresh"></i> {% trans 'Refresh node hardware info' %}</a></li>
|
||||
<li id="menu_test_connective" class="btn-test-connective" tabindex="-1"><a><i class="fa fa-chain"></i> {% trans 'Test node connective' %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="show_current_asset" class="btn-show-current-asset" style="display: none;" tabindex="-1"><a><i class="fa fa-hand-o-up"></i> {% trans 'Display only current node assets' %}</a></li>
|
||||
<li id="show_all_asset" class="btn-show-all-asset" style="display: none;" tabindex="-1"><a><i class="fa fa-th"></i> {% trans 'Displays all child node assets' %}</a></li>
|
||||
`
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function toggle() {
|
||||
if (show === 0) {
|
||||
$("#split-left").hide(500, function () {
|
||||
|
@ -458,6 +216,18 @@ function toggle() {
|
|||
}
|
||||
}
|
||||
|
||||
function onNodeSelected(event, treeNode) {
|
||||
current_node = treeNode;
|
||||
current_node_id = treeNode.meta.node.id;
|
||||
zTree.expandNode(current_node, true);
|
||||
var url = asset_table.ajax.url();
|
||||
url = setUrlParam(url, "node_id", current_node_id);
|
||||
url = setUrlParam(url, "show_current_asset", getCookie('show_current_asset'));
|
||||
setCookie('node_selected', treeNode.node_id);
|
||||
asset_table.ajax.url(url);
|
||||
asset_table.ajax.reload();
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
initTable();
|
||||
initTree();
|
||||
|
@ -555,69 +325,7 @@ $(document).ready(function(){
|
|||
}
|
||||
window.open(url, '_self');
|
||||
})
|
||||
.on('click', '.btn-refresh-hardware', function () {
|
||||
var url = "{% url 'api-assets:node-refresh-hardware-info' pk=DEFAULT_PK %}";
|
||||
var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
|
||||
function success(data) {
|
||||
rMenu.css({"visibility" : "hidden"});
|
||||
var task_id = data.task;
|
||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600')
|
||||
}
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
method: "GET",
|
||||
success: success,
|
||||
flash_message: false
|
||||
});
|
||||
|
||||
})
|
||||
.on('click', '.btn-test-connective', function () {
|
||||
var url = "{% url 'api-assets:node-test-connective' pk=DEFAULT_PK %}";
|
||||
if (!current_node_id) {
|
||||
return null;
|
||||
}
|
||||
var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
|
||||
function success(data) {
|
||||
rMenu.css({"visibility" : "hidden"});
|
||||
var task_id = data.task;
|
||||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600')
|
||||
}
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
method: "GET",
|
||||
success: success,
|
||||
flash_message: false
|
||||
});
|
||||
})
|
||||
.on('click', '.btn-show-current-asset', function(){
|
||||
hideRMenu();
|
||||
$(this).css('display', 'none');
|
||||
$('#show_all_asset').css('display', 'inline-block');
|
||||
setCookie('show_current_asset', '1');
|
||||
location.reload();
|
||||
})
|
||||
.on('click', '.btn-show-all-asset', function(){
|
||||
hideRMenu();
|
||||
$(this).css('display', 'none');
|
||||
$('#show_current_asset').css('display', 'inline-block');
|
||||
setCookie('show_current_asset', '');
|
||||
location.reload();
|
||||
})
|
||||
.on('click', '.btn-test-connective', function () {
|
||||
hideRMenu();
|
||||
|
||||
})
|
||||
.on('click', '#menu_refresh_assets_amount', function () {
|
||||
hideRMenu();
|
||||
var url = "{% url 'api-assets:refresh-assets-amount' %}";
|
||||
APIUpdateAttr({
|
||||
'url': url,
|
||||
'method': 'GET'
|
||||
});
|
||||
window.location.reload();
|
||||
})
|
||||
.on('click', '.btn_asset_delete', function () {
|
||||
var $this = $(this);
|
||||
var $data_table = $("#asset_list_table").DataTable();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
#
|
||||
import time
|
||||
from django.db.models import Prefetch
|
||||
|
||||
from common.utils import get_object_or_none, get_logger
|
||||
|
@ -56,9 +57,11 @@ class NodeUtil:
|
|||
def get_all_nodes(self):
|
||||
all_nodes = Node.objects.all()
|
||||
if self.with_assets_amount:
|
||||
now = time.time()
|
||||
all_nodes = all_nodes.prefetch_related(
|
||||
Prefetch('assets', queryset=Asset.objects.all().only('id'))
|
||||
)
|
||||
all_nodes = list(all_nodes)
|
||||
for node in all_nodes:
|
||||
node._assets = set(node.assets.all())
|
||||
all_nodes = sorted(all_nodes, key=self.sorted_by)
|
||||
|
|
|
@ -130,16 +130,13 @@ def get_short_uuid_str():
|
|||
|
||||
|
||||
def is_uuid(seq):
|
||||
if isinstance(seq, str):
|
||||
if UUID_PATTERN.match(seq):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
for s in seq:
|
||||
if not is_uuid(s):
|
||||
return False
|
||||
if isinstance(seq, uuid.UUID):
|
||||
return True
|
||||
elif isinstance(seq, str) and UUID_PATTERN.match(seq):
|
||||
return True
|
||||
elif isinstance(seq, (list, tuple)):
|
||||
all([is_uuid(x) for x in seq])
|
||||
return False
|
||||
|
||||
|
||||
def get_request_ip(request):
|
||||
|
|
|
@ -399,7 +399,7 @@ REST_FRAMEWORK = {
|
|||
'ORDERING_PARAM': "order",
|
||||
'SEARCH_PARAM': "search",
|
||||
'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S %z',
|
||||
'DATETIME_INPUT_FORMATS': ['%Y-%m-%d %H:%M:%S %z'],
|
||||
'DATETIME_INPUT_FORMATS': ['iso-8601', '%Y-%m-%d %H:%M:%S %z'],
|
||||
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
|
||||
# 'PAGE_SIZE': 15
|
||||
}
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from assets.models import Node
|
||||
from orgs.utils import set_current_org, current_org
|
||||
from orgs.utils import set_current_org, current_org, get_current_org
|
||||
|
|
|
@ -4,7 +4,8 @@ import traceback
|
|||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.shortcuts import redirect, get_object_or_404
|
||||
from django.forms import ModelForm
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.http.response import HttpResponseForbidden
|
||||
from rest_framework import serializers
|
||||
from rest_framework.validators import UniqueTogetherValidator
|
||||
|
@ -101,6 +102,26 @@ class OrgModelMixin(models.Model):
|
|||
else:
|
||||
return name
|
||||
|
||||
def validate_unique(self, exclude=None):
|
||||
"""
|
||||
Check unique constraints on the model and raise ValidationError if any
|
||||
failed.
|
||||
Form 提交时会使用这个检验
|
||||
"""
|
||||
self.org_id = current_org.id if current_org.is_real() else ''
|
||||
if exclude and 'org_id' in exclude:
|
||||
exclude.remove('org_id')
|
||||
unique_checks, date_checks = self._get_unique_checks(exclude=exclude)
|
||||
|
||||
errors = self._perform_unique_checks(unique_checks)
|
||||
date_errors = self._perform_date_checks(date_checks)
|
||||
|
||||
for k, v in date_errors.items():
|
||||
errors.setdefault(k, []).extend(v)
|
||||
|
||||
if errors:
|
||||
raise ValidationError(errors)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
@ -123,11 +144,9 @@ class RootOrgViewMixin:
|
|||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class OrgModelForm(ModelForm):
|
||||
class OrgModelForm(forms.ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# if 'initial' not in kwargs:
|
||||
# return
|
||||
for name, field in self.fields.items():
|
||||
if not hasattr(field, 'queryset'):
|
||||
continue
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.db.models.signals import post_save
|
|||
from django.dispatch import receiver
|
||||
|
||||
from .models import Organization
|
||||
from .hands import set_current_org, current_org, Node
|
||||
from .hands import set_current_org, current_org, Node, get_current_org
|
||||
from perms.models import AssetPermission
|
||||
from users.models import UserGroup
|
||||
|
||||
|
@ -14,7 +14,7 @@ from users.models import UserGroup
|
|||
@receiver(post_save, sender=Organization)
|
||||
def on_org_create_or_update(sender, instance=None, created=False, **kwargs):
|
||||
if instance:
|
||||
old_org = current_org
|
||||
old_org = get_current_org()
|
||||
set_current_org(instance)
|
||||
node_root = Node.root()
|
||||
if node_root.value != instance.name:
|
||||
|
|
|
@ -20,16 +20,10 @@ from .. import serializers
|
|||
__all__ = [
|
||||
'AssetPermissionViewSet', 'AssetPermissionRemoveUserApi',
|
||||
'AssetPermissionAddUserApi', 'AssetPermissionRemoveAssetApi',
|
||||
'AssetPermissionAddAssetApi', 'ActionViewSet',
|
||||
'AssetPermissionAddAssetApi',
|
||||
]
|
||||
|
||||
|
||||
class ActionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = Action.objects.all()
|
||||
serializer_class = serializers.ActionSerializer
|
||||
permission_classes = (IsOrgAdmin,)
|
||||
|
||||
|
||||
class AssetPermissionViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
资产授权列表的增删改查api
|
||||
|
|
|
@ -14,7 +14,6 @@ from rest_framework.pagination import LimitOffsetPagination
|
|||
from common.permissions import IsValidUser, IsOrgAdminOrAppUser
|
||||
from common.tree import TreeNodeSerializer
|
||||
from common.utils import get_logger
|
||||
from orgs.utils import set_to_root_org
|
||||
from ..utils import (
|
||||
AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node,
|
||||
check_system_user_action, RemoteAppPermissionUtil,
|
||||
|
@ -515,6 +514,7 @@ class ValidateUserRemoteAppPermissionApi(APIView):
|
|||
permission_classes = (IsOrgAdminOrAppUser,)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.change_org_if_need(request, kwargs)
|
||||
user_id = request.query_params.get('user_id', '')
|
||||
remote_app_id = request.query_params.get('remote_app_id', '')
|
||||
user = get_object_or_404(User, id=user_id)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from functools import reduce
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -18,17 +19,22 @@ class AssetPermissionForm(OrgModelForm):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
users_field = self.fields.get('users')
|
||||
if hasattr(users_field, 'queryset'):
|
||||
users_field.queryset = current_org.get_org_users()
|
||||
assets_field = self.fields.get('assets')
|
||||
users_field.queryset = current_org.get_org_users()
|
||||
|
||||
# 前端渲染优化, 防止过多资产
|
||||
if not self.data:
|
||||
instance = kwargs.get('instance')
|
||||
assets_field = self.fields['assets']
|
||||
if instance:
|
||||
assets_field.queryset = instance.assets.all()
|
||||
else:
|
||||
assets_field.queryset = Asset.objects.none()
|
||||
nodes_field = self.fields['nodes']
|
||||
nodes_field._queryset = Node.get_queryset()
|
||||
|
||||
def clean_action(self):
|
||||
actions = self.cleaned_data.get("action")
|
||||
return reduce(lambda x, y: x | y, actions)
|
||||
|
||||
class Meta:
|
||||
model = AssetPermission
|
||||
|
@ -51,16 +57,14 @@ class AssetPermissionForm(OrgModelForm):
|
|||
'system_users': forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _('System user')}
|
||||
),
|
||||
'actions': forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _('Action')}
|
||||
)
|
||||
'action': forms.CheckboxSelectMultiple()
|
||||
}
|
||||
labels = {
|
||||
'nodes': _("Node"),
|
||||
}
|
||||
help_texts = {
|
||||
'actions': _('Tips: The RDP protocol does not support separate '
|
||||
'controls for uploading or downloading files')
|
||||
'action': _('Tips: The RDP protocol does not support separate '
|
||||
'controls for uploading or downloading files')
|
||||
}
|
||||
|
||||
def clean_user_groups(self):
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-02-25 10:15
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import common.utils
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0004_auto_20180125_1218'),
|
||||
('assets', '0007_auto_20180225_1815'),
|
||||
('perms', '0002_auto_20171228_0025'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='NodePermission',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('is_active', models.BooleanField(default=True, verbose_name='Active')),
|
||||
('date_expired', models.DateTimeField(default=common.utils.date_expired_default, verbose_name='Date expired')),
|
||||
('created_by', models.CharField(blank=True, max_length=128, verbose_name='Created by')),
|
||||
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
|
||||
('comment', models.TextField(blank=True, verbose_name='Comment')),
|
||||
('node', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.Node', verbose_name='Node')),
|
||||
('system_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.SystemUser', verbose_name='System user')),
|
||||
('user_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.UserGroup', verbose_name='User group')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Asset permission',
|
||||
},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='nodepermission',
|
||||
unique_together=set([('node', 'user_group', 'system_user')]),
|
||||
),
|
||||
]
|
|
@ -1,31 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-04-11 03:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0013_auto_20180411_1135'),
|
||||
('perms', '0003_auto_20180225_1815'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='assetpermission',
|
||||
name='asset_groups',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetpermission',
|
||||
name='date_start',
|
||||
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='Date start'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetpermission',
|
||||
name='nodes',
|
||||
field=models.ManyToManyField(blank=True, related_name='granted_by_permissions', to='assets.Node', verbose_name='Nodes'),
|
||||
),
|
||||
]
|
|
@ -1,49 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-04-11 03:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
def migrate_node_permissions(apps, schema_editor):
|
||||
node_perm_model = apps.get_model("perms", "NodePermission")
|
||||
asset_perm_model = apps.get_model("perms", "AssetPermission")
|
||||
db_alias = schema_editor.connection.alias
|
||||
for old in node_perm_model.objects.using(db_alias).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)
|
||||
|
||||
|
||||
def migrate_system_assets_relation(apps, schema_editor):
|
||||
system_user_model = apps.get_model("assets", "SystemUser")
|
||||
db_alias = schema_editor.connection.alias
|
||||
for s in system_user_model.objects.using(db_alias).all():
|
||||
nodes = list(s.nodes.all())
|
||||
s.nodes.set([])
|
||||
s.nodes.set(nodes)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('perms', '0004_auto_20180411_1135'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(migrate_node_permissions),
|
||||
migrations.RunPython(migrate_system_assets_relation),
|
||||
]
|
|
@ -1,27 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-06-06 07:05
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import common.utils
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('perms', '0005_migrate_data_20180411_1144'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='assetpermission',
|
||||
name='date_expired',
|
||||
field=models.DateTimeField(db_index=True, default=common.utils.date_expired_default, verbose_name='Date expired'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetpermission',
|
||||
name='date_start',
|
||||
field=models.DateTimeField(db_index=True, default=django.utils.timezone.now, verbose_name='Date start'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,45 @@
|
|||
# Generated by Django 2.1.7 on 2019-06-28 11:47
|
||||
|
||||
from django.db import migrations, models
|
||||
from functools import reduce
|
||||
|
||||
|
||||
def migrate_old_actions(apps, schema_editor):
|
||||
from orgs.utils import set_to_root_org
|
||||
from ..models import ActionFlag
|
||||
set_to_root_org()
|
||||
perm_model = apps.get_model('perms', 'AssetPermission')
|
||||
db_alias = schema_editor.connection.alias
|
||||
perms = perm_model.objects.using(db_alias).all()
|
||||
actions_map = {
|
||||
"all": ActionFlag.ALL,
|
||||
"connect": ActionFlag.CONNECT,
|
||||
"upload_file": ActionFlag.UPLOAD,
|
||||
"download_file": ActionFlag.DOWNLOAD,
|
||||
}
|
||||
|
||||
for perm in perms:
|
||||
actions = perm.actions.all()
|
||||
new_actions = [actions_map.get(action.name, ActionFlag.ALL) for action in actions]
|
||||
new_action = reduce(lambda x, y: x | y, new_actions)
|
||||
perm.action = new_action
|
||||
perm.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('perms', '0005_auto_20190521_1619'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='assetpermission',
|
||||
name='action',
|
||||
field=models.IntegerField(
|
||||
choices=[(255, 'All'), (1, 'Connect'), (2, 'Upload file'),
|
||||
(6, 'Upload download'), (4, 'Download file')],
|
||||
default=255, verbose_name='Action'),
|
||||
),
|
||||
migrations.RunPython(migrate_old_actions),
|
||||
]
|
|
@ -1,37 +0,0 @@
|
|||
# Generated by Django 2.0.7 on 2018-08-07 03:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('perms', '0006_auto_20180606_1505'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='assetpermission',
|
||||
name='org_id',
|
||||
field=models.CharField(blank=True, default=None, max_length=36, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='nodepermission',
|
||||
name='org_id',
|
||||
field=models.CharField(blank=True, default=None, max_length=36, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='assetpermission',
|
||||
name='name',
|
||||
field=models.CharField(max_length=128, verbose_name='Name'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='assetpermission',
|
||||
unique_together={('org_id', 'name')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='nodepermission',
|
||||
unique_together=set(),
|
||||
),
|
||||
|
||||
]
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 2.1.7 on 2019-06-28 12:02
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('perms', '0006_auto_20190628_1921'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='assetpermission',
|
||||
name='actions',
|
||||
),
|
||||
]
|
|
@ -1,23 +0,0 @@
|
|||
# Generated by Django 2.0.7 on 2018-08-16 08:52
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('perms', '0007_auto_20180807_1116'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='assetpermission',
|
||||
name='org_id',
|
||||
field=models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='nodepermission',
|
||||
name='org_id',
|
||||
field=models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization'),
|
||||
),
|
||||
]
|
|
@ -1,17 +0,0 @@
|
|||
# Generated by Django 2.1 on 2018-09-03 03:32
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('perms', '0008_auto_20180816_1652'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='assetpermission',
|
||||
options={'verbose_name': 'Asset permission'},
|
||||
),
|
||||
]
|
|
@ -11,7 +11,7 @@ from .base import BasePermission
|
|||
|
||||
|
||||
__all__ = [
|
||||
'Action', 'AssetPermission', 'NodePermission',
|
||||
'Action', 'AssetPermission', 'NodePermission', 'ActionFlag'
|
||||
]
|
||||
|
||||
|
||||
|
@ -33,11 +33,28 @@ class Action(models.Model):
|
|||
return cls.objects.get(name=PERMS_ACTION_NAME_ALL)
|
||||
|
||||
|
||||
class ActionFlag:
|
||||
CONNECT = 0b00000001
|
||||
UPLOAD = 0b00000010
|
||||
DOWNLOAD = 0b00000100
|
||||
UPDOWNLOAD = CONNECT | DOWNLOAD
|
||||
ALL = 0b11111111
|
||||
|
||||
CHOICES = (
|
||||
(ALL, _('All')),
|
||||
(CONNECT, _('Connect')),
|
||||
(UPLOAD, _('Upload file')),
|
||||
(UPDOWNLOAD, _("Upload download")),
|
||||
(DOWNLOAD, _('Download file')),
|
||||
)
|
||||
|
||||
|
||||
class AssetPermission(BasePermission):
|
||||
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"))
|
||||
actions = models.ManyToManyField('Action', related_name='permissions', blank=True, verbose_name=_('Action'))
|
||||
# actions = models.ManyToManyField(Action, related_name='permissions', blank=True, verbose_name=_('Action'))
|
||||
action = models.IntegerField(choices=ActionFlag.CHOICES, default=ActionFlag.ALL, verbose_name=_("Action"))
|
||||
|
||||
class Meta:
|
||||
unique_together = [('org_id', 'name')]
|
||||
|
|
|
@ -13,16 +13,10 @@ __all__ = [
|
|||
'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer',
|
||||
'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer',
|
||||
'AssetPermissionNodeSerializer', 'GrantedNodeSerializer',
|
||||
'ActionSerializer', 'NodeGrantedSerializer',
|
||||
'NodeGrantedSerializer',
|
||||
]
|
||||
|
||||
|
||||
class ActionSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Action
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class AssetPermissionCreateUpdateSerializer(BulkOrgResourceModelSerializer):
|
||||
class Meta:
|
||||
model = AssetPermission
|
||||
|
@ -35,7 +29,7 @@ class AssetPermissionListSerializer(BulkOrgResourceModelSerializer):
|
|||
assets = StringManyToManyField(many=True, read_only=True)
|
||||
nodes = StringManyToManyField(many=True, read_only=True)
|
||||
system_users = StringManyToManyField(many=True, read_only=True)
|
||||
actions = StringManyToManyField(many=True, read_only=True)
|
||||
action = serializers.IntegerField(read_only=True)
|
||||
is_valid = serializers.BooleanField()
|
||||
is_expired = serializers.BooleanField()
|
||||
|
||||
|
|
|
@ -25,13 +25,6 @@ def on_transaction_commit(func):
|
|||
@on_transaction_commit
|
||||
def on_permission_created(sender, instance=None, created=False, **kwargs):
|
||||
AssetPermissionUtil.expire_all_cache()
|
||||
actions = instance.actions.all()
|
||||
if created and not actions:
|
||||
default_action = Action.get_action_all()
|
||||
instance.actions.add(default_action)
|
||||
logger.debug(
|
||||
"Set default action to perms: {}".format(default_action, instance)
|
||||
)
|
||||
|
||||
|
||||
@receiver(post_save, sender=AssetPermission)
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
{% bootstrap_field form.system_users layout="horizontal" %}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Action' %}</h3>
|
||||
{% bootstrap_field form.actions layout="horizontal" %}
|
||||
{% bootstrap_field form.action layout="horizontal" %}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Other' %}</h3>
|
||||
<div class="form-group">
|
||||
|
@ -143,6 +143,34 @@ $(document).ready(function () {
|
|||
|
||||
$('#id_assets').val(assets).trigger('change');
|
||||
$("#asset_list_modal").modal('hide');
|
||||
});
|
||||
})
|
||||
.on("submit", "form", function (evt) {
|
||||
evt.preventDefault();
|
||||
var the_url = '{% url 'api-perms:asset-permission-list' %}';
|
||||
var redirect_to = '{% url "perms:asset-permission-list" %}';
|
||||
var method = "POST";
|
||||
var form = $("form");
|
||||
var data = form.serializeObject();
|
||||
console.log(data)
|
||||
var actions = data.action;
|
||||
var action = 0;
|
||||
for (i=0;i<actions.length;i++) {
|
||||
console.log(actions[i])
|
||||
action |= actions[i];
|
||||
}
|
||||
data.action = action;
|
||||
objectAttrsIsList(data, ['users', 'user_groups', 'system_users', 'nodes', 'assets']);
|
||||
objectAttrsIsDatetime(data, ['date_start', 'date_expired']);
|
||||
objectAttrsIsBool(data, ['is_active'])
|
||||
console.log(data)
|
||||
var props = {
|
||||
url: the_url,
|
||||
data: data,
|
||||
method: method,
|
||||
form: form,
|
||||
redirect_to: redirect_to
|
||||
};
|
||||
formSubmit(props);
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -24,15 +24,7 @@
|
|||
<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>
|
||||
{% include 'assets/_node_tree.html' %}
|
||||
</div>
|
||||
<div class="col-lg-9 animated fadeInRight" id="split-right">
|
||||
<div class="tree-toggle">
|
||||
|
@ -86,7 +78,7 @@
|
|||
<script>
|
||||
var zTree, table, show = 0;
|
||||
|
||||
function onSelected(event, treeNode) {
|
||||
function onNodeSelected(event, treeNode) {
|
||||
setCookie('node_selected', treeNode.id);
|
||||
var url = table.ajax.url();
|
||||
if (treeNode.meta.type === 'node') {
|
||||
|
@ -102,7 +94,7 @@ function onSelected(event, treeNode) {
|
|||
}
|
||||
|
||||
|
||||
function beforeAsync(treeId, treeNode) {
|
||||
function beforeNodeAsync(treeId, treeNode) {
|
||||
if (treeNode) {
|
||||
return treeNode.meta.type === 'node'
|
||||
}
|
||||
|
@ -204,28 +196,12 @@ function initTable() {
|
|||
|
||||
|
||||
function initTree() {
|
||||
var setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
async: {
|
||||
enable: true,
|
||||
url: "{% url 'api-assets:node-children-tree' %}?assets=1",
|
||||
autoParam:["id=key", "name=n", "level=lv"],
|
||||
type: 'get'
|
||||
},
|
||||
callback: {
|
||||
onSelected: onSelected,
|
||||
beforeAsync: beforeAsync
|
||||
}
|
||||
};
|
||||
zTree = $.fn.zTree.init($("#assetTree"), setting);
|
||||
initNodeTree({
|
||||
onSelected: onNodeSelected,
|
||||
beforeAsync: beforeNodeAsync,
|
||||
showMenu: false,
|
||||
showAssets: true,
|
||||
})
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
|
|
|
@ -7,7 +7,6 @@ from .. import api
|
|||
app_name = 'perms'
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register('actions', api.ActionViewSet, 'action')
|
||||
router.register('asset-permissions', api.AssetPermissionViewSet, 'asset-permission')
|
||||
router.register('remote-app-permissions', api.RemoteAppPermissionViewSet, 'remote-app-permission')
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ from collections import defaultdict
|
|||
import json
|
||||
from hashlib import md5
|
||||
import time
|
||||
import itertools
|
||||
|
||||
from django.utils import timezone
|
||||
from django.db.models import Q
|
||||
|
@ -102,11 +103,11 @@ def get_user_permissions(user, include_group=True):
|
|||
arg = Q(users=user) | Q(user_groups__in=groups)
|
||||
else:
|
||||
arg = Q(users=user)
|
||||
return AssetPermission.objects.all().valid().filter(arg)
|
||||
return AssetPermission.objects.valid().filter(arg)
|
||||
|
||||
|
||||
def get_user_group_permissions(user_group):
|
||||
return AssetPermission.objects.all().valid().filter(
|
||||
return AssetPermission.objects.valid().filter(
|
||||
user_groups=user_group
|
||||
)
|
||||
|
||||
|
@ -117,15 +118,15 @@ def get_asset_permissions(asset, include_node=True):
|
|||
arg = Q(assets=asset) | Q(nodes__in=nodes)
|
||||
else:
|
||||
arg = Q(assets=asset)
|
||||
return AssetPermission.objects.all().valid().filter(arg)
|
||||
return AssetPermission.objects.valid().filter(arg)
|
||||
|
||||
|
||||
def get_node_permissions(node):
|
||||
return AssetPermission.objects.all().valid().filter(nodes=node)
|
||||
return AssetPermission.objects.valid().filter(nodes=node)
|
||||
|
||||
|
||||
def get_system_user_permissions(system_user):
|
||||
return AssetPermission.objects.valid().all().filter(
|
||||
return AssetPermission.objects.valid().filter(
|
||||
system_users=system_user
|
||||
)
|
||||
|
||||
|
@ -141,11 +142,6 @@ def timeit(func):
|
|||
return wrapper
|
||||
|
||||
|
||||
class AssetGranted:
|
||||
def __init__(self):
|
||||
self.system_users = {}
|
||||
|
||||
|
||||
class AssetPermissionCacheMixin:
|
||||
CACHE_KEY_PREFIX = '_ASSET_PERM_CACHE_'
|
||||
CACHE_META_KEY_PREFIX = '_ASSET_PERM_META_KEY_'
|
||||
|
@ -286,6 +282,38 @@ class AssetPermissionCacheMixin:
|
|||
cache.delete_pattern(key)
|
||||
|
||||
|
||||
class FlatPermissionQueryset:
|
||||
def __init__(self):
|
||||
self.queryset = defaultdict(list)
|
||||
|
||||
def add(self, permission):
|
||||
self.queryset[permission.id].append(permission)
|
||||
|
||||
def add_many(self, assets_or_nodes, system_users, actions):
|
||||
if any([assets_or_nodes, system_users, actions]):
|
||||
return
|
||||
|
||||
iterable = itertools.product(assets_or_nodes, system_users, actions)
|
||||
for source, sysuser, action in iterable:
|
||||
permission = FlatPermission(source, sysuser, action)
|
||||
self.add(permission)
|
||||
|
||||
def clean(self):
|
||||
pass
|
||||
|
||||
|
||||
class FlatPermission:
|
||||
def __init__(self, asset_or_node, system_user, action):
|
||||
self.id = asset_or_node.id
|
||||
self.source = asset_or_node
|
||||
self.system_user = system_user
|
||||
self.action = action
|
||||
|
||||
def __eq__(self, other):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class AssetPermissionUtil(AssetPermissionCacheMixin):
|
||||
get_permissions_map = {
|
||||
"User": get_user_permissions,
|
||||
|
@ -344,19 +372,15 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
|
|||
def get_nodes_direct(self):
|
||||
"""
|
||||
返回用户/组授权规则直接关联的节点
|
||||
:return: {asset1: {system_user1: {'actions': set()},}}
|
||||
:return: {node1: {system_user1: {'actions': set()},}}
|
||||
"""
|
||||
nodes = defaultdict(dict)
|
||||
permissions = self.permissions.prefetch_related('nodes', 'system_users', 'actions')
|
||||
nodes = FlatPermissionQueryset()
|
||||
permissions = self.permissions
|
||||
for perm in permissions:
|
||||
actions = perm.actions.all()
|
||||
for node in perm.nodes.all():
|
||||
system_users = perm.system_users.all()
|
||||
system_users = self._structured_system_user(system_users, actions)
|
||||
nodes[node].update(system_users)
|
||||
self.tree.add_nodes(nodes.keys())
|
||||
# 替换成优化过的node
|
||||
nodes = {self.tree.node_util.get_node_by_key(k.key): v for k, v in nodes.items()}
|
||||
system_users = perm.system_users.all()
|
||||
_nodes = perm.nodes.all()
|
||||
nodes.add_many(_nodes, system_users, actions)
|
||||
return nodes
|
||||
|
||||
@timeit
|
||||
|
@ -385,24 +409,18 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
|
|||
assets = self.get_assets_direct()
|
||||
nodes = self.get_nodes_direct()
|
||||
# for node, system_users in nodes.items():
|
||||
# print(9999, node)
|
||||
# _assets = node.get_all_valid_assets()
|
||||
# print(".......... end .......")
|
||||
# print(">>>>> Node<<<<<<<<<<<<: ", node.value)
|
||||
# _assets = list(node.get_all_valid_assets())
|
||||
# for asset in _assets:
|
||||
# print(">>asset")
|
||||
# for system_user, attr_dict in system_users.items():
|
||||
# print(">>>system user")
|
||||
# if not asset.has_protocol(system_user.protocol):
|
||||
# continue
|
||||
# if system_user in assets[asset]:
|
||||
# actions = assets[asset][system_user]['actions']
|
||||
# attr_dict['actions'].update(actions)
|
||||
# system_users.update({system_user: attr_dict})
|
||||
# print("<<<system user")
|
||||
# print("<<<asset")
|
||||
# assets[asset].update(system_users)
|
||||
# print(">>>>>>")
|
||||
#
|
||||
|
||||
__assets = defaultdict(set)
|
||||
for asset, system_users in assets.items():
|
||||
for system_user, attr_dict in system_users.items():
|
||||
|
@ -507,8 +525,7 @@ def parse_asset_to_tree_node(node, asset, system_users):
|
|||
'id': asset.id,
|
||||
'hostname': asset.hostname,
|
||||
'ip': asset.ip,
|
||||
'protocols': [{"name": p.name, "port": p.port}
|
||||
for p in asset.protocols.all()],
|
||||
'protocols': [str(p) for p in asset.protocols.all()],
|
||||
'platform': asset.platform,
|
||||
'domain': None if not asset.domain else asset.domain.id,
|
||||
'is_active': asset.is_active,
|
||||
|
|
|
@ -58,8 +58,6 @@ class AssetPermissionCreateView(PermissionsMixin, CreateView):
|
|||
assets_id = assets_id.split(",")
|
||||
assets = Asset.objects.filter(id__in=assets_id)
|
||||
form['assets'].initial = assets
|
||||
form['actions'].initial = Action.objects.get(name=PERMS_ACTION_NAME_ALL)
|
||||
|
||||
return form
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
|
|
@ -277,7 +277,7 @@ function APIUpdateAttr(props) {
|
|||
}).done(function(data, textStatue, jqXHR) {
|
||||
if (flash_message) {
|
||||
var msg = "";
|
||||
if (user_fail_message) {
|
||||
if (user_success_message) {
|
||||
msg = user_success_message;
|
||||
} else {
|
||||
msg = default_success_message;
|
||||
|
@ -635,7 +635,7 @@ jumpserver.initServerSideDataTable = function (options) {
|
|||
columns: options.columns || [],
|
||||
select: options.select || select,
|
||||
language: jumpserver.language,
|
||||
lengthMenu: [[15, 25, 50, 9999], [15, 25, 50, 'All']]
|
||||
lengthMenu: options.lengthMenu || [[15, 25, 50, 9999], [15, 25, 50, 'All']]
|
||||
});
|
||||
table.selected = [];
|
||||
table.selected_rows = [];
|
||||
|
@ -1072,3 +1072,27 @@ function htmlEscape ( d ) {
|
|||
d.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"') :
|
||||
d;
|
||||
}
|
||||
|
||||
function objectAttrsIsList(obj, attrs) {
|
||||
attrs.forEach(function (attr) {
|
||||
if (obj[attr] && !(obj[attr] instanceof Array)){
|
||||
obj[attr] = [obj[attr]]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function objectAttrsIsDatetime(obj, attrs) {
|
||||
attrs.forEach(function (attr) {
|
||||
obj[attr] = new Date(obj[attr]).toISOString();
|
||||
})
|
||||
}
|
||||
|
||||
function objectAttrsIsBool(obj, attrs) {
|
||||
attrs.forEach(function (attr) {
|
||||
if (!obj[attr]) {
|
||||
obj[attr] = false
|
||||
} else if (['on', '1'].includes(obj[attr])) {
|
||||
obj[attr] = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue