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
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
367 additions
and
220 deletions
+367
-220
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
+19
-3
node.py
apps/assets/models/node.py
+127
-114
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
+8
-8
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'
]
if
self
.
instance
:
nodes_field
.
choices
=
((
n
.
id
,
n
.
full_value
)
for
n
in
nodes_field
.
choices
=
((
n
.
id
,
n
.
full_value
)
for
n
in
Node
.
get_queryset
())
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
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
#
#
import
uuid
import
uuid
import
re
import
re
import
time
from
django.db
import
models
,
transaction
from
django.db
import
models
,
transaction
from
django.db.models
import
Q
from
django.db.models
import
Q
...
@@ -13,6 +14,7 @@ from orgs.mixins import OrgModelMixin, OrgManager
...
@@ -13,6 +14,7 @@ from orgs.mixins import OrgModelMixin, OrgManager
from
orgs.utils
import
set_current_org
,
get_current_org
from
orgs.utils
import
set_current_org
,
get_current_org
from
orgs.models
import
Organization
from
orgs.models
import
Organization
__all__
=
[
'Node'
]
__all__
=
[
'Node'
]
...
@@ -22,76 +24,102 @@ class NodeQuerySet(models.QuerySet):
...
@@ -22,76 +24,102 @@ class NodeQuerySet(models.QuerySet):
class
FamilyMixin
:
class
FamilyMixin
:
_parents
=
None
_
_
parents
=
None
_children
=
None
_
_
children
=
None
_all_children
=
None
_
_
all_children
=
None
is_node
=
True
is_node
=
True
time_tree_updated
=
None
time_tree_updated_cache_key
=
'NODE_TREE_CREATED_AT'
tree_cache_time
=
3600
_tree_service
=
None
@classmethod
def
tree
(
cls
):
from
..utils
import
TreeService
cache_updated_time
=
cls
.
get_cache_time
()
if
not
cls
.
time_tree_updated
or
cache_updated_time
!=
cls
.
time_tree_updated
:
t
=
TreeService
.
new
()
cls
.
update_cache_tree
(
t
)
return
t
return
cls
.
_tree_service
@classmethod
def
get_cache_time
(
cls
):
return
cache
.
get
(
cls
.
time_tree_updated_cache_key
)
@classmethod
def
update_cache_tree
(
cls
,
t
):
cls
.
_tree_service
=
t
now
=
time
.
time
()
cls
.
time_tree_updated
=
now
cache
.
set
(
cls
.
time_tree_updated_cache_key
,
now
,
cls
.
tree_cache_time
)
@classmethod
def
expire_cache_tree
(
cls
):
cache
.
delete
(
cls
.
time_tree_updated_cache_key
)
@classmethod
def
refresh_tree
(
cls
):
cls
.
expire_cache_tree
()
@property
@property
def
children
(
self
):
def
_tree
(
self
):
if
self
.
_children
:
return
self
.
__class__
.
tree
()
return
self
.
_children
pattern
=
r'^{0}:[0-9]+$'
.
format
(
self
.
key
)
return
Node
.
objects
.
filter
(
key__regex
=
pattern
)
@
children.setter
@
property
def
children
(
self
,
value
):
def
children
(
self
):
self
.
_children
=
value
return
self
.
get_children
(
with_self
=
False
)
@property
@property
def
all_children
(
self
):
def
all_children
(
self
):
if
self
.
_all_children
:
return
self
.
get_all_children
(
with_self
=
False
)
return
self
.
_all_children
pattern
=
r'^{0}:'
.
format
(
self
.
key
)
def
_get_children
(
self
,
with_self
=
False
):
return
Node
.
objects
.
filter
(
pattern
=
r'^{0}:[0-9]+$'
.
format
(
self
.
key
)
key__regex
=
pattern
if
with_self
:
)
pattern
+=
r'^{0}$'
return
Node
.
objects
.
filter
(
key__regex
=
pattern
)
def
get_children
(
self
,
with_self
=
False
):
def
get_children
(
self
,
with_self
=
False
):
children
=
list
(
self
.
children
)
_children
=
self
.
_tree
.
children
(
self
.
key
)
children
=
[
n
.
data
for
n
in
_children
]
if
with_self
:
if
with_self
:
children
.
append
(
self
)
children
.
append
(
self
)
return
children
return
children
def
get_all_children
(
self
,
with_self
=
False
):
def
_
get_all_children
(
self
,
with_self
=
False
):
children
=
self
.
all_children
pattern
=
r'^{0}:'
.
format
(
self
.
key
)
if
with_self
:
if
with_self
:
children
=
list
(
children
)
pattern
+=
r'|^{0}$'
children
.
append
(
self
)
children
=
Node
.
objects
.
filter
(
key__regex
=
pattern
)
return
children
def
get_all_children
(
self
,
with_self
=
False
):
_children
=
self
.
_tree
.
all_children
(
self
.
key
,
with_self
=
with_self
)
children
=
[
n
.
data
for
n
in
_children
]
return
children
return
children
@property
@property
def
parents
(
self
):
def
parents
(
self
):
if
self
.
_parents
:
return
self
.
get_ancestor
(
with_self
=
False
)
return
self
.
_parents
ancestor_keys
=
self
.
get_ancestor_keys
()
ancestor
=
Node
.
objects
.
filter
(
key__in
=
ancestor_keys
)
.
order_by
(
'key'
)
return
ancestor
@parents.setter
def
parents
(
self
,
value
):
self
.
_parents
=
value
def
get_ancestor
(
self
,
with_self
=
False
):
def
_
get_ancestor
(
self
,
with_self
=
False
):
parents
=
self
.
parents
parents
=
self
.
parents
if
with_self
:
if
with_self
:
parents
=
list
(
parents
)
parents
=
list
(
parents
)
parents
.
append
(
self
)
parents
.
append
(
self
)
return
parents
return
parents
def
get_ancestor
(
self
,
with_self
=
False
):
_ancestor
=
self
.
_tree
.
ancestors
(
self
.
key
,
with_self
=
with_self
)
ancestor
=
[
n
.
data
for
n
in
_ancestor
]
return
ancestor
@property
@property
def
parent
(
self
):
def
parent
(
self
):
if
self
.
_parents
:
return
self
.
_parents
[
0
]
if
self
.
is_root
():
if
self
.
is_root
():
return
self
return
self
try
:
return
self
.
_tree
.
parent
(
self
.
key
)
.
data
parent
=
Node
.
objects
.
get
(
key
=
self
.
parent_key
)
return
parent
except
Node
.
DoesNotExist
:
return
Node
.
root
()
@parent.setter
@parent.setter
def
parent
(
self
,
parent
):
def
parent
(
self
,
parent
):
...
@@ -107,7 +135,7 @@ class FamilyMixin:
...
@@ -107,7 +135,7 @@ class FamilyMixin:
child
.
save
()
child
.
save
()
self
.
save
()
self
.
save
()
def
get_sibling
(
self
,
with_self
=
False
):
def
_get_siblings
(
self
,
with_self
=
False
):
key
=
':'
.
join
(
self
.
key
.
split
(
':'
)[:
-
1
])
key
=
':'
.
join
(
self
.
key
.
split
(
':'
)[:
-
1
])
pattern
=
r'^{}:[0-9]+$'
.
format
(
key
)
pattern
=
r'^{}:[0-9]+$'
.
format
(
key
)
sibling
=
Node
.
objects
.
filter
(
sibling
=
Node
.
objects
.
filter
(
...
@@ -117,6 +145,13 @@ class FamilyMixin:
...
@@ -117,6 +145,13 @@ class FamilyMixin:
sibling
=
sibling
.
exclude
(
key
=
self
.
key
)
sibling
=
sibling
.
exclude
(
key
=
self
.
key
)
return
sibling
return
sibling
def
get_siblings
(
self
,
with_self
=
False
):
_siblings
=
self
.
_tree
.
siblings
(
self
.
key
)
siblings
=
[
n
.
data
for
n
in
_siblings
]
if
with_self
:
siblings
.
append
(
self
)
return
siblings
def
get_family
(
self
):
def
get_family
(
self
):
ancestor
=
self
.
get_ancestor
()
ancestor
=
self
.
get_ancestor
()
children
=
self
.
get_all_children
()
children
=
self
.
get_all_children
()
...
@@ -133,12 +168,10 @@ class FamilyMixin:
...
@@ -133,12 +168,10 @@ class FamilyMixin:
return
parent_keys
return
parent_keys
def
is_children
(
self
,
other
):
def
is_children
(
self
,
other
):
pattern
=
re
.
compile
(
r'^{0}:[0-9]+$'
.
format
(
self
.
key
))
return
other
.
key
.
startswith
(
self
.
key
+
':'
)
return
pattern
.
match
(
other
.
key
)
def
is_parent
(
self
,
other
):
def
is_parent
(
self
,
other
):
pattern
=
re
.
compile
(
r'^{0}:[0-9]+$'
.
format
(
other
.
key
))
return
other
.
is_children
(
self
)
return
pattern
.
match
(
self
.
key
)
@property
@property
def
parent_key
(
self
):
def
parent_key
(
self
):
...
@@ -164,40 +197,18 @@ class FullValueMixin:
...
@@ -164,40 +197,18 @@ class FullValueMixin:
@property
@property
def
full_value
(
self
):
def
full_value
(
self
):
if
self
.
_full_value
:
return
self
.
_full_value
key
=
self
.
_full_value_cache_key
.
format
(
self
.
key
)
cached
=
cache
.
get
(
key
)
if
cached
:
return
cached
if
self
.
is_root
():
if
self
.
is_root
():
return
self
.
value
return
self
.
value
parent_full_value
=
self
.
parent
.
full_value
value
=
self
.
_tree
.
get_node_full_tag
(
self
.
key
)
value
=
parent_full_value
+
' / '
+
self
.
value
self
.
full_value
=
value
return
value
return
value
@full_value.setter
def
full_value
(
self
,
value
):
self
.
_full_value
=
value
key
=
self
.
_full_value_cache_key
.
format
(
self
.
key
)
cache
.
set
(
key
,
value
,
3600
*
24
)
def
expire_full_value
(
self
):
key
=
self
.
_full_value_cache_key
.
format
(
self
.
key
)
cache
.
delete_pattern
(
key
+
'*'
)
@classmethod
class
NodeAssetsMixin
:
def
expire_nodes_full_value
(
cls
,
nodes
=
None
):
key
=
cls
.
_full_value_cache_key
.
format
(
'*'
)
cache
.
delete_pattern
(
key
+
'*'
)
class
AssetsAmountMixin
:
_assets_amount_cache_key
=
'_NODE_ASSETS_AMOUNT_{}'
_assets_amount_cache_key
=
'_NODE_ASSETS_AMOUNT_{}'
_assets_amount
=
None
_assets_amount
=
None
key
=
''
key
=
''
cache_time
=
3600
*
24
*
7
cache_time
=
3600
*
24
*
7
id
=
None
@property
@property
def
assets_amount
(
self
):
def
assets_amount
(
self
):
...
@@ -212,14 +223,9 @@ class AssetsAmountMixin:
...
@@ -212,14 +223,9 @@ class AssetsAmountMixin:
if
cached
is
not
None
:
if
cached
is
not
None
:
return
cached
return
cached
assets_amount
=
self
.
get_all_assets
()
.
only
(
'id'
)
.
count
()
assets_amount
=
self
.
get_all_assets
()
.
only
(
'id'
)
.
count
()
self
.
assets_amount
=
assets_amount
return
assets_amount
@assets_amount.setter
def
assets_amount
(
self
,
value
):
self
.
_assets_amount
=
value
cache_key
=
self
.
_assets_amount_cache_key
.
format
(
self
.
key
)
cache_key
=
self
.
_assets_amount_cache_key
.
format
(
self
.
key
)
cache
.
set
(
cache_key
,
value
,
self
.
cache_time
)
cache
.
set
(
cache_key
,
assets_amount
,
self
.
cache_time
)
return
assets_amount
def
expire_assets_amount
(
self
):
def
expire_assets_amount
(
self
):
ancestor_keys
=
self
.
get_ancestor_keys
(
with_self
=
True
)
ancestor_keys
=
self
.
get_ancestor_keys
(
with_self
=
True
)
...
@@ -229,18 +235,38 @@ class AssetsAmountMixin:
...
@@ -229,18 +235,38 @@ class AssetsAmountMixin:
@classmethod
@classmethod
def
expire_nodes_assets_amount
(
cls
,
nodes
=
None
):
def
expire_nodes_assets_amount
(
cls
,
nodes
=
None
):
key
=
cls
.
_assets_amount_cache_key
.
format
(
'*'
)
for
node
in
nodes
:
cache
.
delete_pattern
(
key
)
node
.
expire_assets_amount
(
)
@classmethod
@classmethod
def
refresh_nodes
(
cls
):
def
refresh_assets_amount
(
cls
):
from
..utils
import
NodeUtil
cache_key
=
cls
.
_assets_amount_cache_key
.
format
(
'*'
)
util
=
NodeUtil
(
with_assets_amount
=
True
)
cache
.
delete_pattern
(
cache_key
)
util
.
set_assets_amount
()
util
.
set_full_value
()
def
get_all_assets
(
self
):
from
.asset
import
Asset
if
self
.
is_root
():
return
Asset
.
objects
.
filter
(
org_id
=
self
.
org_id
)
children
=
self
.
get_all_children
(
with_self
=
True
)
assets
=
Asset
.
objects
.
filter
(
nodes__in
=
children
)
.
distinct
()
return
assets
def
get_assets
(
self
):
from
.asset
import
Asset
if
self
.
is_default_node
():
assets
=
Asset
.
objects
.
filter
(
Q
(
nodes__id
=
self
.
id
)
|
Q
(
nodes__isnull
=
True
))
else
:
assets
=
Asset
.
objects
.
filter
(
nodes__id
=
self
.
id
)
return
assets
.
distinct
()
def
get_valid_assets
(
self
):
return
self
.
get_assets
()
.
valid
()
class
Node
(
OrgModelMixin
,
FamilyMixin
,
FullValueMixin
,
AssetsAmountMixin
):
def
get_all_valid_assets
(
self
):
return
self
.
get_all_assets
()
.
valid
()
class
Node
(
OrgModelMixin
,
FamilyMixin
,
FullValueMixin
,
NodeAssetsMixin
):
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
key
=
models
.
CharField
(
unique
=
True
,
max_length
=
64
,
verbose_name
=
_
(
"Key"
))
# '1:1:1:1'
key
=
models
.
CharField
(
unique
=
True
,
max_length
=
64
,
verbose_name
=
_
(
"Key"
))
# '1:1:1:1'
value
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Value"
))
value
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Value"
))
...
@@ -256,7 +282,7 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
...
@@ -256,7 +282,7 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
ordering
=
[
'key'
]
ordering
=
[
'key'
]
def
__str__
(
self
):
def
__str__
(
self
):
return
self
.
full_
value
return
self
.
value
def
__eq__
(
self
,
other
):
def
__eq__
(
self
,
other
):
if
not
other
:
if
not
other
:
...
@@ -316,31 +342,10 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
...
@@ -316,31 +342,10 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
child
=
self
.
__class__
.
objects
.
create
(
id
=
_id
,
key
=
child_key
,
value
=
value
)
child
=
self
.
__class__
.
objects
.
create
(
id
=
_id
,
key
=
child_key
,
value
=
value
)
return
child
return
child
def
get_assets
(
self
):
@classmethod
from
.asset
import
Asset
def
refresh_nodes
(
cls
):
if
self
.
is_default_node
():
cls
.
refresh_assets_amount
()
assets
=
Asset
.
objects
.
filter
(
Q
(
nodes__id
=
self
.
id
)
|
Q
(
nodes__isnull
=
True
))
cls
.
refresh_tree
()
else
:
assets
=
Asset
.
objects
.
filter
(
nodes__id
=
self
.
id
)
return
assets
.
distinct
()
def
get_valid_assets
(
self
):
return
self
.
get_assets
()
.
valid
()
def
get_all_assets
(
self
):
from
.asset
import
Asset
pattern
=
r'^{0}$|^{0}:'
.
format
(
self
.
key
)
args
=
[]
kwargs
=
{}
if
self
.
is_root
():
args
.
append
(
Q
(
nodes__key__regex
=
pattern
)
|
Q
(
nodes
=
None
))
else
:
kwargs
[
'nodes__key__regex'
]
=
pattern
assets
=
Asset
.
objects
.
filter
(
*
args
,
**
kwargs
)
.
distinct
()
return
assets
def
get_all_valid_assets
(
self
):
return
self
.
get_all_assets
()
.
valid
()
def
is_default_node
(
self
):
def
is_default_node
(
self
):
return
self
.
is_root
()
and
self
.
key
==
'1'
return
self
.
is_root
()
and
self
.
key
==
'1'
...
@@ -384,6 +389,7 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
...
@@ -384,6 +389,7 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
def
as_tree_node
(
self
):
def
as_tree_node
(
self
):
from
common.tree
import
TreeNode
from
common.tree
import
TreeNode
name
=
'{} ({})'
.
format
(
self
.
value
,
self
.
assets_amount
)
name
=
'{} ({})'
.
format
(
self
.
value
,
self
.
assets_amount
)
# name = self.value
data
=
{
data
=
{
'id'
:
self
.
key
,
'id'
:
self
.
key
,
'name'
:
name
,
'name'
:
name
,
...
@@ -422,7 +428,14 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
...
@@ -422,7 +428,14 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
org
=
get_current_org
()
org
=
get_current_org
()
if
not
org
or
not
org
.
is_real
():
if
not
org
or
not
org
.
is_real
():
Organization
.
default
()
.
change_to
()
Organization
.
default
()
.
change_to
()
i
=
0
while
i
<
count
:
nodes
=
list
(
cls
.
objects
.
all
())
if
count
>
100
:
length
=
100
else
:
length
=
count
for
i
in
range
(
count
):
for
i
in
range
(
length
):
node
=
random
.
choice
(
cls
.
objects
.
all
()
)
node
=
random
.
choice
(
nodes
)
node
.
create_child
(
'Node {}'
.
format
(
i
))
node
.
create_child
(
'Node {}'
.
format
(
i
))
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
:
instance
=
kwargs
.
get
(
'instance'
)
assets_field
=
self
.
fields
[
'assets'
]
assets_field
=
self
.
fields
[
'assets'
]
if
instance
:
nodes_field
=
self
.
fields
[
'nodes'
]
assets_field
.
queryset
=
instance
.
assets
.
all
()
if
self
.
instance
:
assets_field
.
queryset
=
self
.
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