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
dbdcdb72
Commit
dbdcdb72
authored
Dec 17, 2018
by
ibuler
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' of github.com:jumpserver/jumpserver into dev
parents
1ff9f0ea
517a27ea
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
270 additions
and
192 deletions
+270
-192
asset.py
apps/assets/api/asset.py
+27
-21
node.py
apps/assets/api/node.py
+89
-49
asset.py
apps/assets/models/asset.py
+30
-0
node.py
apps/assets/models/node.py
+42
-1
asset.py
apps/assets/serializers/asset.py
+14
-0
node.py
apps/assets/serializers/node.py
+7
-49
asset_list.html
apps/assets/templates/assets/asset_list.html
+0
-0
api_urls.py
apps/assets/urls/api_urls.py
+2
-0
asset.py
apps/assets/views/asset.py
+0
-1
settings.py
apps/jumpserver/settings.py
+1
-0
django.mo
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh/LC_MESSAGES/django.po
+0
-0
api.py
apps/perms/api.py
+3
-3
hands.py
apps/perms/hands.py
+1
-1
serializers.py
apps/perms/serializers.py
+29
-0
asset_permission_list.html
apps/perms/templates/perms/asset_permission_list.html
+13
-66
utils.py
apps/users/utils.py
+2
-1
config_docker.py
config_docker.py
+7
-0
config_example.py
config_example.py
+3
-0
No files found.
apps/assets/api/asset.py
View file @
dbdcdb72
...
@@ -41,40 +41,46 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
...
@@ -41,40 +41,46 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
pagination_class
=
LimitOffsetPagination
pagination_class
=
LimitOffsetPagination
permission_classes
=
(
IsOrgAdminOrAppUser
,)
permission_classes
=
(
IsOrgAdminOrAppUser
,)
def
filter_node
(
self
):
def
filter_node
(
self
,
queryset
):
node_id
=
self
.
request
.
query_params
.
get
(
"node_id"
)
node_id
=
self
.
request
.
query_params
.
get
(
"node_id"
)
if
not
node_id
:
if
not
node_id
:
return
return
queryset
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
():
if
node
.
is_root
()
and
show_current_asset
:
if
show_current_asset
:
queryset
=
queryset
.
filter
(
self
.
queryset
=
self
.
queryset
.
filter
(
Q
(
nodes
=
node_id
)
|
Q
(
nodes__isnull
=
True
)
Q
(
nodes
=
node_id
)
|
Q
(
nodes__isnull
=
True
)
)
)
elif
node
.
is_root
()
and
not
show_current_asset
:
return
pass
if
show_current_asset
:
elif
not
node
.
is_root
()
and
show_current_asset
:
self
.
queryset
=
self
.
queryset
.
filter
(
nodes
=
node
)
queryset
=
queryset
.
filter
(
nodes
=
node
)
else
:
else
:
self
.
queryset
=
self
.
queryset
.
filter
(
queryset
=
queryset
.
filter
(
nodes__key__regex
=
'^{}(:[0-9]+)*$'
.
format
(
node
.
key
),
nodes__key__regex
=
'^{}(:[0-9]+)*$'
.
format
(
node
.
key
),
)
)
return
queryset
def
filter_admin_user_id
(
self
):
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'
)
if
admin_user_id
:
if
not
admin_user_id
:
admin_user
=
get_object_or_404
(
AdminUser
,
id
=
admin_user_id
)
return
queryset
self
.
queryset
=
self
.
queryset
.
filter
(
admin_user
=
admin_user
)
admin_user
=
get_object_or_404
(
AdminUser
,
id
=
admin_user_id
)
queryset
=
queryset
.
filter
(
admin_user
=
admin_user
)
return
queryset
def
filter_queryset
(
self
,
queryset
):
queryset
=
super
()
.
filter_queryset
(
queryset
)
queryset
=
self
.
filter_node
(
queryset
)
queryset
=
self
.
filter_admin_user_id
(
queryset
)
return
queryset
def
get_queryset
(
self
):
def
get_queryset
(
self
):
self
.
queryset
=
super
()
.
get_queryset
()
\
queryset
=
super
()
.
get_queryset
()
.
distinct
()
.
prefetch_related
(
'labels'
,
'nodes'
)
\
queryset
=
self
.
get_serializer_class
()
.
setup_eager_loading
(
queryset
)
.
select_related
(
'admin_user'
)
return
queryset
self
.
filter_admin_user_id
()
self
.
filter_node
()
return
self
.
queryset
.
distinct
()
class
AssetListUpdateApi
(
IDInFilterMixin
,
ListBulkCreateUpdateDestroyAPIView
):
class
AssetListUpdateApi
(
IDInFilterMixin
,
ListBulkCreateUpdateDestroyAPIView
):
...
...
apps/assets/api/node.py
View file @
dbdcdb72
...
@@ -17,13 +17,13 @@ from rest_framework import generics, mixins, viewsets
...
@@ -17,13 +17,13 @@ from rest_framework import generics, mixins, viewsets
from
rest_framework.serializers
import
ValidationError
from
rest_framework.serializers
import
ValidationError
from
rest_framework.views
import
APIView
from
rest_framework.views
import
APIView
from
rest_framework.response
import
Response
from
rest_framework.response
import
Response
from
rest_framework_bulk
import
BulkModelViewSet
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.shortcuts
import
get_object_or_404
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
..hands
import
IsOrgAdmin
from
..hands
import
IsOrgAdmin
from
..models
import
Node
,
Asset
from
..models
import
Node
from
..tasks
import
update_assets_hardware_info_util
,
test_asset_connectability_util
from
..tasks
import
update_assets_hardware_info_util
,
test_asset_connectability_util
from
..
import
serializers
from
..
import
serializers
...
@@ -33,7 +33,8 @@ __all__ = [
...
@@ -33,7 +33,8 @@ __all__ = [
'NodeViewSet'
,
'NodeChildrenApi'
,
'NodeAssetsApi'
,
'NodeViewSet'
,
'NodeChildrenApi'
,
'NodeAssetsApi'
,
'NodeAddAssetsApi'
,
'NodeRemoveAssetsApi'
,
'NodeReplaceAssetsApi'
,
'NodeAddAssetsApi'
,
'NodeRemoveAssetsApi'
,
'NodeReplaceAssetsApi'
,
'NodeAddChildrenApi'
,
'RefreshNodeHardwareInfoApi'
,
'NodeAddChildrenApi'
,
'RefreshNodeHardwareInfoApi'
,
'TestNodeConnectiveApi'
'TestNodeConnectiveApi'
,
'NodeListAsTreeApi'
,
'NodeChildrenAsTreeApi'
,
]
]
...
@@ -42,22 +43,89 @@ class NodeViewSet(viewsets.ModelViewSet):
...
@@ -42,22 +43,89 @@ class NodeViewSet(viewsets.ModelViewSet):
permission_classes
=
(
IsOrgAdmin
,)
permission_classes
=
(
IsOrgAdmin
,)
serializer_class
=
serializers
.
NodeSerializer
serializer_class
=
serializers
.
NodeSerializer
def
perform_create
(
self
,
serializer
):
child_key
=
Node
.
root
()
.
get_next_child_key
()
serializer
.
validated_data
[
"key"
]
=
child_key
serializer
.
save
()
def
update
(
self
,
request
,
*
args
,
**
kwargs
):
class
NodeListAsTreeApi
(
generics
.
ListAPIView
):
node
=
self
.
get_object
()
"""
if
node
.
is_root
():
获取节点列表树
node_value
=
node
.
value
[
post_value
=
request
.
data
.
get
(
'value'
)
{
if
node_value
!=
post_value
:
"id": "",
return
Response
(
"name": "",
{
"msg"
:
_
(
"You can't update the root node name"
)},
"pId": "",
status
=
400
"meta": ""
)
}
return
super
()
.
update
(
request
,
*
args
,
**
kwargs
)
]
"""
permission_classes
=
(
IsOrgAdmin
,)
serializer_class
=
TreeNodeSerializer
def
get_queryset
(
self
):
queryset
=
[
node
.
as_tree_node
()
for
node
in
Node
.
objects
.
all
()]
return
queryset
def
filter_queryset
(
self
,
queryset
):
if
self
.
request
.
query_params
.
get
(
'refresh'
,
'0'
)
==
'1'
:
queryset
=
self
.
refresh_nodes
(
queryset
)
return
queryset
@staticmethod
def
refresh_nodes
(
queryset
):
Node
.
expire_nodes_assets_amount
()
Node
.
expire_nodes_full_value
()
return
queryset
class
NodeChildrenAsTreeApi
(
generics
.
ListAPIView
):
"""
节点子节点作为树返回,
[
{
"id": "",
"name": "",
"pId": "",
"meta": ""
}
]
"""
permission_classes
=
(
IsOrgAdmin
,)
serializer_class
=
TreeNodeSerializer
node
=
None
is_root
=
False
def
get_queryset
(
self
):
node_key
=
self
.
request
.
query_params
.
get
(
'key'
)
if
node_key
:
self
.
node
=
Node
.
objects
.
get
(
key
=
node_key
)
queryset
=
self
.
node
.
get_children
(
with_self
=
False
)
else
:
self
.
is_root
=
True
self
.
node
=
Node
.
root
()
queryset
=
list
(
self
.
node
.
get_children
(
with_self
=
True
))
nodes_invalid
=
Node
.
objects
.
exclude
(
key__startswith
=
self
.
node
.
key
)
queryset
.
extend
(
list
(
nodes_invalid
))
queryset
=
[
node
.
as_tree_node
()
for
node
in
queryset
]
return
queryset
def
filter_assets
(
self
,
queryset
):
include_assets
=
self
.
request
.
query_params
.
get
(
'assets'
,
'0'
)
==
'1'
if
not
include_assets
:
return
queryset
assets
=
self
.
node
.
get_assets
()
for
asset
in
assets
:
queryset
.
append
(
asset
.
as_tree_node
(
self
.
node
))
return
queryset
def
filter_queryset
(
self
,
queryset
):
queryset
=
self
.
filter_assets
(
queryset
)
queryset
=
self
.
filter_refresh_nodes
(
queryset
)
return
queryset
def
filter_refresh_nodes
(
self
,
queryset
):
if
self
.
request
.
query_params
.
get
(
'refresh'
,
'0'
)
==
'1'
:
Node
.
expire_nodes_assets_amount
()
Node
.
expire_nodes_full_value
()
return
queryset
class
NodeChildrenApi
(
mixins
.
ListModelMixin
,
generics
.
CreateAPIView
):
class
NodeChildrenApi
(
mixins
.
ListModelMixin
,
generics
.
CreateAPIView
):
...
@@ -66,19 +134,10 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
...
@@ -66,19 +134,10 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
serializer_class
=
serializers
.
NodeSerializer
serializer_class
=
serializers
.
NodeSerializer
instance
=
None
instance
=
None
def
counter
(
self
):
values
=
[
child
.
value
[
child
.
value
.
rfind
(
' '
):]
for
child
in
self
.
get_object
()
.
get_children
()
if
child
.
value
.
startswith
(
"新节点 "
)
]
values
=
[
int
(
value
)
for
value
in
values
if
value
.
strip
()
.
isdigit
()]
count
=
max
(
values
)
+
1
if
values
else
1
return
count
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
instance
=
self
.
get_object
()
if
not
request
.
data
.
get
(
"value"
):
if
not
request
.
data
.
get
(
"value"
):
request
.
data
[
"value"
]
=
_
(
"New node {}"
)
.
format
(
self
.
counter
()
)
request
.
data
[
"value"
]
=
instance
.
get_next_child_preset_name
(
)
return
super
()
.
post
(
request
,
*
args
,
**
kwargs
)
return
super
()
.
post
(
request
,
*
args
,
**
kwargs
)
def
create
(
self
,
request
,
*
args
,
**
kwargs
):
def
create
(
self
,
request
,
*
args
,
**
kwargs
):
...
@@ -90,10 +149,7 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
...
@@ -90,10 +149,7 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
'The same level node name cannot be the same'
'The same level node name cannot be the same'
)
)
node
=
instance
.
create_child
(
value
=
value
)
node
=
instance
.
create_child
(
value
=
value
)
return
Response
(
return
Response
(
self
.
serializer_class
(
instance
=
node
)
.
data
,
status
=
201
)
{
"id"
:
node
.
id
,
"key"
:
node
.
key
,
"value"
:
node
.
value
},
status
=
201
,
)
def
get_object
(
self
):
def
get_object
(
self
):
pk
=
self
.
kwargs
.
get
(
'pk'
)
or
self
.
request
.
query_params
.
get
(
'id'
)
pk
=
self
.
kwargs
.
get
(
'pk'
)
or
self
.
request
.
query_params
.
get
(
'id'
)
...
@@ -106,7 +162,6 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
...
@@ -106,7 +162,6 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
def
get_queryset
(
self
):
def
get_queryset
(
self
):
queryset
=
[]
queryset
=
[]
query_all
=
self
.
request
.
query_params
.
get
(
"all"
)
query_all
=
self
.
request
.
query_params
.
get
(
"all"
)
query_assets
=
self
.
request
.
query_params
.
get
(
'assets'
)
node
=
self
.
get_object
()
node
=
self
.
get_object
()
if
node
is
None
:
if
node
is
None
:
...
@@ -119,23 +174,8 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
...
@@ -119,23 +174,8 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
else
:
else
:
children
=
node
.
get_children
()
children
=
node
.
get_children
()
queryset
.
extend
(
list
(
children
))
queryset
.
extend
(
list
(
children
))
if
query_assets
:
assets
=
node
.
get_assets
()
for
asset
in
assets
:
node_fake
=
Node
()
node_fake
.
assets__count
=
0
node_fake
.
id
=
asset
.
id
node_fake
.
is_node
=
False
node_fake
.
key
=
node
.
key
+
':0'
node_fake
.
value
=
asset
.
hostname
queryset
.
append
(
node_fake
)
queryset
=
sorted
(
queryset
,
key
=
lambda
x
:
x
.
is_node
,
reverse
=
True
)
return
queryset
return
queryset
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
return
super
()
.
list
(
request
,
*
args
,
**
kwargs
)
class
NodeAssetsApi
(
generics
.
ListAPIView
):
class
NodeAssetsApi
(
generics
.
ListAPIView
):
permission_classes
=
(
IsOrgAdmin
,)
permission_classes
=
(
IsOrgAdmin
,)
...
...
apps/assets/models/asset.py
View file @
dbdcdb72
...
@@ -255,6 +255,36 @@ class Asset(OrgModelMixin):
...
@@ -255,6 +255,36 @@ class Asset(OrgModelMixin):
})
})
return
data
return
data
def
as_tree_node
(
self
,
parent_node
):
from
common.tree
import
TreeNode
icon_skin
=
'file'
if
self
.
platform
.
lower
()
==
'windows'
:
icon_skin
=
'windows'
elif
self
.
platform
.
lower
()
==
'linux'
:
icon_skin
=
'linux'
data
=
{
'id'
:
str
(
self
.
id
),
'name'
:
self
.
hostname
,
'title'
:
self
.
ip
,
'pId'
:
parent_node
.
key
,
'isParent'
:
False
,
'open'
:
False
,
'iconSkin'
:
icon_skin
,
'meta'
:
{
'type'
:
'asset'
,
'asset'
:
{
'id'
:
self
.
id
,
'hostname'
:
self
.
hostname
,
'ip'
:
self
.
ip
,
'port'
:
self
.
port
,
'platform'
:
self
.
platform
,
'protocol'
:
self
.
protocol
,
}
}
}
tree_node
=
TreeNode
(
**
data
)
return
tree_node
class
Meta
:
class
Meta
:
unique_together
=
[(
'org_id'
,
'hostname'
)]
unique_together
=
[(
'org_id'
,
'hostname'
)]
verbose_name
=
_
(
"Asset"
)
verbose_name
=
_
(
"Asset"
)
...
...
apps/assets/models/node.py
View file @
dbdcdb72
...
@@ -5,6 +5,7 @@ import uuid
...
@@ -5,6 +5,7 @@ import uuid
from
django.db
import
models
,
transaction
from
django.db
import
models
,
transaction
from
django.db.models
import
Q
from
django.db.models
import
Q
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext
from
django.core.cache
import
cache
from
django.core.cache
import
cache
from
orgs.mixins
import
OrgModelMixin
from
orgs.mixins
import
OrgModelMixin
...
@@ -103,6 +104,15 @@ class Node(OrgModelMixin):
...
@@ -103,6 +104,15 @@ class Node(OrgModelMixin):
key
=
self
.
_full_value_cache_key
.
format
(
self
.
key
)
key
=
self
.
_full_value_cache_key
.
format
(
self
.
key
)
cache
.
delete_pattern
(
key
+
'*'
)
cache
.
delete_pattern
(
key
+
'*'
)
@classmethod
def
expire_nodes_full_value
(
cls
,
nodes
=
None
):
if
nodes
:
for
node
in
nodes
:
node
.
expire_full_value
()
return
key
=
cls
.
_full_value_cache_key
.
format
(
'*'
)
cache
.
delete_pattern
(
key
+
'*'
)
@property
@property
def
level
(
self
):
def
level
(
self
):
return
len
(
self
.
key
.
split
(
':'
))
return
len
(
self
.
key
.
split
(
':'
))
...
@@ -113,6 +123,17 @@ class Node(OrgModelMixin):
...
@@ -113,6 +123,17 @@ class Node(OrgModelMixin):
self
.
save
()
self
.
save
()
return
"{}:{}"
.
format
(
self
.
key
,
mark
)
return
"{}:{}"
.
format
(
self
.
key
,
mark
)
def
get_next_child_preset_name
(
self
):
name
=
ugettext
(
"New node"
)
values
=
[
child
.
value
[
child
.
value
.
rfind
(
' '
):]
for
child
in
self
.
get_children
()
if
child
.
value
.
startswith
(
name
)
]
values
=
[
int
(
value
)
for
value
in
values
if
value
.
strip
()
.
isdigit
()]
count
=
max
(
values
)
+
1
if
values
else
1
return
'{} {}'
.
format
(
name
,
count
)
def
create_child
(
self
,
value
):
def
create_child
(
self
,
value
):
with
transaction
.
atomic
():
with
transaction
.
atomic
():
child_key
=
self
.
get_next_child_key
()
child_key
=
self
.
get_next_child_key
()
...
@@ -162,7 +183,7 @@ class Node(OrgModelMixin):
...
@@ -162,7 +183,7 @@ class Node(OrgModelMixin):
pattern
=
r'^{0}$|^{0}:'
.
format
(
self
.
key
)
pattern
=
r'^{0}$|^{0}:'
.
format
(
self
.
key
)
args
=
[]
args
=
[]
kwargs
=
{}
kwargs
=
{}
if
self
.
is_
default_node
():
if
self
.
is_
root
():
args
.
append
(
Q
(
nodes__key__regex
=
pattern
)
|
Q
(
nodes
=
None
))
args
.
append
(
Q
(
nodes__key__regex
=
pattern
)
|
Q
(
nodes
=
None
))
else
:
else
:
kwargs
[
'nodes__key__regex'
]
=
pattern
kwargs
[
'nodes__key__regex'
]
=
pattern
...
@@ -256,6 +277,26 @@ class Node(OrgModelMixin):
...
@@ -256,6 +277,26 @@ class Node(OrgModelMixin):
defaults
=
{
'value'
:
'Default'
}
defaults
=
{
'value'
:
'Default'
}
return
cls
.
objects
.
get_or_create
(
defaults
=
defaults
,
key
=
'1'
)
return
cls
.
objects
.
get_or_create
(
defaults
=
defaults
,
key
=
'1'
)
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
,
'title'
:
name
,
'pId'
:
self
.
parent_key
,
'isParent'
:
True
,
'open'
:
self
.
is_root
(),
'meta'
:
{
'node'
:
node_serializer
.
data
,
'type'
:
'node'
}
}
tree_node
=
TreeNode
(
**
data
)
return
tree_node
@classmethod
@classmethod
def
generate_fake
(
cls
,
count
=
100
):
def
generate_fake
(
cls
,
count
=
100
):
import
random
import
random
...
...
apps/assets/serializers/asset.py
View file @
dbdcdb72
...
@@ -9,6 +9,7 @@ from .system_user import AssetSystemUserSerializer
...
@@ -9,6 +9,7 @@ from .system_user import AssetSystemUserSerializer
__all__
=
[
__all__
=
[
'AssetSerializer'
,
'AssetGrantedSerializer'
,
'MyAssetGrantedSerializer'
,
'AssetSerializer'
,
'AssetGrantedSerializer'
,
'MyAssetGrantedSerializer'
,
'AssetAsNodeSerializer'
,
]
]
...
@@ -22,6 +23,13 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
...
@@ -22,6 +23,13 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
fields
=
'__all__'
fields
=
'__all__'
validators
=
[]
validators
=
[]
@classmethod
def
setup_eager_loading
(
cls
,
queryset
):
""" Perform necessary eager loading of data. """
queryset
=
queryset
.
prefetch_related
(
'labels'
,
'nodes'
)
\
.
select_related
(
'admin_user'
)
return
queryset
def
get_field_names
(
self
,
declared_fields
,
info
):
def
get_field_names
(
self
,
declared_fields
,
info
):
fields
=
super
()
.
get_field_names
(
declared_fields
,
info
)
fields
=
super
()
.
get_field_names
(
declared_fields
,
info
)
fields
.
extend
([
fields
.
extend
([
...
@@ -30,6 +38,12 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
...
@@ -30,6 +38,12 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
return
fields
return
fields
class
AssetAsNodeSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Asset
fields
=
[
'id'
,
'hostname'
,
'ip'
,
'port'
,
'platform'
,
'protocol'
]
class
AssetGrantedSerializer
(
serializers
.
ModelSerializer
):
class
AssetGrantedSerializer
(
serializers
.
ModelSerializer
):
"""
"""
被授权资产的数据结构
被授权资产的数据结构
...
...
apps/assets/serializers/node.py
View file @
dbdcdb72
...
@@ -8,76 +8,33 @@ from .asset import AssetGrantedSerializer
...
@@ -8,76 +8,33 @@ from .asset import AssetGrantedSerializer
__all__
=
[
__all__
=
[
'NodeSerializer'
,
"Node
GrantedSerializer"
,
"Node
AddChildrenSerializer"
,
'NodeSerializer'
,
"NodeAddChildrenSerializer"
,
"NodeAssetsSerializer"
,
"NodeAssetsSerializer"
,
]
]
class
NodeGrantedSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
):
"""
授权资产组
"""
assets_granted
=
AssetGrantedSerializer
(
many
=
True
,
read_only
=
True
)
assets_amount
=
serializers
.
SerializerMethodField
()
parent
=
serializers
.
SerializerMethodField
()
name
=
serializers
.
SerializerMethodField
()
class
Meta
:
model
=
Node
fields
=
[
'id'
,
'key'
,
'name'
,
'value'
,
'parent'
,
'assets_granted'
,
'assets_amount'
,
'org_id'
,
]
@staticmethod
def
get_assets_amount
(
obj
):
return
len
(
obj
.
assets_granted
)
@staticmethod
def
get_name
(
obj
):
return
obj
.
name
@staticmethod
def
get_parent
(
obj
):
return
obj
.
parent
.
id
class
NodeSerializer
(
serializers
.
ModelSerializer
):
class
NodeSerializer
(
serializers
.
ModelSerializer
):
assets_amount
=
serializers
.
IntegerField
()
assets_amount
=
serializers
.
IntegerField
(
read_only
=
True
)
tree_id
=
serializers
.
SerializerMethodField
()
tree_parent
=
serializers
.
SerializerMethodField
()
class
Meta
:
class
Meta
:
model
=
Node
model
=
Node
fields
=
[
fields
=
[
'id'
,
'key'
,
'value'
,
'assets_amount'
,
'id'
,
'key'
,
'value'
,
'assets_amount'
,
'org_id'
,
'is_node'
,
'org_id'
,
'tree_id'
,
'tree_parent'
,
]
]
read_only_fields
=
[
read_only_fields
=
[
'id'
,
'key'
,
'assets_amount'
,
'is_node'
,
'id'
,
'key'
,
'assets_amount'
,
'org_id'
,
'org_id'
,
]
]
list_serializer_class
=
BulkListSerializer
def
validate
(
self
,
data
):
def
validate_value
(
self
,
data
):
value
=
data
.
get
(
'value'
)
instance
=
self
.
instance
if
self
.
instance
else
Node
.
root
()
instance
=
self
.
instance
if
self
.
instance
else
Node
.
root
()
children
=
instance
.
parent
.
get_children
()
.
exclude
(
key
=
instance
.
key
)
children
=
instance
.
parent
.
get_children
()
.
exclude
(
key
=
instance
.
key
)
values
=
[
child
.
value
for
child
in
children
]
values
=
[
child
.
value
for
child
in
children
]
if
value
in
values
:
if
data
in
values
:
raise
serializers
.
ValidationError
(
raise
serializers
.
ValidationError
(
'The same level node name cannot be the same'
'The same level node name cannot be the same'
)
)
return
data
return
data
@staticmethod
def
get_tree_id
(
obj
):
return
obj
.
key
@staticmethod
def
get_tree_parent
(
obj
):
return
obj
.
parent_key
class
NodeAssetsSerializer
(
serializers
.
ModelSerializer
):
class
NodeAssetsSerializer
(
serializers
.
ModelSerializer
):
assets
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
Asset
.
objects
.
all
())
assets
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
Asset
.
objects
.
all
())
...
@@ -89,3 +46,4 @@ class NodeAssetsSerializer(serializers.ModelSerializer):
...
@@ -89,3 +46,4 @@ class NodeAssetsSerializer(serializers.ModelSerializer):
class
NodeAddChildrenSerializer
(
serializers
.
Serializer
):
class
NodeAddChildrenSerializer
(
serializers
.
Serializer
):
nodes
=
serializers
.
ListField
()
nodes
=
serializers
.
ListField
()
apps/assets/templates/assets/asset_list.html
View file @
dbdcdb72
This diff is collapsed.
Click to expand it.
apps/assets/urls/api_urls.py
View file @
dbdcdb72
...
@@ -53,6 +53,8 @@ urlpatterns = [
...
@@ -53,6 +53,8 @@ urlpatterns = [
path
(
'system-user/<uuid:pk>/cmd-filter-rules/'
,
path
(
'system-user/<uuid:pk>/cmd-filter-rules/'
,
api
.
SystemUserCommandFilterRuleListApi
.
as_view
(),
name
=
'system-user-cmd-filter-rule-list'
),
api
.
SystemUserCommandFilterRuleListApi
.
as_view
(),
name
=
'system-user-cmd-filter-rule-list'
),
path
(
'nodes/tree/'
,
api
.
NodeListAsTreeApi
.
as_view
(),
name
=
'node-tree'
),
path
(
'nodes/children/tree/'
,
api
.
NodeChildrenAsTreeApi
.
as_view
(),
name
=
'node-children-tree'
),
path
(
'nodes/<uuid:pk>/children/'
,
path
(
'nodes/<uuid:pk>/children/'
,
api
.
NodeChildrenApi
.
as_view
(),
name
=
'node-children'
),
api
.
NodeChildrenApi
.
as_view
(),
name
=
'node-children'
),
path
(
'nodes/children/'
,
api
.
NodeChildrenApi
.
as_view
(),
name
=
'node-children-2'
),
path
(
'nodes/children/'
,
api
.
NodeChildrenApi
.
as_view
(),
name
=
'node-children-2'
),
...
...
apps/assets/views/asset.py
View file @
dbdcdb72
...
@@ -216,7 +216,6 @@ class AssetExportView(LoginRequiredMixin, View):
...
@@ -216,7 +216,6 @@ class AssetExportView(LoginRequiredMixin, View):
return
HttpResponse
(
'Json object not valid'
,
status
=
400
)
return
HttpResponse
(
'Json object not valid'
,
status
=
400
)
if
not
assets_id
:
if
not
assets_id
:
print
(
node_id
)
node
=
get_object_or_none
(
Node
,
id
=
node_id
)
if
node_id
else
Node
.
root
()
node
=
get_object_or_none
(
Node
,
id
=
node_id
)
if
node_id
else
Node
.
root
()
assets
=
node
.
get_all_assets
()
assets
=
node
.
get_all_assets
()
for
asset
in
assets
:
for
asset
in
assets
:
...
...
apps/jumpserver/settings.py
View file @
dbdcdb72
...
@@ -356,6 +356,7 @@ FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o755
...
@@ -356,6 +356,7 @@ FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o755
# OTP settings
# OTP settings
OTP_ISSUER_NAME
=
CONFIG
.
OTP_ISSUER_NAME
OTP_ISSUER_NAME
=
CONFIG
.
OTP_ISSUER_NAME
OTP_VALID_WINDOW
=
CONFIG
.
OTP_VALID_WINDOW
# Auth LDAP settings
# Auth LDAP settings
AUTH_LDAP
=
False
AUTH_LDAP
=
False
...
...
apps/locale/zh/LC_MESSAGES/django.mo
View file @
dbdcdb72
No preview for this file type
apps/locale/zh/LC_MESSAGES/django.po
View file @
dbdcdb72
This diff is collapsed.
Click to expand it.
apps/perms/api.py
View file @
dbdcdb72
...
@@ -16,7 +16,7 @@ from orgs.utils import set_to_root_org
...
@@ -16,7 +16,7 @@ from orgs.utils import set_to_root_org
from
.utils
import
AssetPermissionUtil
from
.utils
import
AssetPermissionUtil
from
.models
import
AssetPermission
from
.models
import
AssetPermission
from
.hands
import
AssetGrantedSerializer
,
User
,
UserGroup
,
Asset
,
Node
,
\
from
.hands
import
AssetGrantedSerializer
,
User
,
UserGroup
,
Asset
,
Node
,
\
NodeGrantedSerializer
,
SystemUser
,
NodeSerializer
SystemUser
,
NodeSerializer
from
.
import
serializers
from
.
import
serializers
from
.mixins
import
AssetsFilterMixin
from
.mixins
import
AssetsFilterMixin
...
@@ -150,7 +150,7 @@ class UserGrantedNodesWithAssetsApi(AssetsFilterMixin, ListAPIView):
...
@@ -150,7 +150,7 @@ class UserGrantedNodesWithAssetsApi(AssetsFilterMixin, ListAPIView):
用户授权的节点并带着节点下资产的api
用户授权的节点并带着节点下资产的api
"""
"""
permission_classes
=
(
IsOrgAdminOrAppUser
,)
permission_classes
=
(
IsOrgAdminOrAppUser
,)
serializer_class
=
NodeGrantedSerializer
serializer_class
=
serializers
.
NodeGrantedSerializer
def
change_org_if_need
(
self
):
def
change_org_if_need
(
self
):
if
self
.
request
.
user
.
is_superuser
or
\
if
self
.
request
.
user
.
is_superuser
or
\
...
@@ -360,7 +360,7 @@ class UserGroupGrantedNodesApi(ListAPIView):
...
@@ -360,7 +360,7 @@ class UserGroupGrantedNodesApi(ListAPIView):
class
UserGroupGrantedNodesWithAssetsApi
(
ListAPIView
):
class
UserGroupGrantedNodesWithAssetsApi
(
ListAPIView
):
permission_classes
=
(
IsOrgAdmin
,)
permission_classes
=
(
IsOrgAdmin
,)
serializer_class
=
NodeGrantedSerializer
serializer_class
=
serializers
.
NodeGrantedSerializer
def
get_queryset
(
self
):
def
get_queryset
(
self
):
user_group_id
=
self
.
kwargs
.
get
(
'pk'
,
''
)
user_group_id
=
self
.
kwargs
.
get
(
'pk'
,
''
)
...
...
apps/perms/hands.py
View file @
dbdcdb72
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
from
common.permissions
import
AdminUserRequiredMixin
from
common.permissions
import
AdminUserRequiredMixin
from
users.models
import
User
,
UserGroup
from
users.models
import
User
,
UserGroup
from
assets.models
import
Asset
,
SystemUser
,
Node
from
assets.models
import
Asset
,
SystemUser
,
Node
from
assets.serializers
import
AssetGrantedSerializer
,
Node
GrantedSerializer
,
Node
Serializer
from
assets.serializers
import
AssetGrantedSerializer
,
NodeSerializer
apps/perms/serializers.py
View file @
dbdcdb72
...
@@ -83,6 +83,35 @@ class AssetPermissionNodeSerializer(serializers.ModelSerializer):
...
@@ -83,6 +83,35 @@ class AssetPermissionNodeSerializer(serializers.ModelSerializer):
return
obj
.
parent_key
return
obj
.
parent_key
class
NodeGrantedSerializer
(
serializers
.
ModelSerializer
):
"""
授权资产组
"""
assets_granted
=
AssetGrantedSerializer
(
many
=
True
,
read_only
=
True
)
assets_amount
=
serializers
.
SerializerMethodField
()
parent
=
serializers
.
SerializerMethodField
()
name
=
serializers
.
SerializerMethodField
()
class
Meta
:
model
=
Node
fields
=
[
'id'
,
'key'
,
'name'
,
'value'
,
'parent'
,
'assets_granted'
,
'assets_amount'
,
'org_id'
,
]
@staticmethod
def
get_assets_amount
(
obj
):
return
len
(
obj
.
assets_granted
)
@staticmethod
def
get_name
(
obj
):
return
obj
.
name
@staticmethod
def
get_parent
(
obj
):
return
obj
.
parent
.
id
class
GrantedNodeSerializer
(
serializers
.
ModelSerializer
):
class
GrantedNodeSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
class
Meta
:
model
=
Node
model
=
Node
...
...
apps/perms/templates/perms/asset_permission_list.html
View file @
dbdcdb72
...
@@ -78,58 +78,24 @@ var zTree, table, show = 0;
...
@@ -78,58 +78,24 @@ var zTree, table, show = 0;
function
onSelected
(
event
,
treeNode
)
{
function
onSelected
(
event
,
treeNode
)
{
setCookie
(
'node_selected'
,
treeNode
.
id
);
setCookie
(
'node_selected'
,
treeNode
.
id
);
var
url
=
table
.
ajax
.
url
();
var
url
=
table
.
ajax
.
url
();
if
(
treeNode
.
is_node
)
{
if
(
treeNode
.
meta
.
type
===
'node'
)
{
url
=
setUrlParam
(
url
,
'asset'
,
""
);
url
=
setUrlParam
(
url
,
'asset'
,
""
);
url
=
setUrlParam
(
url
,
'node'
,
treeNode
.
node_
id
)
url
=
setUrlParam
(
url
,
'node'
,
treeNode
.
meta
.
node
.
id
)
}
else
{
}
else
{
url
=
setUrlParam
(
url
,
'node'
,
""
);
url
=
setUrlParam
(
url
,
'node'
,
""
);
url
=
setUrlParam
(
url
,
'asset'
,
treeNode
.
node_
id
)
url
=
setUrlParam
(
url
,
'asset'
,
treeNode
.
meta
.
asset
.
id
)
}
}
setCookie
(
'node_selected'
,
treeNode
.
node_id
);
setCookie
(
'node_selected'
,
treeNode
.
node_id
);
table
.
ajax
.
url
(
url
);
table
.
ajax
.
url
(
url
);
table
.
ajax
.
reload
();
table
.
ajax
.
reload
();
}
}
function
selectQueryNode
()
{
var
query_node_id
=
$
.
getUrlParam
(
"node"
);
var
cookie_node_id
=
getCookie
(
'node_selected'
);
var
node
;
var
node_id
;
if
(
query_node_id
!==
null
)
{
node_id
=
query_node_id
}
else
if
(
cookie_node_id
!==
null
)
{
node_id
=
cookie_node_id
;
}
node
=
zTree
.
getNodesByParam
(
"id"
,
node_id
,
null
);
if
(
node
){
zTree
.
selectNode
(
node
[
0
]);
node
.
open
=
true
;
}
}
function
filter
(
treeId
,
parentNode
,
childNodes
)
{
$
.
each
(
childNodes
,
function
(
index
,
value
)
{
value
[
"node_id"
]
=
value
[
"id"
];
value
[
"id"
]
=
value
[
"tree_id"
];
if
(
value
[
"tree_id"
]
!==
value
[
"tree_parent"
])
{
value
[
"pId"
]
=
value
[
"tree_parent"
];
}
else
{
value
[
"isParent"
]
=
true
;
}
value
[
'name'
]
=
value
[
'value'
];
value
[
"iconSkin"
]
=
value
[
"is_node"
]
?
null
:
'file'
;
{
#
value
[
"pId"
]
=
value
[
"parent"
];
#
}
{
#
value
[
"name"
]
=
value
[
"value"
];
#
}
value
[
"isParent"
]
=
value
[
"is_node"
];
});
return
childNodes
;
}
function
beforeAsync
(
treeId
,
treeNode
)
{
function
beforeAsync
(
treeId
,
treeNode
)
{
return
treeNode
.
is_node
if
(
treeNode
)
{
return
treeNode
.
meta
.
type
===
'node'
}
return
true
}
}
function
makeLabel
(
data
)
{
function
makeLabel
(
data
)
{
...
@@ -235,9 +201,8 @@ function initTree() {
...
@@ -235,9 +201,8 @@ function initTree() {
},
},
async
:
{
async
:
{
enable
:
true
,
enable
:
true
,
url
:
"{% url 'api-assets:node-children-2' %}?assets=1&all="
,
url
:
"{% url 'api-assets:node-children-tree' %}?assets=1"
,
autoParam
:[
"node_id=id"
,
"name=n"
,
"level=lv"
],
autoParam
:[
"id=key"
,
"name=n"
,
"level=lv"
],
dataFilter
:
filter
,
type
:
'get'
type
:
'get'
},
},
callback
:
{
callback
:
{
...
@@ -245,25 +210,7 @@ function initTree() {
...
@@ -245,25 +210,7 @@ function initTree() {
beforeAsync
:
beforeAsync
beforeAsync
:
beforeAsync
}
}
};
};
zTree
=
$
.
fn
.
zTree
.
init
(
$
(
"#assetTree"
),
setting
);
var
zNodes
=
[];
$
.
get
(
"{% url 'api-assets:node-children-2' %}?assets=1"
,
function
(
data
,
status
){
$
.
each
(
data
,
function
(
index
,
value
)
{
value
[
"node_id"
]
=
value
[
"id"
];
value
[
"id"
]
=
value
[
"tree_id"
];
if
(
value
[
"tree_id"
]
!==
value
[
"tree_parent"
])
{
value
[
"pId"
]
=
value
[
"tree_parent"
];
}
value
[
"isParent"
]
=
value
[
"is_node"
];
value
[
'name'
]
=
value
[
'value'
];
value
[
"iconSkin"
]
=
value
[
"is_node"
]
?
null
:
'file'
;
});
zNodes
=
data
;
$
.
fn
.
zTree
.
init
(
$
(
"#assetTree"
),
setting
,
zNodes
);
zTree
=
$
.
fn
.
zTree
.
getZTreeObj
(
"assetTree"
);
var
root
=
zTree
.
getNodes
()[
0
];
zTree
.
expandNode
(
root
);
});
}
}
function
toggle
()
{
function
toggle
()
{
...
@@ -299,10 +246,10 @@ $(document).ready(function(){
...
@@ -299,10 +246,10 @@ $(document).ready(function(){
var
_nodes
=
[];
var
_nodes
=
[];
var
_assets
=
[];
var
_assets
=
[];
$
.
each
(
nodes
,
function
(
id
,
node
)
{
$
.
each
(
nodes
,
function
(
id
,
node
)
{
if
(
node
.
is_node
)
{
if
(
node
.
meta
.
type
===
'node'
)
{
_nodes
.
push
(
node
.
node_
id
)
_nodes
.
push
(
node
.
meta
.
node
.
id
)
}
else
{
}
else
{
_assets
.
push
(
node
.
node_
id
)
_assets
.
push
(
node
.
meta
.
asset
.
id
)
}
}
});
});
url
+=
"?assets="
+
_assets
.
join
(
","
)
+
"&nodes="
+
_nodes
.
join
(
","
);
url
+=
"?assets="
+
_assets
.
join
(
","
)
+
"&nodes="
+
_nodes
.
join
(
","
);
...
...
apps/users/utils.py
View file @
dbdcdb72
...
@@ -292,7 +292,8 @@ def check_otp_code(otp_secret_key, otp_code):
...
@@ -292,7 +292,8 @@ def check_otp_code(otp_secret_key, otp_code):
if
not
otp_secret_key
or
not
otp_code
:
if
not
otp_secret_key
or
not
otp_code
:
return
False
return
False
totp
=
pyotp
.
TOTP
(
otp_secret_key
)
totp
=
pyotp
.
TOTP
(
otp_secret_key
)
return
totp
.
verify
(
otp_code
)
otp_valid_window
=
settings
.
OTP_VALID_WINDOW
or
0
return
totp
.
verify
(
otp
=
otp_code
,
valid_window
=
otp_valid_window
)
def
get_password_check_rules
():
def
get_password_check_rules
():
...
...
config_docker.py
View file @
dbdcdb72
...
@@ -100,6 +100,9 @@ class Config:
...
@@ -100,6 +100,9 @@ class Config:
}
}
AUTH_LDAP_START_TLS
=
False
AUTH_LDAP_START_TLS
=
False
#
# OTP_VALID_WINDOW = 0
def
__init__
(
self
):
def
__init__
(
self
):
pass
pass
...
@@ -200,6 +203,10 @@ class DockerConfig(Config):
...
@@ -200,6 +203,10 @@ class DockerConfig(Config):
AUTH_LDAP_START_TLS
=
False
AUTH_LDAP_START_TLS
=
False
#
OTP_VALID_WINDOW
=
int
(
os
.
environ
.
get
(
"OTP_VALID_WINDOW"
))
if
os
.
environ
.
get
(
"OTP_VALID_WINDOW"
)
else
0
# Default using Config settings, you can write if/else for different env
# Default using Config settings, you can write if/else for different env
config
=
DockerConfig
()
config
=
DockerConfig
()
config_example.py
View file @
dbdcdb72
...
@@ -90,6 +90,9 @@ class Config:
...
@@ -90,6 +90,9 @@ class Config:
# AUTH_OPENID_CLIENT_ID = 'client-id'
# AUTH_OPENID_CLIENT_ID = 'client-id'
# AUTH_OPENID_CLIENT_SECRET = 'client-secret'
# AUTH_OPENID_CLIENT_SECRET = 'client-secret'
#
# OTP_VALID_WINDOW = 0
def
__init__
(
self
):
def
__init__
(
self
):
pass
pass
...
...
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