Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
b81c52ae
Commit
b81c52ae
authored
Aug 14, 2019
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Update] 优化节点
parent
a315df29
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
244 additions
and
110 deletions
+244
-110
asset.py
apps/assets/api/asset.py
+8
-6
node.py
apps/assets/api/node.py
+37
-23
asset.py
apps/assets/forms/asset.py
+20
-4
node.py
apps/assets/models/node.py
+0
-0
node.py
apps/assets/serializers/node.py
+10
-3
signals_handler.py
apps/assets/signals_handler.py
+2
-1
_node_tree.html
apps/assets/templates/assets/_node_tree.html
+3
-2
asset_create.html
apps/assets/templates/assets/asset_create.html
+21
-0
utils.py
apps/assets/utils.py
+107
-56
settings.py
apps/jumpserver/settings.py
+4
-4
asset_permission.py
apps/perms/forms/asset_permission.py
+11
-11
asset_permission_create_update.html
...perms/templates/perms/asset_permission_create_update.html
+21
-0
No files found.
apps/assets/api/asset.py
View file @
b81c52ae
...
@@ -73,19 +73,21 @@ class AssetViewSet(LabelFilter, OrgBulkModelViewSet):
...
@@ -73,19 +73,21 @@ class AssetViewSet(LabelFilter, OrgBulkModelViewSet):
node
=
get_object_or_404
(
Node
,
id
=
node_id
)
node
=
get_object_or_404
(
Node
,
id
=
node_id
)
show_current_asset
=
self
.
request
.
query_params
.
get
(
"show_current_asset"
)
in
(
'1'
,
'true'
)
show_current_asset
=
self
.
request
.
query_params
.
get
(
"show_current_asset"
)
in
(
'1'
,
'true'
)
# 当前节点是顶层节点, 并且仅显示直接资产
if
node
.
is_root
()
and
show_current_asset
:
if
node
.
is_root
()
and
show_current_asset
:
queryset
=
queryset
.
filter
(
queryset
=
queryset
.
filter
(
Q
(
nodes
=
node_id
)
|
Q
(
nodes__isnull
=
True
)
Q
(
nodes
=
node_id
)
|
Q
(
nodes__isnull
=
True
)
)
)
.
distinct
()
# 当前节点是顶层节点,显示所有资产
elif
node
.
is_root
()
and
not
show_current_asset
:
elif
node
.
is_root
()
and
not
show_current_asset
:
pass
return
queryset
# 当前节点不是鼎城节点,只显示直接资产
elif
not
node
.
is_root
()
and
show_current_asset
:
elif
not
node
.
is_root
()
and
show_current_asset
:
queryset
=
queryset
.
filter
(
nodes
=
node
)
queryset
=
queryset
.
filter
(
nodes
=
node
)
else
:
else
:
queryset
=
queryset
.
filter
(
children
=
node
.
get_all_children
(
with_self
=
True
)
nodes__key__regex
=
'^{}(:[0-9]+)*$'
.
format
(
node
.
key
),
queryset
=
queryset
.
filter
(
nodes__in
=
children
)
.
distinct
()
)
return
queryset
return
queryset
.
distinct
()
def
filter_admin_user_id
(
self
,
queryset
):
def
filter_admin_user_id
(
self
,
queryset
):
admin_user_id
=
self
.
request
.
query_params
.
get
(
'admin_user_id'
)
admin_user_id
=
self
.
request
.
query_params
.
get
(
'admin_user_id'
)
...
...
apps/assets/api/node.py
View file @
b81c52ae
...
@@ -13,8 +13,11 @@
...
@@ -13,8 +13,11 @@
# See the License for the specific language governing permissions and
# See the License for the specific language governing permissions and
# limitations under the License.
# limitations under the License.
from
rest_framework
import
generics
,
mixins
,
viewsets
import
time
from
rest_framework
import
generics
,
mixins
from
rest_framework.serializers
import
ValidationError
from
rest_framework.serializers
import
ValidationError
from
rest_framework.pagination
import
LimitOffsetPagination
from
rest_framework.views
import
APIView
from
rest_framework.views
import
APIView
from
rest_framework.response
import
Response
from
rest_framework.response
import
Response
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
...
@@ -22,6 +25,7 @@ from django.shortcuts import get_object_or_404
...
@@ -22,6 +25,7 @@ from django.shortcuts import get_object_or_404
from
common.utils
import
get_logger
,
get_object_or_none
from
common.utils
import
get_logger
,
get_object_or_none
from
common.tree
import
TreeNodeSerializer
from
common.tree
import
TreeNodeSerializer
from
orgs.mixins
import
OrgModelViewSet
from
..hands
import
IsOrgAdmin
from
..hands
import
IsOrgAdmin
from
..models
import
Node
from
..models
import
Node
from
..tasks
import
update_assets_hardware_info_util
,
test_asset_connectivity_util
from
..tasks
import
update_assets_hardware_info_util
,
test_asset_connectivity_util
...
@@ -39,29 +43,26 @@ __all__ = [
...
@@ -39,29 +43,26 @@ __all__ = [
]
]
class
NodeViewSet
(
viewsets
.
ModelViewSet
):
class
NodeViewSet
(
Org
ModelViewSet
):
filter_fields
=
(
'value'
,
'key'
,
)
filter_fields
=
(
'value'
,
'key'
,
'id'
)
search_fields
=
filter_fields
search_fields
=
(
'value'
,
)
queryset
=
Node
.
objects
.
all
()
queryset
=
Node
.
objects
.
all
()
permission_classes
=
(
IsOrgAdmin
,)
permission_classes
=
(
IsOrgAdmin
,)
serializer_class
=
serializers
.
NodeSerializer
serializer_class
=
serializers
.
NodeSerializer
pagination_class
=
LimitOffsetPagination
# 仅支持根节点指直接创建,子节点下的节点需要通过children接口创建
def
perform_create
(
self
,
serializer
):
def
perform_create
(
self
,
serializer
):
child_key
=
Node
.
root
()
.
get_next_child_key
()
child_key
=
Node
.
root
()
.
get_next_child_key
()
serializer
.
validated_data
[
"key"
]
=
child_key
serializer
.
validated_data
[
"key"
]
=
child_key
serializer
.
save
()
serializer
.
save
()
def
update
(
self
,
request
,
*
args
,
**
kwargs
):
def
perform_update
(
self
,
serializer
):
node
=
self
.
get_object
()
node
=
self
.
get_object
()
if
node
.
is_root
():
if
node
.
is_root
()
and
node
.
value
!=
serializer
.
validated_data
[
'value'
]:
node_value
=
node
.
value
msg
=
_
(
"You can't update the root node name"
)
post_value
=
request
.
data
.
get
(
'value'
)
raise
ValidationError
({
"error"
:
msg
})
if
node_value
!=
post_value
:
return
super
()
.
perform_update
(
serializer
)
return
Response
(
{
"msg"
:
_
(
"You can't update the root node name"
)},
status
=
400
)
return
super
()
.
update
(
request
,
*
args
,
**
kwargs
)
class
NodeListAsTreeApi
(
generics
.
ListAPIView
):
class
NodeListAsTreeApi
(
generics
.
ListAPIView
):
...
@@ -79,17 +80,19 @@ class NodeListAsTreeApi(generics.ListAPIView):
...
@@ -79,17 +80,19 @@ class NodeListAsTreeApi(generics.ListAPIView):
permission_classes
=
(
IsOrgAdmin
,)
permission_classes
=
(
IsOrgAdmin
,)
serializer_class
=
TreeNodeSerializer
serializer_class
=
TreeNodeSerializer
def
get_queryset
(
self
):
def
to_tree_queryset
(
self
,
queryset
):
queryset
=
Node
.
objects
.
all
()
util
=
NodeUtil
()
util
=
NodeUtil
()
nodes
=
util
.
get_nodes_by_queryset
(
queryset
)
nodes
=
util
.
get_nodes_by_queryset
(
queryset
)
queryset
=
[
node
.
as_tree_node
()
for
node
in
nodes
]
queryset
=
[
node
.
as_tree_node
()
for
node
in
nodes
]
return
queryset
return
queryset
@staticmethod
def
get_queryset
(
self
):
def
refresh_nodes
(
queryset
):
queryset
=
Node
.
objects
.
all
()
Node
.
expire_nodes_assets_amount
()
return
queryset
Node
.
expire_nodes_full_value
()
def
filter_queryset
(
self
,
queryset
):
queryset
=
super
()
.
filter_queryset
(
queryset
)
queryset
=
self
.
to_tree_queryset
(
queryset
)
return
queryset
return
queryset
...
@@ -112,18 +115,28 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
...
@@ -112,18 +115,28 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
is_root
=
False
is_root
=
False
def
get_queryset
(
self
):
def
get_queryset
(
self
):
t1
=
time
.
time
()
self
.
check_need_refresh_nodes
()
self
.
check_need_refresh_nodes
()
t2
=
time
.
time
()
print
(
"1: "
,
t2
-
t1
)
node_key
=
self
.
request
.
query_params
.
get
(
'key'
)
node_key
=
self
.
request
.
query_params
.
get
(
'key'
)
util
=
NodeUtil
()
#
util = NodeUtil()
# 是否包含自己
# 是否包含自己
with_self
=
False
with_self
=
False
if
not
node_key
:
if
not
node_key
:
node_key
=
Node
.
root
()
.
key
node_key
=
Node
.
root
()
.
key
with_self
=
True
with_self
=
True
self
.
node
=
util
.
get_node_by_key
(
node_key
)
# self.node = util.get_node_by_key(node_key)
self
.
node
=
get_object_or_404
(
Node
,
key
=
node_key
)
t3
=
time
.
time
()
print
(
"2: "
,
t3
-
t2
)
queryset
=
self
.
node
.
get_children
(
with_self
=
with_self
)
queryset
=
self
.
node
.
get_children
(
with_self
=
with_self
)
t4
=
time
.
time
()
queryset
=
[
node
.
as_tree_node
()
for
node
in
queryset
]
queryset
=
[
node
.
as_tree_node
()
for
node
in
queryset
]
print
(
"3: "
,
t4
-
t3
)
t5
=
time
.
time
()
queryset
=
sorted
(
queryset
)
queryset
=
sorted
(
queryset
)
print
(
"4: "
,
t5
-
t4
)
return
queryset
return
queryset
def
filter_assets
(
self
,
queryset
):
def
filter_assets
(
self
,
queryset
):
...
@@ -131,7 +144,8 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
...
@@ -131,7 +144,8 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
if
not
include_assets
:
if
not
include_assets
:
return
queryset
return
queryset
assets
=
self
.
node
.
get_assets
()
.
only
(
assets
=
self
.
node
.
get_assets
()
.
only
(
"id"
,
"hostname"
,
"ip"
,
'platform'
,
"os"
,
"org_id"
,
"protocols"
,
"id"
,
"hostname"
,
"ip"
,
'platform'
,
"os"
,
"org_id"
,
"protocols"
,
)
)
for
asset
in
assets
:
for
asset
in
assets
:
queryset
.
append
(
asset
.
as_tree_node
(
self
.
node
))
queryset
.
append
(
asset
.
as_tree_node
(
self
.
node
))
...
...
apps/assets/forms/asset.py
View file @
b81c52ae
...
@@ -29,9 +29,14 @@ class ProtocolForm(forms.Form):
...
@@ -29,9 +29,14 @@ class ProtocolForm(forms.Form):
class
AssetCreateForm
(
OrgModelForm
):
class
AssetCreateForm
(
OrgModelForm
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
super
()
.
__init__
(
*
args
,
**
kwargs
)
if
self
.
data
:
return
nodes_field
=
self
.
fields
[
'nodes'
]
nodes_field
=
self
.
fields
[
'nodes'
]
nodes_field
.
choices
=
((
n
.
id
,
n
.
full_value
)
for
n
in
if
self
.
instance
:
Node
.
get_queryset
())
nodes_field
.
choices
=
((
n
.
id
,
n
.
full_value
)
for
n
in
self
.
instance
.
nodes
.
all
())
else
:
nodes_field
.
choices
=
[]
class
Meta
:
class
Meta
:
model
=
Asset
model
=
Asset
...
@@ -42,7 +47,7 @@ class AssetCreateForm(OrgModelForm):
...
@@ -42,7 +47,7 @@ class AssetCreateForm(OrgModelForm):
]
]
widgets
=
{
widgets
=
{
'nodes'
:
forms
.
SelectMultiple
(
attrs
=
{
'nodes'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Nodes'
)
'class'
:
'
nodes-
select2'
,
'data-placeholder'
:
_
(
'Nodes'
)
}),
}),
'admin_user'
:
forms
.
Select
(
attrs
=
{
'admin_user'
:
forms
.
Select
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Admin user'
)
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Admin user'
)
...
@@ -68,6 +73,17 @@ class AssetCreateForm(OrgModelForm):
...
@@ -68,6 +73,17 @@ class AssetCreateForm(OrgModelForm):
class
AssetUpdateForm
(
OrgModelForm
):
class
AssetUpdateForm
(
OrgModelForm
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
if
self
.
data
:
return
nodes_field
=
self
.
fields
[
'nodes'
]
if
self
.
instance
:
nodes_field
.
choices
=
((
n
.
id
,
n
.
full_value
)
for
n
in
self
.
instance
.
nodes
.
all
())
else
:
nodes_field
.
choices
=
[]
class
Meta
:
class
Meta
:
model
=
Asset
model
=
Asset
fields
=
[
fields
=
[
...
@@ -77,7 +93,7 @@ class AssetUpdateForm(OrgModelForm):
...
@@ -77,7 +93,7 @@ class AssetUpdateForm(OrgModelForm):
]
]
widgets
=
{
widgets
=
{
'nodes'
:
forms
.
SelectMultiple
(
attrs
=
{
'nodes'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Node'
)
'class'
:
'
nodes-
select2'
,
'data-placeholder'
:
_
(
'Node'
)
}),
}),
'admin_user'
:
forms
.
Select
(
attrs
=
{
'admin_user'
:
forms
.
Select
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Admin user'
)
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Admin user'
)
...
...
apps/assets/models/node.py
View file @
b81c52ae
This diff is collapsed.
Click to expand it.
apps/assets/serializers/node.py
View file @
b81c52ae
...
@@ -13,17 +13,24 @@ __all__ = [
...
@@ -13,17 +13,24 @@ __all__ = [
class
NodeSerializer
(
BulkOrgResourceModelSerializer
):
class
NodeSerializer
(
BulkOrgResourceModelSerializer
):
assets_amount
=
serializers
.
IntegerField
(
read_only
=
True
)
name
=
serializers
.
ReadOnlyField
(
source
=
'value'
)
name
=
serializers
.
ReadOnlyField
(
source
=
'value'
)
full_value
=
serializers
.
SerializerMethodField
(
label
=
_
(
"Full value"
))
class
Meta
:
class
Meta
:
model
=
Node
model
=
Node
only_fields
=
[
'id'
,
'key'
,
'value'
,
'org_id'
]
only_fields
=
[
'id'
,
'key'
,
'value'
,
'org_id'
]
fields
=
only_fields
+
[
'name'
,
'
assets_amount
'
]
fields
=
only_fields
+
[
'name'
,
'
full_value
'
]
read_only_fields
=
[
read_only_fields
=
[
'key'
,
'name'
,
'
assets_amount
'
,
'org_id'
,
'key'
,
'name'
,
'
full_value
'
,
'org_id'
,
]
]
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
self
.
tree
=
Node
.
tree
()
def
get_full_value
(
self
,
obj
):
return
self
.
tree
.
get_node_full_tag
(
obj
.
key
)
def
validate_value
(
self
,
data
):
def
validate_value
(
self
,
data
):
instance
=
self
.
instance
if
self
.
instance
else
Node
.
root
()
instance
=
self
.
instance
if
self
.
instance
else
Node
.
root
()
children
=
instance
.
parent
.
get_children
()
children
=
instance
.
parent
.
get_children
()
...
...
apps/assets/signals_handler.py
View file @
b81c52ae
...
@@ -112,7 +112,8 @@ def on_node_assets_changed(sender, instance=None, **kwargs):
...
@@ -112,7 +112,8 @@ def on_node_assets_changed(sender, instance=None, **kwargs):
@receiver
(
post_save
,
sender
=
Node
)
@receiver
(
post_save
,
sender
=
Node
)
def
on_node_update_or_created
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
def
on_node_update_or_created
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
instance
and
not
created
:
if
instance
and
not
created
:
instance
.
expire_full_value
()
pass
# instance.expire_full_value()
@receiver
(
post_save
,
sender
=
AuthBook
)
@receiver
(
post_save
,
sender
=
AuthBook
)
...
...
apps/assets/templates/assets/_node_tree.html
View file @
b81c52ae
...
@@ -236,7 +236,8 @@ function onBodyMouseDown(event){
...
@@ -236,7 +236,8 @@ function onBodyMouseDown(event){
}
}
function
onRename
(
event
,
treeId
,
treeNode
,
isCancel
){
function
onRename
(
event
,
treeId
,
treeNode
,
isCancel
){
var
url
=
"{% url 'api-assets:node-detail' pk=DEFAULT_PK %}"
.
replace
(
"{{ DEFAULT_PK }}"
,
current_node_id
);
var
url
=
"{% url 'api-assets:node-detail' pk=DEFAULT_PK %}"
.
replace
(
"{{ DEFAULT_PK }}"
,
current_node_id
);
var
data
=
{
"value"
:
treeNode
.
name
};
var
data
=
{
"value"
:
treeNode
.
name
};
if
(
isCancel
){
if
(
isCancel
){
return
return
...
@@ -250,7 +251,7 @@ function onRename(event, treeId, treeNode, isCancel){
...
@@ -250,7 +251,7 @@ function onRename(event, treeId, treeNode, isCancel){
treeNode
.
name
=
treeNode
.
name
+
' ('
+
treeNode
.
meta
.
node
.
assets_amount
+
')'
;
treeNode
.
name
=
treeNode
.
name
+
' ('
+
treeNode
.
meta
.
node
.
assets_amount
+
')'
;
zTree
.
updateNode
(
treeNode
);
zTree
.
updateNode
(
treeNode
);
console
.
log
(
"Success: "
+
treeNode
.
name
)
console
.
log
(
"Success: "
+
treeNode
.
name
)
}
}
,
})
})
}
}
...
...
apps/assets/templates/assets/asset_create.html
View file @
b81c52ae
...
@@ -110,6 +110,27 @@ $(document).ready(function () {
...
@@ -110,6 +110,27 @@ $(document).ready(function () {
$
(
'.select2'
).
select2
({
$
(
'.select2'
).
select2
({
allowClear
:
true
allowClear
:
true
});
});
$
(
".nodes-select2"
).
select2
({
closeOnSelect
:
false
,
ajax
:
{
url
:
'{% url "api-assets:node-list" %}'
,
data
:
function
(
params
)
{
var
page
=
params
.
page
||
1
;
var
query
=
{
search
:
params
.
term
,
offset
:
(
page
-
1
)
*
10
,
limit
:
10
};
return
query
},
processResults
:
function
(
data
)
{
var
results
=
$
.
map
(
data
.
results
,
function
(
v
,
i
)
{
return
{
id
:
v
.
id
,
text
:
v
.
full_value
}
});
return
{
results
:
results
,
pagination
:
{
"more"
:
true
}}
}
},
});
$
(
".labels"
).
select2
({
$
(
".labels"
).
select2
({
allowClear
:
true
,
allowClear
:
true
,
templateSelection
:
format
templateSelection
:
format
...
...
apps/assets/utils.py
View file @
b81c52ae
# ~*~ coding: utf-8 ~*~
# ~*~ coding: utf-8 ~*~
#
#
import
time
from
functools
import
reduce
from
functools
import
reduce
from
treelib
import
Tree
from
django.db.models
import
Prefetch
,
Q
from
django.db.models
import
Prefetch
,
Q
from
common.utils
import
get_object_or_none
,
get_logger
from
common.utils
import
get_object_or_none
,
get_logger
,
timeit
from
common.struct
import
Stack
from
common.struct
import
Stack
from
.models
import
SystemUser
,
Label
,
Node
,
Asset
from
.models
import
SystemUser
,
Label
,
Node
,
Asset
...
@@ -54,10 +54,12 @@ class LabelFilter(LabelFilterMixin):
...
@@ -54,10 +54,12 @@ class LabelFilter(LabelFilterMixin):
class
NodeUtil
:
class
NodeUtil
:
full_value_sep
=
' / '
def
__init__
(
self
,
with_assets_amount
=
False
,
debug
=
False
):
def
__init__
(
self
,
with_assets_amount
=
False
,
debug
=
False
):
self
.
stack
=
Stack
()
self
.
stack
=
Stack
()
self
.
_nodes
=
{}
self
.
with_assets_amount
=
with_assets_amount
self
.
with_assets_amount
=
with_assets_amount
self
.
_nodes
=
{}
self
.
_debug
=
debug
self
.
_debug
=
debug
self
.
init
()
self
.
init
()
...
@@ -65,62 +67,85 @@ class NodeUtil:
...
@@ -65,62 +67,85 @@ class NodeUtil:
def
sorted_by
(
node
):
def
sorted_by
(
node
):
return
[
int
(
i
)
for
i
in
node
.
key
.
split
(
':'
)]
return
[
int
(
i
)
for
i
in
node
.
key
.
split
(
':'
)]
@timeit
def
get_queryset
(
self
):
def
get_queryset
(
self
):
all_nodes
=
Node
.
objects
.
all
(
)
queryset
=
Node
.
objects
.
all
()
.
only
(
'id'
,
'key'
,
'value'
)
if
self
.
with_assets_amount
:
if
self
.
with_assets_amount
:
all_nodes
=
all_nodes
.
prefetch_related
(
queryset
=
queryset
.
prefetch_related
(
Prefetch
(
'assets'
,
queryset
=
Asset
.
objects
.
all
()
.
only
(
'id'
))
Prefetch
(
'assets'
,
queryset
=
Asset
.
objects
.
all
()
.
only
(
'id'
)
)
))
all_nodes
=
list
(
all_nodes
)
return
list
(
queryset
)
for
node
in
all_nodes
:
node
.
_assets
=
set
(
node
.
assets
.
all
())
return
all_nodes
def
get_all_nodes
(
self
):
@staticmethod
all_nodes
=
sorted
(
self
.
get_queryset
(),
key
=
self
.
sorted_by
)
def
set_node_default_attr
(
node
):
setattr
(
node
,
'_full_value'
,
node
.
value
)
setattr
(
node
,
'_children'
,
[])
setattr
(
node
,
'_all_children'
,
[])
setattr
(
node
,
'_parents'
,
[])
guarder
=
Node
(
key
=
''
,
value
=
'Guarder'
)
@timeit
guarder
.
_assets
=
[]
def
get_all_nodes
(
self
):
all_nodes
.
append
(
guarder
)
queryset
=
sorted
(
list
(
self
.
get_queryset
()),
key
=
self
.
sorted_by
)
return
all_nodes
guarder
=
Node
(
key
=
''
,
value
=
'ROOT'
)
self
.
set_node_default_attr
(
guarder
)
queryset
.
append
(
guarder
)
for
node
in
queryset
[:
-
1
]:
self
.
set_node_default_attr
(
node
)
if
not
self
.
with_assets_amount
:
continue
assets
=
set
([
str
(
a
.
id
)
for
a
in
node
.
assets
.
all
()])
node
.
_assets
=
assets
node
.
_all_assets
=
assets
return
queryset
def
push_to_stack
(
self
,
node
):
def
push_to_stack
(
self
,
node
):
# 入栈之前检查
# 入栈之前检查
# 如果栈是空的,证明是一颗树的根部
# 如果栈是空的,证明是一颗树的根部
if
self
.
stack
.
is_empty
():
if
self
.
stack
.
is_empty
():
node
.
_full_value
=
node
.
value
node
.
_full_value
=
node
.
value
node
.
_parents
=
[]
else
:
else
:
# 如果不是根节点,
# 如果不是根节点,
# 该节点的祖先应该是父节点的祖先加上父节点
# 该节点的祖先应该是父节点的祖先加上父节点
# 该节点的名字是父节点的名字+自己的名字
# 该节点的名字是父节点的名字+自己的名字
node
.
_parents
=
[
self
.
stack
.
top
]
+
self
.
stack
.
top
.
_parents
node
.
_parents
=
[
self
.
stack
.
top
]
+
getattr
(
self
.
stack
.
top
,
'_parents'
)
node
.
_full_value
=
' / '
.
join
(
node
.
_full_value
=
self
.
full_value_sep
.
join
(
[
self
.
stack
.
top
.
_full_value
,
node
.
value
]
[
getattr
(
self
.
stack
.
top
,
'_full_value'
,
''
)
,
node
.
value
]
)
)
node
.
_children
=
[]
# self.debug("入栈: {}".format(node.key))
node
.
_all_children
=
[]
self
.
debug
(
"入栈: {}"
.
format
(
node
.
key
))
self
.
stack
.
push
(
node
)
self
.
stack
.
push
(
node
)
# 出栈
# 出栈
# @timeit
def
pop_from_stack
(
self
):
def
pop_from_stack
(
self
):
_node
=
self
.
stack
.
pop
()
_node
=
self
.
stack
.
pop
()
self
.
debug
(
"出栈: {} 栈顶: {}"
.
format
(
_node
.
key
,
self
.
stack
.
top
.
key
if
self
.
stack
.
top
else
None
))
# self.debug("出栈: {} 栈顶: {}".format(
# _node.key, self.stack.top.key if self.stack.top else None)
# )
self
.
_nodes
[
_node
.
key
]
=
_node
self
.
_nodes
[
_node
.
key
]
=
_node
if
not
self
.
stack
.
top
:
if
not
self
.
stack
.
top
:
return
return
if
self
.
with_assets_amount
:
parent
=
self
.
stack
.
top
self
.
stack
.
top
.
_assets
.
update
(
_node
.
_assets
)
parent_children
=
getattr
(
parent
,
'_children'
)
_node
.
_assets_amount
=
len
(
_node
.
_assets
)
parent_all_children
=
getattr
(
parent
,
'_all_children'
)
delattr
(
_node
,
'_assets'
)
node_all_children
=
getattr
(
_node
,
'_all_children'
)
self
.
stack
.
top
.
_children
.
append
(
_node
)
parent_children
.
append
(
_node
)
self
.
stack
.
top
.
_all_children
.
extend
([
_node
]
+
_node
.
_all_children
)
parent_all_children
.
extend
([
_node
]
+
node_all_children
)
if
not
self
.
with_assets_amount
:
return
node_all_assets
=
getattr
(
_node
,
'_all_assets'
)
parent_all_assets
=
getattr
(
parent
,
'_all_assets'
)
_node
.
_assets_amount
=
len
(
node_all_assets
)
parent_all_assets
.
update
(
node_all_assets
)
@timeit
def
init
(
self
):
def
init
(
self
):
all_nodes
=
self
.
get_all_nodes
()
all_nodes
=
self
.
get_all_nodes
()
for
node
in
all_nodes
:
for
node
in
all_nodes
:
self
.
debug
(
"准备: {} 栈顶: {}"
.
format
(
node
.
key
,
self
.
stack
.
top
.
key
if
self
.
stack
.
top
else
None
))
self
.
debug
(
"准备: {} 栈顶: {}"
.
format
(
node
.
key
,
self
.
stack
.
top
.
key
if
self
.
stack
.
top
else
None
)
)
# 入栈之前检查,该节点是不是栈顶节点的子节点
# 入栈之前检查,该节点是不是栈顶节点的子节点
# 如果不是,则栈顶出栈
# 如果不是,则栈顶出栈
while
self
.
stack
.
top
and
not
self
.
stack
.
top
.
is_children
(
node
):
while
self
.
stack
.
top
and
not
self
.
stack
.
top
.
is_children
(
node
):
...
@@ -144,27 +169,19 @@ class NodeUtil:
...
@@ -144,27 +169,19 @@ class NodeUtil:
def
debug
(
self
,
msg
):
def
debug
(
self
,
msg
):
self
.
_debug
and
logger
.
debug
(
msg
)
self
.
_debug
and
logger
.
debug
(
msg
)
def
set_assets_amount
(
self
):
for
node
in
self
.
_nodes
.
values
():
node
.
assets_amount
=
node
.
_assets_amount
def
set_full_value
(
self
):
for
node
in
self
.
_nodes
.
values
():
node
.
full_value
=
node
.
_full_value
@property
@property
def
nodes
(
self
):
def
nodes
(
self
):
return
list
(
self
.
_nodes
.
values
())
return
list
(
self
.
_nodes
.
values
())
def
get_family_by_key
(
self
,
key
):
def
get_family_by_key
(
self
,
key
):
tree_nodes
=
set
()
family
=
set
()
node
=
self
.
get_node_by_key
(
key
)
node
=
self
.
get_node_by_key
(
key
)
if
not
node
:
if
not
node
:
return
[]
return
[]
tree_nodes
.
update
(
node
.
_parents
)
family
.
update
(
getattr
(
node
,
'_parents'
)
)
tree_nodes
.
add
(
node
)
family
.
add
(
node
)
tree_nodes
.
update
(
node
.
_all_children
)
family
.
update
(
getattr
(
node
,
'_all_children'
)
)
return
list
(
tree_nodes
)
return
list
(
family
)
# 使用给定节点生成一颗树
# 使用给定节点生成一颗树
# 找到他们的祖先节点
# 找到他们的祖先节点
...
@@ -179,8 +196,8 @@ class NodeUtil:
...
@@ -179,8 +196,8 @@ class NodeUtil:
def
get_some_nodes_family_by_keys
(
self
,
keys
):
def
get_some_nodes_family_by_keys
(
self
,
keys
):
family
=
set
()
family
=
set
()
for
key
in
keys
:
for
key
in
keys
:
family
.
update
(
se
lf
.
get_family_by_key
(
key
))
family
.
update
(
se
t
(
self
.
get_family_by_key
(
key
)
))
return
family
return
list
(
family
)
def
get_some_nodes_family_keys_by_keys
(
self
,
keys
):
def
get_some_nodes_family_keys_by_keys
(
self
,
keys
):
family
=
self
.
get_some_nodes_family_by_keys
(
keys
)
family
=
self
.
get_some_nodes_family_by_keys
(
keys
)
...
@@ -191,7 +208,7 @@ class NodeUtil:
...
@@ -191,7 +208,7 @@ class NodeUtil:
node
=
self
.
get_node_by_key
(
key
)
node
=
self
.
get_node_by_key
(
key
)
if
not
node
:
if
not
node
:
return
[]
return
[]
parents
.
update
(
set
(
node
.
_parents
))
parents
.
update
(
set
(
getattr
(
node
,
'_parents'
)
))
if
with_self
:
if
with_self
:
parents
.
add
(
node
)
parents
.
add
(
node
)
return
list
(
parents
)
return
list
(
parents
)
...
@@ -203,21 +220,20 @@ class NodeUtil:
...
@@ -203,21 +220,20 @@ class NodeUtil:
nodes
=
self
.
get_nodes_parents_by_key
(
key
,
with_self
=
with_self
)
nodes
=
self
.
get_nodes_parents_by_key
(
key
,
with_self
=
with_self
)
return
[
n
.
key
for
n
in
nodes
]
return
[
n
.
key
for
n
in
nodes
]
def
get_all_children_by_key
(
self
,
key
,
with_self
=
True
):
def
get_node_all_children_by_key
(
self
,
key
,
with_self
=
True
):
children
=
set
()
node
=
self
.
get_node_by_key
(
key
)
node
=
self
.
get_node_by_key
(
key
)
if
not
node
:
if
not
node
:
return
[]
return
[]
children
.
update
(
set
(
node
.
_all_children
))
children
=
set
(
getattr
(
node
,
'_all_children'
))
if
with_self
:
if
with_self
:
children
.
add
(
node
)
children
.
add
(
node
)
return
list
(
children
)
return
list
(
children
)
def
get_all_children
(
self
,
node
,
with_self
=
True
):
def
get_all_children
(
self
,
node
,
with_self
=
True
):
return
self
.
get_all_children_by_key
(
node
.
key
,
with_self
=
with_self
)
return
self
.
get_
node_
all_children_by_key
(
node
.
key
,
with_self
=
with_self
)
def
get_all_children_keys_by_key
(
self
,
key
,
with_self
=
True
):
def
get_all_children_keys_by_key
(
self
,
key
,
with_self
=
True
):
nodes
=
self
.
get_all_children_by_key
(
key
,
with_self
=
with_self
)
nodes
=
self
.
get_
node_
all_children_by_key
(
key
,
with_self
=
with_self
)
return
[
n
.
key
for
n
in
nodes
]
return
[
n
.
key
for
n
in
nodes
]
...
@@ -250,7 +266,42 @@ def test_node_tree():
...
@@ -250,7 +266,42 @@ def test_node_tree():
)
)
class
TreeService
(
Tree
):
tag_sep
=
' / '
@classmethod
@timeit
def
new
(
cls
):
from
.models
import
Node
all_nodes
=
Node
.
objects
.
all
()
tree
=
cls
()
tree
.
create_node
(
tag
=
''
,
identifier
=
''
)
for
node
in
all_nodes
:
tree
.
create_node
(
tag
=
node
.
value
,
identifier
=
node
.
key
,
parent
=
node
.
parent_key
,
data
=
node
)
return
tree
def
all_children
(
self
,
nid
,
with_self
=
True
):
children_ids
=
self
.
expand_tree
(
nid
)
if
not
with_self
:
next
(
children_ids
)
return
[
self
[
i
]
for
i
in
children_ids
]
def
ancestors
(
self
,
nid
,
with_self
=
True
):
ancestor_ids
=
list
(
self
.
rsearch
(
nid
))
ancestor_ids
.
pop
()
if
not
with_self
:
ancestor_ids
.
pop
(
0
)
return
[
self
.
get_node
(
i
)
for
i
in
ancestor_ids
]
def
get_node_full_tag
(
self
,
nid
):
ancestors
=
self
.
ancestors
(
nid
)
ancestors
.
reverse
()
return
self
.
tag_sep
.
join
(
n
.
tag
for
n
in
ancestors
)
def
get_family
(
self
,
nid
):
ancestors
=
self
.
ancestors
(
nid
,
with_self
=
False
)
children
=
self
.
all_children
(
nid
,
with_self
=
False
)
return
ancestors
+
[
self
[
nid
]]
+
children
apps/jumpserver/settings.py
View file @
b81c52ae
...
@@ -304,10 +304,10 @@ LOGGING = {
...
@@ -304,10 +304,10 @@ LOGGING = {
'handlers'
:
[
'gunicorn_console'
,
'gunicorn_file'
],
'handlers'
:
[
'gunicorn_console'
,
'gunicorn_file'
],
'level'
:
'INFO'
,
'level'
:
'INFO'
,
},
},
#
'django.db': {
'django.db'
:
{
#
'handlers': ['console', 'file'],
'handlers'
:
[
'console'
,
'file'
],
#
'level': 'DEBUG'
'level'
:
'DEBUG'
#
}
}
}
}
}
}
...
...
apps/perms/forms/asset_permission.py
View file @
b81c52ae
...
@@ -41,17 +41,17 @@ class AssetPermissionForm(OrgModelForm):
...
@@ -41,17 +41,17 @@ class AssetPermissionForm(OrgModelForm):
users_field
=
self
.
fields
.
get
(
'users'
)
users_field
=
self
.
fields
.
get
(
'users'
)
users_field
.
queryset
=
current_org
.
get_org_users
()
users_field
.
queryset
=
current_org
.
get_org_users
()
nodes_field
=
self
.
fields
[
'nodes'
]
if
self
.
data
:
nodes_field
.
choices
=
((
n
.
id
,
n
.
full_value
)
for
n
in
Node
.
get_queryset
())
return
# 前端渲染优化, 防止过多资产
# 前端渲染优化, 防止过多资产
if
not
self
.
data
:
assets_field
=
self
.
fields
[
'assets'
]
instance
=
kwargs
.
get
(
'instance'
)
nodes_field
=
self
.
fields
[
'nodes'
]
assets_field
=
self
.
fields
[
'assets'
]
if
self
.
instance
:
if
instance
:
assets_field
.
queryset
=
self
.
instance
.
assets
.
all
()
assets_field
.
queryset
=
instance
.
assets
.
all
()
nodes_field
.
queryset
=
self
.
instance
.
nodes
.
all
()
else
:
else
:
assets_field
.
queryset
=
Asset
.
objects
.
none
()
assets_field
.
queryset
=
Asset
.
objects
.
none
()
nodes_field
.
queryset
=
Node
.
objects
.
none
()
class
Meta
:
class
Meta
:
model
=
AssetPermission
model
=
AssetPermission
...
@@ -69,7 +69,7 @@ class AssetPermissionForm(OrgModelForm):
...
@@ -69,7 +69,7 @@ class AssetPermissionForm(OrgModelForm):
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
"Asset"
)}
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
"Asset"
)}
),
),
'nodes'
:
forms
.
SelectMultiple
(
'nodes'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
"Node"
)}
attrs
=
{
'class'
:
'
nodes-
select2'
,
'data-placeholder'
:
_
(
"Node"
)}
),
),
'system_users'
:
forms
.
SelectMultiple
(
'system_users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'System user'
)}
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'System user'
)}
...
...
apps/perms/templates/perms/asset_permission_create_update.html
View file @
b81c52ae
...
@@ -115,6 +115,27 @@ $(document).ready(function () {
...
@@ -115,6 +115,27 @@ $(document).ready(function () {
$
(
'.select2'
).
select2
({
$
(
'.select2'
).
select2
({
closeOnSelect
:
false
closeOnSelect
:
false
});
});
$
(
".nodes-select2"
).
select2
({
closeOnSelect
:
false
,
ajax
:
{
url
:
'{% url "api-assets:node-list" %}'
,
data
:
function
(
params
)
{
var
page
=
params
.
page
||
1
;
var
query
=
{
search
:
params
.
term
,
offset
:
(
page
-
1
)
*
10
,
limit
:
10
};
return
query
},
processResults
:
function
(
data
)
{
var
results
=
$
.
map
(
data
.
results
,
function
(
v
,
i
)
{
return
{
id
:
v
.
id
,
text
:
v
.
full_value
}
});
return
{
results
:
results
,
pagination
:
{
"more"
:
true
}}
}
},
});
$
(
'#date_start'
).
daterangepicker
(
dateOptions
);
$
(
'#date_start'
).
daterangepicker
(
dateOptions
);
$
(
'#date_expired'
).
daterangepicker
(
dateOptions
);
$
(
'#date_expired'
).
daterangepicker
(
dateOptions
);
$
(
"#id_assets"
).
parent
().
find
(
".select2-selection"
).
on
(
'click'
,
function
(
e
)
{
$
(
"#id_assets"
).
parent
().
find
(
".select2-selection"
).
on
(
'click'
,
function
(
e
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment