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
24bdaeca
Unverified
Commit
24bdaeca
authored
Apr 11, 2018
by
老广
Committed by
GitHub
Apr 11, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1185 from jumpserver/dev
授权规则优化,支持细颗粒授权
parents
d2d10b59
8b3b517b
Hide whitespace changes
Inline
Side-by-side
Showing
48 changed files
with
1641 additions
and
813 deletions
+1641
-813
__init__.py
apps/__init__.py
+1
-1
asset.py
apps/assets/api/asset.py
+3
-1
node.py
apps/assets/api/node.py
+75
-7
asset.py
apps/assets/forms/asset.py
+11
-5
asset.py
apps/assets/models/asset.py
+5
-1
node.py
apps/assets/models/node.py
+5
-0
user.py
apps/assets/models/user.py
+6
-10
node.py
apps/assets/serializers/node.py
+1
-1
system_user.py
apps/assets/serializers/system_user.py
+1
-1
signals_handler.py
apps/assets/signals_handler.py
+28
-15
tasks.py
apps/assets/tasks.py
+8
-43
asset_create.html
apps/assets/templates/assets/asset_create.html
+1
-1
asset_list.html
apps/assets/templates/assets/asset_list.html
+2
-2
asset_update.html
apps/assets/templates/assets/asset_update.html
+1
-1
user_asset_list.html
apps/assets/templates/assets/user_asset_list.html
+142
-51
api_urls.py
apps/assets/urls/api_urls.py
+2
-0
fields.py
apps/common/fields.py
+5
-0
utils.py
apps/common/utils.py
+19
-4
django.mo
apps/i18n/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/i18n/zh/LC_MESSAGES/django.po
+254
-223
api.py
apps/perms/api.py
+164
-59
forms.py
apps/perms/forms.py
+49
-12
models.py
apps/perms/models.py
+34
-41
serializers.py
apps/perms/serializers.py
+18
-24
signals_handler.py
apps/perms/signals_handler.py
+31
-7
asset_permission_asset.html
apps/perms/templates/perms/asset_permission_asset.html
+19
-19
asset_permission_create_update.html
...perms/templates/perms/asset_permission_create_update.html
+20
-22
asset_permission_detail.html
apps/perms/templates/perms/asset_permission_detail.html
+25
-21
asset_permission_list.html
apps/perms/templates/perms/asset_permission_list.html
+182
-96
asset_permission_user.html
apps/perms/templates/perms/asset_permission_user.html
+3
-3
api_urls.py
apps/perms/urls/api_urls.py
+42
-9
views_urls.py
apps/perms/urls/views_urls.py
+3
-3
utils.py
apps/perms/utils.py
+190
-3
views.py
apps/perms/views.py
+98
-19
awesome.css
apps/static/css/plugins/ztree/awesomeStyle/awesome.css
+33
-9
awesome.less
apps/static/css/plugins/ztree/awesomeStyle/awesome.less
+21
-17
jumpserver.js
apps/static/js/jumpserver.js
+8
-2
command_list.html
apps/terminal/templates/terminal/command_list.html
+2
-2
api.py
apps/users/api.py
+8
-3
forms.py
apps/users/forms.py
+24
-25
user.py
apps/users/models/user.py
+23
-4
signals_handler.py
apps/users/signals_handler.py
+20
-11
user_granted_asset.html
apps/users/templates/users/user_granted_asset.html
+14
-15
user_group_granted_asset.html
apps/users/templates/users/user_group_granted_asset.html
+12
-13
user_profile.html
apps/users/templates/users/user_profile.html
+1
-1
login.py
apps/users/views/login.py
+2
-6
user.py
apps/users/views/user.py
+1
-0
2018_04_11_migrate_permissions.sh
utils/2018_04_11_migrate_permissions.sh
+24
-0
No files found.
apps/__init__.py
View file @
24bdaeca
...
...
@@ -2,4 +2,4 @@
# -*- coding: utf-8 -*-
#
__version__
=
"1.
0
.0"
__version__
=
"1.
3
.0"
apps/assets/api/asset.py
View file @
24bdaeca
...
...
@@ -50,7 +50,9 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
if
node_id
:
node
=
get_object_or_404
(
Node
,
id
=
node_id
)
if
not
node
.
is_root
():
queryset
=
queryset
.
filter
(
nodes__key__startswith
=
node
.
key
)
.
distinct
()
queryset
=
queryset
.
filter
(
nodes__key__regex
=
'{}(:[0-9]+)*$'
.
format
(
node
.
key
),
)
.
distinct
()
return
queryset
...
...
apps/assets/api/node.py
View file @
24bdaeca
...
...
@@ -30,6 +30,7 @@ from .. import serializers
logger
=
get_logger
(
__file__
)
__all__
=
[
'NodeViewSet'
,
'NodeChildrenApi'
,
'NodeAssetsApi'
,
'NodeWithAssetsApi'
,
'NodeAddAssetsApi'
,
'NodeRemoveAssetsApi'
,
'NodeAddChildrenApi'
,
'RefreshNodeHardwareInfoApi'
,
'TestNodeConnectiveApi'
...
...
@@ -47,6 +48,34 @@ class NodeViewSet(BulkModelViewSet):
serializer
.
save
()
class
NodeWithAssetsApi
(
generics
.
ListAPIView
):
permission_classes
=
(
IsSuperUser
,)
serializers
=
serializers
.
NodeSerializer
def
get_node
(
self
):
pk
=
self
.
kwargs
.
get
(
'pk'
)
or
self
.
request
.
query_params
.
get
(
'node'
)
if
not
pk
:
node
=
Node
.
root
()
else
:
node
=
get_object_or_404
(
Node
,
pk
)
return
node
def
get_queryset
(
self
):
queryset
=
[]
node
=
self
.
get_node
()
children
=
node
.
get_children
()
assets
=
node
.
get_assets
()
queryset
.
extend
(
list
(
children
))
for
asset
in
assets
:
node
=
Node
()
node
.
id
=
asset
.
id
node
.
parent
=
node
.
id
node
.
value
=
asset
.
hostname
queryset
.
append
(
node
)
return
queryset
class
NodeChildrenApi
(
mixins
.
ListModelMixin
,
generics
.
CreateAPIView
):
queryset
=
Node
.
objects
.
all
()
permission_classes
=
(
IsSuperUser
,)
...
...
@@ -69,14 +98,54 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
status
=
201
,
)
def
get_object
(
self
):
pk
=
self
.
kwargs
.
get
(
'pk'
)
or
self
.
request
.
query_params
.
get
(
'id'
)
if
not
pk
:
node
=
Node
.
root
()
else
:
node
=
get_object_or_404
(
Node
,
pk
=
pk
)
return
node
def
get_queryset
(
self
):
queryset
=
[]
query_all
=
self
.
request
.
query_params
.
get
(
"all"
)
query_assets
=
self
.
request
.
query_params
.
get
(
'assets'
)
node
=
self
.
get_object
()
if
node
==
Node
.
root
():
queryset
.
append
(
node
)
if
query_all
:
children
=
node
.
get_all_children
()
else
:
children
=
node
.
get_children
()
queryset
.
extend
(
list
(
children
))
if
query_assets
:
assets
=
node
.
get_assets
()
for
asset
in
assets
:
node_fake
=
Node
()
node_fake
.
id
=
asset
.
id
node_fake
.
parent
=
node
node_fake
.
value
=
asset
.
hostname
node_fake
.
is_asset
=
True
queryset
.
append
(
node_fake
)
return
queryset
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
instance
=
self
.
get_object
()
if
self
.
request
.
query_params
.
get
(
"all"
):
children
=
instance
.
get_all_children
()
return
super
()
.
list
(
request
,
*
args
,
**
kwargs
)
class
NodeAssetsApi
(
generics
.
ListAPIView
):
permission_classes
=
(
IsSuperUser
,)
serializer_class
=
serializers
.
AssetSerializer
def
get_queryset
(
self
):
node_id
=
self
.
kwargs
.
get
(
'pk'
)
query_all
=
self
.
request
.
query_params
.
get
(
'all'
)
instance
=
get_object_or_404
(
Node
,
pk
=
node_id
)
if
query_all
:
return
instance
.
get_all_assets
()
else
:
children
=
instance
.
get_children
()
response
=
[{
"id"
:
node
.
id
,
"key"
:
node
.
key
,
"value"
:
node
.
value
}
for
node
in
children
]
return
Response
(
response
,
status
=
200
)
return
instance
.
get_assets
()
class
NodeAddChildrenApi
(
generics
.
UpdateAPIView
):
...
...
@@ -146,4 +215,3 @@ class TestNodeConnectiveApi(APIView):
task_name
=
_
(
"测试节点下资产是否可连接: {}"
.
format
(
node
.
name
))
task
=
test_asset_connectability_util
.
delay
(
assets
,
task_name
=
task_name
)
return
Response
({
"task"
:
task
.
id
})
apps/assets/forms/asset.py
View file @
24bdaeca
...
...
@@ -27,13 +27,16 @@ class AssetCreateForm(forms.ModelForm):
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Admin user'
)
}),
'labels'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Label
s
'
)
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Label'
)
}),
'port'
:
forms
.
TextInput
(),
'domain'
:
forms
.
Select
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Domain'
)
}),
}
labels
=
{
'nodes'
:
_
(
"Node"
),
}
help_texts
=
{
'hostname'
:
'* required'
,
'ip'
:
'* required'
,
...
...
@@ -57,19 +60,22 @@ class AssetUpdateForm(forms.ModelForm):
]
widgets
=
{
'nodes'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Node
s
'
)
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Node'
)
}),
'admin_user'
:
forms
.
Select
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Admin user'
)
}),
'labels'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Label
s
'
)
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Label'
)
}),
'port'
:
forms
.
TextInput
(),
'domain'
:
forms
.
Select
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Domain'
)
}),
}
labels
=
{
'nodes'
:
_
(
"Node"
),
}
help_texts
=
{
'hostname'
:
'* required'
,
'ip'
:
'* required'
,
...
...
@@ -116,10 +122,10 @@ class AssetBulkUpdateForm(forms.ModelForm):
]
widgets
=
{
'labels'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'
Select labels
'
)}
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'
Label
'
)}
),
'nodes'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'
Select nodes
'
)}
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'
Node
'
)}
),
}
...
...
apps/assets/models/asset.py
View file @
24bdaeca
...
...
@@ -84,7 +84,7 @@ class Asset(models.Model):
comment
=
models
.
TextField
(
max_length
=
128
,
default
=
''
,
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
def
__str__
(
self
):
return
self
.
hostname
return
'{0.hostname}({0.ip})'
.
format
(
self
)
@property
def
is_valid
(
self
):
...
...
@@ -101,6 +101,10 @@ class Asset(models.Model):
else
:
return
False
def
get_nodes
(
self
):
from
.node
import
Node
return
self
.
nodes
.
all
()
or
[
Node
.
root
()]
@property
def
hardware_info
(
self
):
if
self
.
cpu_count
:
...
...
apps/assets/models/node.py
View file @
24bdaeca
...
...
@@ -16,6 +16,8 @@ class Node(models.Model):
child_mark
=
models
.
IntegerField
(
default
=
0
)
date_create
=
models
.
DateTimeField
(
auto_now_add
=
True
)
is_asset
=
False
def
__str__
(
self
):
return
self
.
value
...
...
@@ -73,6 +75,9 @@ class Node(models.Model):
assets
=
Asset
.
objects
.
filter
(
nodes__in
=
nodes
)
return
assets
def
has_assets
(
self
):
return
self
.
get_all_assets
()
def
get_all_active_assets
(
self
):
return
self
.
get_all_assets
()
.
filter
(
is_active
=
True
)
...
...
apps/assets/models/user.py
View file @
24bdaeca
...
...
@@ -3,6 +3,7 @@
#
import
logging
import
uuid
from
django.core.cache
import
cache
from
django.db
import
models
...
...
@@ -100,14 +101,15 @@ class SystemUser(AssetUser):
)
nodes
=
models
.
ManyToManyField
(
'assets.Node'
,
blank
=
True
,
verbose_name
=
_
(
"Nodes"
))
assets
=
models
.
ManyToManyField
(
'assets.Asset'
,
blank
=
True
,
verbose_name
=
_
(
"Assets"
))
priority
=
models
.
IntegerField
(
default
=
10
,
verbose_name
=
_
(
"Priority"
))
protocol
=
models
.
CharField
(
max_length
=
16
,
choices
=
PROTOCOL_CHOICES
,
default
=
'ssh'
,
verbose_name
=
_
(
'Protocol'
))
auto_push
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
'Auto push'
))
sudo
=
models
.
TextField
(
default
=
'/
sbin/ifconfig
'
,
verbose_name
=
_
(
'Sudo'
))
sudo
=
models
.
TextField
(
default
=
'/
bin/whoami
'
,
verbose_name
=
_
(
'Sudo'
))
shell
=
models
.
CharField
(
max_length
=
64
,
default
=
'/bin/bash'
,
verbose_name
=
_
(
'Shell'
))
def
__str__
(
self
):
return
self
.
name
return
'{0.name}({0.username})'
.
format
(
self
)
def
to_json
(
self
):
return
{
...
...
@@ -119,11 +121,8 @@ class SystemUser(AssetUser):
'auto_push'
:
self
.
auto_push
,
}
@property
def
assets
(
self
):
assets
=
set
()
for
node
in
self
.
nodes
.
all
():
assets
.
update
(
set
(
node
.
get_all_assets
()))
def
get_assets
(
self
):
assets
=
set
(
self
.
assets
.
all
())
return
assets
@property
...
...
@@ -168,6 +167,3 @@ class SystemUser(AssetUser):
except
IntegrityError
:
print
(
'Error continue'
)
continue
apps/assets/serializers/node.py
View file @
24bdaeca
...
...
@@ -42,7 +42,7 @@ class NodeSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
Node
fields
=
[
'id'
,
'key'
,
'value'
,
'parent'
,
'assets_amount'
]
fields
=
[
'id'
,
'key'
,
'value'
,
'parent'
,
'assets_amount'
,
'is_asset'
]
list_serializer_class
=
BulkListSerializer
@staticmethod
...
...
apps/assets/serializers/system_user.py
View file @
24bdaeca
...
...
@@ -34,7 +34,7 @@ class SystemUserSerializer(serializers.ModelSerializer):
@staticmethod
def
get_assets_amount
(
obj
):
return
len
(
obj
.
assets
)
return
len
(
obj
.
get_assets
()
)
class
SystemUserAuthSerializer
(
AuthSerializer
):
...
...
apps/assets/signals_handler.py
View file @
24bdaeca
# -*- coding: utf-8 -*-
#
from
collections
import
defaultdict
from
django.db.models.signals
import
post_save
,
m2m_changed
from
django.dispatch
import
receiver
from
common.utils
import
get_logger
from
.models
import
Asset
,
SystemUser
,
Node
from
.tasks
import
update_assets_hardware_info_util
,
\
test_asset_connectability_util
,
push_system_user_to_node
,
\
push_node_system_users_to_asset
test_asset_connectability_util
,
push_system_user_to_assets
logger
=
get_logger
(
__file__
)
...
...
@@ -31,7 +30,6 @@ def set_asset_root_node(asset):
@receiver
(
post_save
,
sender
=
Asset
,
dispatch_uid
=
"my_unique_identifier"
)
def
on_asset_created_or_update
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
set_asset_root_node
(
instance
)
if
created
:
logger
.
info
(
"Asset `{}` create signal received"
.
format
(
instance
))
update_asset_hardware_info_on_created
(
instance
)
...
...
@@ -41,25 +39,39 @@ def on_asset_created_or_update(sender, instance=None, created=False, **kwargs):
@receiver
(
post_save
,
sender
=
SystemUser
,
dispatch_uid
=
"my_unique_identifier"
)
def
on_system_user_update
(
sender
,
instance
=
None
,
created
=
True
,
**
kwargs
):
if
instance
and
not
created
:
for
node
in
instance
.
nodes
.
all
():
push_system_user_to_node
(
instance
,
node
)
logger
.
info
(
"System user `{}` update signal received"
.
format
(
instance
))
assets
=
instance
.
assets
.
all
()
push_system_user_to_assets
.
delay
(
instance
,
assets
)
@receiver
(
m2m_changed
,
sender
=
SystemUser
.
nodes
.
through
)
def
on_system_user_node_change
(
sender
,
instance
=
None
,
**
kwargs
):
def
on_system_user_nodes_change
(
sender
,
instance
=
None
,
**
kwargs
):
if
instance
and
kwargs
[
"action"
]
==
"post_add"
:
assets
=
set
()
nodes
=
kwargs
[
'model'
]
.
objects
.
filter
(
pk__in
=
kwargs
[
'pk_set'
])
for
node
in
nodes
:
assets
.
update
(
set
(
node
.
get_all_assets
()))
instance
.
assets
.
add
(
*
tuple
(
assets
))
@receiver
(
m2m_changed
,
sender
=
SystemUser
.
assets
.
through
)
def
on_system_user_assets_change
(
sender
,
instance
=
None
,
**
kwargs
):
if
instance
and
kwargs
[
"action"
]
==
"post_add"
:
for
pk
in
kwargs
[
'pk_set'
]:
node
=
kwargs
[
'model'
]
.
objects
.
get
(
pk
=
pk
)
push_system_user_to_node
(
instance
,
node
)
assets
=
kwargs
[
'model'
]
.
objects
.
filter
(
pk__in
=
kwargs
[
'pk_set'
])
push_system_user_to_assets
(
instance
,
assets
)
@receiver
(
m2m_changed
,
sender
=
Asset
.
nodes
.
through
)
def
on_asset_node_changed
(
sender
,
instance
=
None
,
**
kwargs
):
if
isinstance
(
instance
,
Asset
)
and
kwargs
[
'action'
]
==
'post_add'
:
logger
.
debug
(
"Asset node change signal received"
)
for
pk
in
kwargs
[
'pk_set'
]:
node
=
kwargs
[
'model'
]
.
objects
.
get
(
pk
=
pk
)
push_node_system_users_to_asset
(
node
,
[
instance
])
nodes
=
kwargs
[
'model'
]
.
objects
.
filter
(
pk__in
=
kwargs
[
'pk_set'
])
system_users_assets
=
defaultdict
(
set
)
system_users
=
SystemUser
.
objects
.
filter
(
nodes__in
=
nodes
)
for
system_user
in
system_users
:
system_users_assets
[
system_user
]
.
update
({
instance
})
for
system_user
,
assets
in
system_users_assets
.
items
():
system_user
.
assets
.
add
(
*
tuple
(
assets
))
@receiver
(
m2m_changed
,
sender
=
Asset
.
nodes
.
through
)
...
...
@@ -67,5 +79,6 @@ def on_node_assets_changed(sender, instance=None, **kwargs):
if
isinstance
(
instance
,
Node
)
and
kwargs
[
'action'
]
==
'post_add'
:
logger
.
debug
(
"Node assets change signal received"
)
assets
=
kwargs
[
'model'
]
.
objects
.
filter
(
pk__in
=
kwargs
[
'pk_set'
])
push_node_system_users_to_asset
(
instance
,
assets
)
system_users
=
SystemUser
.
objects
.
filter
(
nodes
=
instance
)
for
system_user
in
system_users
:
system_user
.
assets
.
add
(
*
tuple
(
assets
))
apps/assets/tasks.py
View file @
24bdaeca
...
...
@@ -276,7 +276,7 @@ def test_system_user_connectability_util(system_user, task_name):
:return:
"""
from
ops.utils
import
update_or_create_ansible_task
assets
=
system_user
.
assets
assets
=
system_user
.
get_assets
()
hosts
=
[
asset
.
hostname
for
asset
in
assets
if
asset
.
is_active
and
asset
.
is_unixlike
()]
tasks
=
const
.
TEST_SYSTEM_USER_CONN_TASKS
if
not
hosts
:
...
...
@@ -386,52 +386,17 @@ def push_system_user_util(system_users, assets, task_name):
return
task
.
run
()
def
get_node_push_system_user_task_name
(
system_user
,
node
):
# return _("Push system user to node: {} => {}").format(
return
_
(
"推送系统用户到节点资产: {} => {}"
)
.
format
(
system_user
.
name
,
node
.
value
)
@shared_task
def
push_system_user_to_node
(
system_user
,
node
):
logger
.
info
(
"Start push system user node: {} => {}"
.
format
(
system_user
.
name
,
node
.
value
))
assets
=
node
.
get_all_assets
()
task_name
=
get_node_push_system_user_task_name
(
system_user
,
node
)
push_system_user_util
([
system_user
],
assets
,
task_name
)
@shared_task
def
push_system_user_related_nodes
(
system_user
):
if
not
system_user
.
is_need_push
():
msg
=
"push system user `{}` passed, may be not auto push or ssh "
\
"protocol is not ssh"
.
format
(
system_user
.
name
)
logger
.
info
(
msg
)
return
nodes
=
system_user
.
nodes
.
all
()
for
node
in
nodes
:
push_system_user_to_node
(
system_user
,
node
)
@shared_task
def
push_system_user_to_assets_manual
(
system_user
):
push_system_user_related_nodes
(
system_user
)
assets
=
system_user
.
get_assets
()
task_name
=
"推送系统用户到入资产: {}"
.
format
(
system_user
.
name
)
return
push_system_user_util
([
system_user
],
assets
,
task_name
=
task_name
)
def
push_node_system_users_to_asset
(
node
,
assets
):
system_users
=
[]
nodes
=
node
.
ancestor_with_node
# 获取该节点所有父节点有的系统用户, 然后推送
for
n
in
nodes
:
system_users
.
extend
(
list
(
n
.
systemuser_set
.
all
()))
if
system_users
:
# task_name = _("Push system users to node: {}").format(node.value)
task_name
=
_
(
"推送节点系统用户到新加入资产中: {}"
)
.
format
(
node
.
valu
e
)
push_system_user_util
.
delay
(
system_users
,
assets
,
task_name
)
@shared_task
def
push_system_user_to_assets
(
system_user
,
assets
):
task_name
=
_
(
"推送系统用户到入资产: {}"
)
.
format
(
system_user
.
nam
e
)
return
push_system_user_util
.
delay
([
system_user
]
,
assets
,
task_name
)
# @shared_task
...
...
apps/assets/templates/assets/asset_create.html
View file @
24bdaeca
...
...
@@ -34,7 +34,7 @@
<div
class=
"form-group {% if form.errors.labels %} has-error {% endif %}"
>
<label
for=
"{{ form.labels.id_for_label }}"
class=
"col-md-2 control-label"
>
{% trans 'Label' %}
</label>
<div
class=
"col-md-9"
>
<select
name=
"labels"
class=
"select2 labels"
data-placeholder=
"{% trans '
Select labels
' %}"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
id=
"{{ form.labels.id_for_label }}"
>
<select
name=
"labels"
class=
"select2 labels"
data-placeholder=
"{% trans '
Label
' %}"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
id=
"{{ form.labels.id_for_label }}"
>
{% for name, labels in form.labels.field.queryset|group_labels %}
<optgroup
label=
"{{ name }}"
>
{% for label in labels %}
...
...
apps/assets/templates/assets/asset_list.html
View file @
24bdaeca
...
...
@@ -41,9 +41,9 @@
{% block content %}
<div
class=
"wrapper wrapper-content"
>
<div
class=
"row"
>
<div
class=
"col-lg-3"
id=
"split-left"
>
<div
class=
"col-lg-3"
id=
"split-left"
style=
"padding-left: 3px"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-content mailbox-content"
style=
"padding-top: 0"
>
<div
class=
"ibox-content mailbox-content"
style=
"padding-top: 0
;padding-left: 1px
"
>
<div
class=
"file-manager "
>
<div
id=
"assetTree"
class=
"ztree"
>
</div>
...
...
apps/assets/templates/assets/asset_update.html
View file @
24bdaeca
...
...
@@ -39,7 +39,7 @@
<div
class=
"form-group"
>
<label
for=
"{{ form.labels.id_for_label }}"
class=
"col-md-2 control-label"
>
{% trans 'Label' %}
</label>
<div
class=
"col-md-9"
>
<select
name=
"labels"
class=
"select2 labels"
data-placeholder=
"
Select labels
"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
id=
"{{ form.labels.id_for_label }}"
>
<select
name=
"labels"
class=
"select2 labels"
data-placeholder=
"
{% trans 'Label' %}
"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
id=
"{{ form.labels.id_for_label }}"
>
{% for name, labels in form.labels.field.queryset|group_labels %}
<optgroup
label=
"{{ name }}"
>
{% for label in labels %}
...
...
apps/assets/templates/assets/user_asset_list.html
View file @
24bdaeca
{% extends '_base_list.html' %}
{% load i18n %}
{% extends 'base.html' %}
{% load static %}
{% block custom_head_css_js %}
<link
href=
"{% static 'css/plugins/select2/select2.min.css' %}"
rel=
"stylesheet"
>
<script
src=
"{% static 'js/plugins/select2/select2.full.min.js' %}"
></script>
{% load i18n %}
{% block custom_head_css_js %}
<link
href=
"{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}"
rel=
"stylesheet"
>
<script
type=
"text/javascript"
src=
"{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"
></script>
<script
src=
"{% static 'js/jquery.form.min.js' %}"
></script>
{% endblock %}
{% block content_left_head %}{% endblock %}
{% block table_search %}
{% endblock %}
{% block content %}
<div
class=
"wrapper wrapper-content"
>
<div
class=
"row"
>
<div
class=
"col-lg-3"
id=
"split-left"
style=
"padding-left: 3px"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-content mailbox-content"
style=
"padding-top: 0;padding-left: 1px"
>
<div
class=
"file-manager "
>
<div
id=
"assetTree"
class=
"ztree"
>
</div>
{% block table_container %}
<table
class=
"table table-striped table-bordered table-hover "
id=
"asset_list_table"
>
<thead>
<tr>
<th
class=
"text-center"
><input
type=
"checkbox"
class=
"ipt_check_all"
></th>
<th
class=
"text-center"
>
{% trans 'Hostname' %}
</th>
<th
class=
"text-center"
>
{% trans 'IP' %}
</th>
<th
class=
"text-center"
>
{% trans 'Port' %}
</th>
<th
class=
"text-center"
>
{% trans 'Hardware' %}
</th>
<th
class=
"text-center"
>
{% trans 'Active' %}
</th>
<th
class=
"text-center"
>
{% trans 'Connective' %}
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div
class=
"clearfix"
></div>
</div>
</div>
</div>
</div>
<div
class=
"col-lg-9 animated fadeInRight"
id=
"split-right"
>
<div
class=
"tree-toggle"
>
<div
class=
"btn btn-sm btn-primary tree-toggle-btn"
onclick=
"toggle()"
>
<i
class=
"fa fa-angle-left fa-x"
id=
"toggle-icon"
></i>
</div>
</div>
<div
class=
"mail-box-header"
>
<div
class=
"btn-group"
style=
"float: right"
>
<button
data-toggle=
"dropdown"
class=
"btn btn-default btn-sm dropdown-toggle"
>
{% trans 'Label' %}
<span
class=
"caret"
></span></button>
<ul
class=
"dropdown-menu labels"
>
{% for label in labels %}
<li><a
style=
"font-weight: bolder"
>
{{ label.name }}:{{ label.value }}
</a></li>
{% endfor %}
</ul>
</div>
<table
class=
"table table-striped table-bordered table-hover "
id=
"user_assets_table"
style=
"width: 100%"
>
<thead>
<tr>
<th
class=
"text-center"
><input
type=
"checkbox"
class=
"ipt_check_all"
></th>
<th
class=
"text-center"
>
{% trans 'Hostname' %}
</th>
<th
class=
"text-center"
>
{% trans 'IP' %}
</th>
<th
class=
"text-center"
>
{% trans 'Active' %}
</th>
<th
class=
"text-center"
>
{% trans 'System users' %}
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/jquery.form.min.js' %}"
></script>
<script
type=
"text/javascript"
>
<script>
var
zTree
,
rMenu
,
asset_table
;
var
inited
=
false
;
var
url
;
function
initTable
()
{
if
(
inited
){
return
}
else
{
inited
=
true
;
}
var
options
=
{
ele
:
$
(
'#
asset_list
_table'
),
ele
:
$
(
'#
user_assets
_table'
),
columnDefs
:
[
{
targets
:
1
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
{
%
url
'assets:asset-detail'
pk
=
DEFAULT_PK
as
the_url
%
}
var
detail_btn
=
'<a href="{{ the_url }}">'
+
cellData
+
'</a>'
;
$
(
td
).
html
(
detail_btn
.
replace
(
'{{ DEFAULT_PK }}'
,
rowData
.
id
));
}},
{
targets
:
5
,
createdCell
:
function
(
td
,
cellData
)
{
{
targets
:
3
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
!
cellData
)
{
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
}
else
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
}},
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
cellData
==
'Unknown'
){
$
(
td
).
html
(
'<i class="fa fa-circle text-warning"></i>'
)
}
else
if
(
!
cellData
)
{
$
(
td
).
html
(
'<i class="fa fa-circle text-danger"></i>'
)
}
else
{
$
(
td
).
html
(
'<i class="fa fa-circle text-navy"></i>'
)
}
}},
{
#
{
targets
:
9
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
#
}
{
#
var
conn_btn
=
'<a href="{% url "terminal:web-terminal" %}?id={{ DEFAULT_PK }}" class="btn btn-xs btn-info">{% trans "Connect" %}</a>'
.
replace
(
"{{ DEFAULT_PK }}"
,
cellData
);
#
}
{
#
$
(
td
).
html
(
conn_btn
)
#
}
{
#
}}
#
}
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
)
{
var
users
=
[];
$
.
each
(
cellData
,
function
(
id
,
data
)
{
users
.
push
(
data
.
name
);
});
$
(
td
).
html
(
users
.
join
(
', '
))
}}
],
ajax_url
:
'{% url "api-assets:user-asset-list" %}'
,
ajax_url
:
url
,
columns
:
[
{
data
:
"id"
},
{
data
:
"hostname"
},
{
data
:
"ip"
},
{
data
:
"port"
},
{
data
:
"
hardware_info"
},
{
data
:
"is_active"
},
{
data
:
"is_connective"
}
],
op_html
:
$
(
'#actions'
).
html
()
{
data
:
"id"
},
{
data
:
"hostname"
},
{
data
:
"ip"
},
{
data
:
"
is_active"
,
orderable
:
false
},
{
data
:
"system_users_granted"
,
orderable
:
false
}
]
};
return
jumpserver
.
initDataTable
(
options
);
asset_table
=
jumpserver
.
initDataTable
(
options
);
return
asset_table
}
$
(
document
).
ready
(
function
(){
function
onSelected
(
event
,
treeNode
)
{
console
.
log
(
"select"
);
url
=
'{% url "api-perms:my-node-assets" node_id=DEFAULT_PK %}'
;
url
=
url
.
replace
(
"{{ DEFAULT_PK }}"
,
treeNode
.
id
);
initTable
();
});
setCookie
(
'node_selected'
,
treeNode
.
id
);
asset_table
.
ajax
.
url
(
url
);
asset_table
.
ajax
.
reload
();
}
function
selectQueryNode
()
{
var
query_node_id
=
$
.
getUrlParam
(
"node"
);
var
cookie_node_id
=
getCookie
(
'node_selected'
);
var
node
;
var
node_id
;
if
(
query_node_id
!==
null
)
{
node_id
=
query_node_id
}
else
if
(
cookie_node_id
!==
null
)
{
node_id
=
cookie_node_id
;
}
node
=
zTree
.
getNodesByParam
(
"id"
,
node_id
,
null
);
if
(
node
){
zTree
.
selectNode
(
node
[
0
]);
}
}
function
initTree
()
{
var
setting
=
{
view
:
{
dblClickExpand
:
false
,
showLine
:
true
},
data
:
{
simpleData
:
{
enable
:
true
}
},
callback
:
{
onSelected
:
onSelected
}
};
var
zNodes
=
[];
$
.
get
(
"{% url 'api-perms:my-nodes' %}"
,
function
(
data
,
status
){
$
.
each
(
data
,
function
(
index
,
value
)
{
value
[
"pId"
]
=
value
[
"parent"
];
if
(
value
[
"key"
]
===
"0"
)
{
value
[
"open"
]
=
true
;
}
value
[
"name"
]
=
value
[
"value"
]
});
zNodes
=
data
;
$
.
fn
.
zTree
.
init
(
$
(
"#assetTree"
),
setting
,
zNodes
);
zTree
=
$
.
fn
.
zTree
.
getZTreeObj
(
"assetTree"
);
rMenu
=
$
(
"#rMenu"
);
selectQueryNode
();
});
}
$
(
document
).
ready
(
function
()
{
initTree
();
});
</script>
{% endblock %}
{% endblock %}
\ No newline at end of file
apps/assets/urls/api_urls.py
View file @
24bdaeca
...
...
@@ -36,7 +36,9 @@ urlpatterns = [
url
(
r'^v1/system-user/(?P<pk>[0-9a-zA-Z\-]{36})/connective/$'
,
api
.
SystemUserTestConnectiveApi
.
as_view
(),
name
=
'system-user-connective'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/children/$'
,
api
.
NodeChildrenApi
.
as_view
(),
name
=
'node-children'
),
url
(
r'^v1/nodes/children/$'
,
api
.
NodeChildrenApi
.
as_view
(),
name
=
'node-children-2'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/children/add/$'
,
api
.
NodeAddChildrenApi
.
as_view
(),
name
=
'node-add-children'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
NodeAssetsApi
.
as_view
(),
name
=
'node-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/add/$'
,
api
.
NodeAddAssetsApi
.
as_view
(),
name
=
'node-add-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/remove/$'
,
api
.
NodeRemoveAssetsApi
.
as_view
(),
name
=
'node-remove-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/refresh-hardware-info/$'
,
api
.
RefreshNodeHardwareInfoApi
.
as_view
(),
name
=
'node-refresh-hardware-info'
),
...
...
apps/common/fields.py
View file @
24bdaeca
...
...
@@ -43,3 +43,7 @@ class StringIDField(serializers.Field):
def
to_representation
(
self
,
value
):
return
{
"pk"
:
value
.
pk
,
"name"
:
value
.
__str__
()}
class
StringManyToManyField
(
serializers
.
RelatedField
):
def
to_representation
(
self
,
value
):
return
value
.
__str__
()
\ No newline at end of file
apps/common/utils.py
View file @
24bdaeca
...
...
@@ -232,6 +232,14 @@ def setattr_bulk(seq, key, value):
return
map
(
set_attr
,
seq
)
def
set_or_append_attr_bulk
(
seq
,
key
,
value
):
for
obj
in
seq
:
ori
=
getattr
(
obj
,
key
,
None
)
if
ori
:
value
+=
" "
+
ori
setattr
(
obj
,
key
,
value
)
def
content_md5
(
data
):
"""计算data的MD5值,经过Base64编码并返回str类型。
...
...
@@ -350,11 +358,17 @@ def get_short_uuid_str():
return
str
(
uuid
.
uuid4
())
.
split
(
'-'
)[
-
1
]
def
is_uuid
(
s
):
if
UUID_PATTERN
.
match
(
s
):
return
True
def
is_uuid
(
seq
):
if
isinstance
(
seq
,
str
):
if
UUID_PATTERN
.
match
(
seq
):
return
True
else
:
return
False
else
:
return
False
for
s
in
seq
:
if
not
is_uuid
(
s
):
return
False
return
True
def
get_signer
():
...
...
@@ -378,3 +392,4 @@ class TeeObj:
def
close
(
self
):
self
.
file_obj
.
close
()
apps/i18n/zh/LC_MESSAGES/django.mo
View file @
24bdaeca
No preview for this file type
apps/i18n/zh/LC_MESSAGES/django.po
View file @
24bdaeca
...
...
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-
06 10:24
+0800\n"
"POT-Creation-Date: 2018-04-
11 15:13
+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
...
...
@@ -17,45 +17,57 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: assets/api/node.py:
58
#: assets/api/node.py:
87
msgid "New node {}"
msgstr "新节点 {}"
#: assets/api/node.py:
133
#: assets/api/node.py:
202
msgid "更新节点资产硬件信息: {}"
msgstr ""
#: assets/api/node.py:
146
#: assets/api/node.py:
215
msgid "测试节点下资产是否可连接: {}"
msgstr ""
#: assets/forms/asset.py:24 assets/
forms/asset.py:60 assets/models/asset.py:5
3
#: assets/
models/user.py:102 assets/
templates/assets/asset_detail.html:183
#: assets/forms/asset.py:24 assets/
models/asset.py:53 assets/models/user.py:10
3
#: assets/templates/assets/asset_detail.html:183
#: assets/templates/assets/asset_detail.html:191
#: assets/templates/assets/system_user_detail.html:166
#: assets/templates/assets/system_user_detail.html:166
perms/models.py:23
msgid "Nodes"
msgstr "节点管理"
#: assets/forms/asset.py:27 assets/forms/asset.py:6
3 assets/forms/asset.py:103
#: assets/forms/asset.py:1
07
assets/models/asset.py:57
#: assets/models/cluster.py:19 assets/models/user.py:7
1
#: assets/forms/asset.py:27 assets/forms/asset.py:6
6 assets/forms/asset.py:109
#: assets/forms/asset.py:1
13
assets/models/asset.py:57
#: assets/models/cluster.py:19 assets/models/user.py:7
2
#: assets/templates/assets/asset_detail.html:73 templates/_nav.html:25
msgid "Admin user"
msgstr "管理用户"
#: assets/forms/asset.py:30 assets/forms/asset.py:66 assets/models/asset.py:81
#: assets/templates/assets/asset_create.html:33
#: assets/templates/assets/asset_detail.html:220
#: assets/templates/assets/asset_update.html:38 templates/_nav.html:27
msgid "Labels"
msgstr "标签管理"
#: assets/forms/asset.py:30 assets/forms/asset.py:69 assets/forms/asset.py:125
#: assets/templates/assets/asset_create.html:35
#: assets/templates/assets/asset_create.html:37
#: assets/templates/assets/asset_list.html:75
#: assets/templates/assets/asset_update.html:40
#: assets/templates/assets/asset_update.html:42
#: assets/templates/assets/user_asset_list.html:34
msgid "Label"
msgstr "标签"
#: assets/forms/asset.py:34 assets/forms/asset.py:7
0
assets/models/asset.py:52
#: assets/forms/asset.py:34 assets/forms/asset.py:7
3
assets/models/asset.py:52
#: assets/models/domain.py:46
msgid "Domain"
msgstr "网域"
#: assets/forms/asset.py:42 assets/forms/asset.py:79
#: assets/forms/asset.py:38 assets/forms/asset.py:63 assets/forms/asset.py:77
#: assets/forms/asset.py:128 assets/templates/assets/asset_create.html:29
#: assets/templates/assets/asset_update.html:34 perms/forms.py:40
#: perms/forms.py:47 perms/models.py:67
#: perms/templates/perms/asset_permission_list.html:57
#: perms/templates/perms/asset_permission_list.html:142
msgid "Node"
msgstr "节点"
#: assets/forms/asset.py:45 assets/forms/asset.py:85
msgid ""
"root or other NOPASSWD sudo privilege user existed in asset,If asset is "
"windows or other set any one, more see admin user left menu"
...
...
@@ -63,46 +75,41 @@ msgstr ""
"root或其他拥有NOPASSWD: ALL权限的用户, 如果是windows或其它硬件可以随意设置一"
"个, 更多信息查看左侧 `管理用户` 菜单"
#: assets/forms/asset.py:4
5 assets/forms/asset.py:82
#: assets/forms/asset.py:4
8 assets/forms/asset.py:88
msgid "* required Must set exact system platform, Windows, Linux ..."
msgstr "* required 必须准确设置操作系统平台,如Windows, Linux ..."
#: assets/forms/asset.py:4
6 assets/forms/asset.py:83
#: assets/forms/asset.py:4
9 assets/forms/asset.py:89
msgid ""
"If your have some network not connect with each other, you can set domain"
msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,使用网域网关跳转登录"
#: assets/forms/asset.py:9
0 assets/forms/asset.py:94
assets/forms/domain.py:16
#: assets/forms/asset.py:9
6 assets/forms/asset.py:100
assets/forms/domain.py:16
#: assets/forms/label.py:15
#: perms/templates/perms/asset_permission_asset.html:88
users/forms.py:272
#: perms/templates/perms/asset_permission_asset.html:88
msgid "Select assets"
msgstr "选择资产"
#: assets/forms/asset.py:
99
assets/models/asset.py:51
#: assets/forms/asset.py:
105
assets/models/asset.py:51
#: assets/models/domain.py:44 assets/templates/assets/admin_user_assets.html:53
#: assets/templates/assets/asset_detail.html:69
#: assets/templates/assets/domain_gateway_list.html:58
#: assets/templates/assets/system_user_asset.html:51
#: assets/templates/assets/user_asset_list.html:21
msgid "Port"
msgstr "端口"
#: assets/forms/asset.py:119 assets/templates/assets/asset_create.html:37
msgid "Select labels"
msgstr "选择标签"
#: assets/forms/asset.py:122 assets/templates/assets/admin_user_detail.html:91
msgid "Select nodes"
msgstr "选择节点"
#: assets/forms/domain.py:14 assets/forms/label.py:13
#: assets/models/asset.py:16
5
assets/templates/assets/admin_user_list.html:25
#: assets/models/asset.py:16
9
assets/templates/assets/admin_user_list.html:25
#: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_list.html:15
#: assets/templates/assets/label_list.html:16
#: assets/templates/assets/system_user_list.html:29 audits/models.py:11
#: audits/templates/audits/ftp_log_list.html:41
#: audits/templates/audits/ftp_log_list.html:72 perms/models.py:17
#: audits/templates/audits/ftp_log_list.html:72 perms/forms.py:37
#: perms/models.py:22
#: perms/templates/perms/asset_permission_create_update.html:40
#: perms/templates/perms/asset_permission_list.html:56
#: perms/templates/perms/asset_permission_list.html:139
#: terminal/backends/command/models.py:11 terminal/models.py:123
#: terminal/templates/terminal/command_list.html:40
#: terminal/templates/terminal/command_list.html:73
...
...
@@ -125,11 +132,12 @@ msgstr "资产"
#: common/templates/common/terminal_setting.html:67
#: common/templates/common/terminal_setting.html:85 ops/models/adhoc.py:36
#: ops/templates/ops/task_detail.html:59 ops/templates/ops/task_list.html:35
#: perms/models.py:14 perms/templates/perms/asset_permission_detail.html:62
#: perms/models.py:19 perms/templates/perms/asset_permission_detail.html:62
#: perms/templates/perms/asset_permission_list.html:53
#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:16
#: terminal/models.py:149 terminal/templates/terminal/terminal_detail.html:43
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
#: users/models/user.py:
35
users/templates/users/_select_user_modal.html:13
#: users/models/user.py:
40
users/templates/users/_select_user_modal.html:13
#: users/templates/users/user_detail.html:63
#: users/templates/users/user_group_detail.html:55
#: users/templates/users/user_group_list.html:12
...
...
@@ -145,8 +153,8 @@ msgstr "名称"
#: assets/templates/assets/domain_gateway_list.html:60
#: assets/templates/assets/system_user_detail.html:62
#: assets/templates/assets/system_user_list.html:27
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:1
4
#: users/models/authentication.py:45 users/models/user.py:3
4
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:1
3
#: users/models/authentication.py:45 users/models/user.py:3
9
#: users/templates/users/_select_user_modal.html:14
#: users/templates/users/login.html:56
#: users/templates/users/login_log_list.html:49
...
...
@@ -161,7 +169,7 @@ msgid "Password or private key passphrase"
msgstr "密码或密钥密码"
#: assets/forms/user.py:25 assets/models/base.py:22 common/forms.py:113
#: users/forms.py:1
6 users/forms.py:25
users/templates/users/login.html:59
#: users/forms.py:1
5 users/forms.py:24
users/templates/users/login.html:59
#: users/templates/users/reset_password.html:52
#: users/templates/users/user_create.html:11
#: users/templates/users/user_password_update.html:40
...
...
@@ -170,7 +178,7 @@ msgstr "密码或密钥密码"
msgid "Password"
msgstr "密码"
#: assets/forms/user.py:28 users/models/user.py:
45
#: assets/forms/user.py:28 users/models/user.py:
50
msgid "Private key"
msgstr "ssh私钥"
...
...
@@ -199,7 +207,7 @@ msgstr "高优先级的系统用户将会作为默认登录用户"
#: assets/templates/assets/asset_list.html:87
#: assets/templates/assets/domain_gateway_list.html:57
#: assets/templates/assets/system_user_asset.html:50
#: assets/templates/assets/user_asset_list.html:
20
common/forms.py:144
#: assets/templates/assets/user_asset_list.html:
46
common/forms.py:144
#: perms/templates/perms/asset_permission_asset.html:55
#: users/templates/users/login_log_list.html:52
#: users/templates/users/user_granted_asset.html:45
...
...
@@ -212,7 +220,7 @@ msgstr "IP"
#: assets/templates/assets/asset_detail.html:57
#: assets/templates/assets/asset_list.html:86
#: assets/templates/assets/system_user_asset.html:49
#: assets/templates/assets/user_asset_list.html:
19
common/forms.py:143
#: assets/templates/assets/user_asset_list.html:
45
common/forms.py:143
#: perms/templates/perms/asset_permission_asset.html:54
#: users/templates/users/user_granted_asset.html:44
#: users/templates/users/user_group_granted_asset.html:44
...
...
@@ -221,7 +229,6 @@ msgstr "主机名"
#: assets/models/asset.py:54 assets/models/domain.py:48
#: assets/models/label.py:20 assets/templates/assets/asset_detail.html:105
#: perms/templates/perms/asset_permission_list.html:70
msgid "Is active"
msgstr "激活"
...
...
@@ -289,15 +296,21 @@ msgstr "系统架构"
msgid "Hostname raw"
msgstr "主机名原始"
#: assets/models/asset.py:81 assets/templates/assets/asset_create.html:33
#: assets/templates/assets/asset_detail.html:220
#: assets/templates/assets/asset_update.html:38 templates/_nav.html:27
msgid "Labels"
msgstr "标签管理"
#: assets/models/asset.py:82 assets/models/base.py:28
#: assets/models/cluster.py:28 assets/models/group.py:21
#: assets/templates/assets/admin_user_detail.html:68
#: assets/templates/assets/asset_detail.html:117
#: assets/templates/assets/domain_detail.html:72
#: assets/templates/assets/system_user_detail.html:96
#: ops/templates/ops/adhoc_detail.html:86 perms/models.py:2
2 perms/models.py:79
#: perms/templates/perms/asset_permission_detail.html:9
4
#: users/models/user.py:5
0
users/templates/users/user_detail.html:99
#: ops/templates/ops/adhoc_detail.html:86 perms/models.py:2
8 perms/models.py:72
#: perms/templates/perms/asset_permission_detail.html:9
8
#: users/models/user.py:5
5
users/templates/users/user_detail.html:99
msgid "Created by"
msgstr "创建者"
...
...
@@ -307,8 +320,8 @@ msgstr "创建者"
#: assets/templates/assets/domain_detail.html:68
#: assets/templates/assets/system_user_detail.html:92
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:63
#: perms/models.py:2
3 perms/models.py:80
#: perms/templates/perms/asset_permission_detail.html:9
0
#: perms/models.py:2
9 perms/models.py:73
#: perms/templates/perms/asset_permission_detail.html:9
4
#: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:17
#: users/templates/users/user_group_detail.html:63
msgid "Date created"
...
...
@@ -325,10 +338,10 @@ msgstr "创建日期"
#: assets/templates/assets/domain_list.html:17
#: assets/templates/assets/system_user_detail.html:100
#: assets/templates/assets/system_user_list.html:33 common/models.py:30
#: ops/models/adhoc.py:42 perms/models.py:
24 perms/models.py:81
#: perms/templates/perms/asset_permission_detail.html:
98
terminal/models.py:26
#: ops/models/adhoc.py:42 perms/models.py:
30 perms/models.py:74
#: perms/templates/perms/asset_permission_detail.html:
102
terminal/models.py:26
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15
#: users/models/user.py:
47
users/templates/users/user_detail.html:111
#: users/models/user.py:
52
users/templates/users/user_detail.html:111
#: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_list.html:14
#: users/templates/users/user_profile.html:114
...
...
@@ -351,7 +364,7 @@ msgstr "带宽"
msgid "Contact"
msgstr "联系人"
#: assets/models/cluster.py:22 users/models/user.py:4
1
#: assets/models/cluster.py:22 users/models/user.py:4
6
#: users/templates/users/user_detail.html:76
msgid "Phone"
msgstr "手机"
...
...
@@ -377,7 +390,7 @@ msgid "Default"
msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:13
#: users/models/user.py:2
66
#: users/models/user.py:2
85
msgid "System"
msgstr "系统"
...
...
@@ -389,14 +402,14 @@ msgstr "默认Cluster"
msgid "Cluster"
msgstr "集群"
#: assets/models/domain.py:45 assets/models/user.py:10
4
#: assets/models/domain.py:45 assets/models/user.py:10
6
#: assets/templates/assets/domain_gateway_list.html:59
#: assets/templates/assets/system_user_detail.html:66
#: assets/templates/assets/system_user_list.html:28
msgid "Protocol"
msgstr "协议"
#: assets/models/group.py:30
perms/models.py:18
#: assets/models/group.py:30
msgid "Asset group"
msgstr "资产组"
...
...
@@ -406,15 +419,19 @@ msgstr "默认资产组"
#: assets/models/label.py:14 audits/models.py:9
#: audits/templates/audits/ftp_log_list.html:33
#: audits/templates/audits/ftp_log_list.html:71 perms/models.py:15
#: audits/templates/audits/ftp_log_list.html:71 perms/forms.py:14
#: perms/forms.py:31 perms/models.py:20
#: perms/templates/perms/asset_permission_create_update.html:36
#: perms/templates/perms/asset_permission_list.html:54
#: perms/templates/perms/asset_permission_list.html:133
#: terminal/backends/command/models.py:10 terminal/models.py:122
#: terminal/templates/terminal/command_list.html:32
#: terminal/templates/terminal/command_list.html:72
#: terminal/templates/terminal/session_list.html:33
#: terminal/templates/terminal/session_list.html:71 users/forms.py:2
20
#: users/models/user.py:30 users/models/user.py:2
54
#: terminal/templates/terminal/session_list.html:71 users/forms.py:2
19
#: users/models/user.py:30 users/models/user.py:2
73
#: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:13 users/views/user.py:33
4
#: users/templates/users/user_group_list.html:13 users/views/user.py:33
5
msgid "User"
msgstr "用户"
...
...
@@ -431,30 +448,49 @@ msgstr "分类"
msgid "Key"
msgstr ""
#: assets/models/user.py:103
#: assets/models/user.py:104
#: assets/templates/assets/_asset_group_bulk_update_modal.html:11
#: assets/templates/assets/system_user_asset.html:21
#: assets/views/admin_user.py:29 assets/views/admin_user.py:47
#: assets/views/admin_user.py:63 assets/views/admin_user.py:78
#: assets/views/admin_user.py:102 assets/views/asset.py:49
#: assets/views/asset.py:95 assets/views/asset.py:155 assets/views/asset.py:172
#: assets/views/asset.py:196 assets/views/domain.py:29
#: assets/views/domain.py:45 assets/views/domain.py:61
#: assets/views/domain.py:74 assets/views/domain.py:98
#: assets/views/domain.py:126 assets/views/domain.py:150
#: assets/views/label.py:26 assets/views/label.py:42 assets/views/label.py:58
#: assets/views/system_user.py:28 assets/views/system_user.py:44
#: assets/views/system_user.py:60 assets/views/system_user.py:74
#: templates/_nav.html:20
msgid "Assets"
msgstr "资产管理"
#: assets/models/user.py:105
msgid "Priority"
msgstr "优先级"
#: assets/models/user.py:10
5
assets/templates/assets/_system_user.html:58
#: assets/models/user.py:10
7
assets/templates/assets/_system_user.html:58
#: assets/templates/assets/system_user_detail.html:118
#: assets/templates/assets/system_user_update.html:11
msgid "Auto push"
msgstr "自动推送"
#: assets/models/user.py:10
6
assets/templates/assets/system_user_detail.html:70
#: assets/models/user.py:10
8
assets/templates/assets/system_user_detail.html:70
msgid "Sudo"
msgstr "Sudo"
#: assets/models/user.py:10
7
assets/templates/assets/system_user_detail.html:75
#: assets/models/user.py:10
9
assets/templates/assets/system_user_detail.html:75
msgid "Shell"
msgstr "Shell"
#: assets/models/user.py:1
50
audits/models.py:12
#: assets/models/user.py:1
49
audits/models.py:12
#: audits/templates/audits/ftp_log_list.html:49
#: audits/templates/audits/ftp_log_list.html:73 perms/forms.py:25
#: perms/models.py:19 perms/models.py:76
#: perms/templates/perms/asset_permission_detail.html:136
#: perms/templates/perms/asset_permission_list.html:69 templates/_nav.html:26
#: audits/templates/audits/ftp_log_list.html:73 perms/forms.py:43
#: perms/models.py:24 perms/models.py:69
#: perms/templates/perms/asset_permission_detail.html:140
#: perms/templates/perms/asset_permission_list.html:58
#: perms/templates/perms/asset_permission_list.html:145 templates/_nav.html:26
#: terminal/backends/command/models.py:12 terminal/models.py:124
#: terminal/templates/terminal/command_list.html:48
#: terminal/templates/terminal/command_list.html:74
...
...
@@ -496,12 +532,8 @@ msgstr "测试系统用户可连接性: {}"
msgid "定期测试系统用户可连接性: {}"
msgstr ""
#: assets/tasks.py:392
msgid "推送系统用户到节点资产: {} => {}"
msgstr ""
#: assets/tasks.py:433
msgid "推送节点系统用户到新加入资产中: {}"
#: assets/tasks.py:398
msgid "推送系统用户到入资产: {}"
msgstr ""
#: assets/templates/assets/_asset_group_bulk_update_modal.html:5
...
...
@@ -512,28 +544,13 @@ msgstr "更新用户组"
msgid "Hint: only change the field you want to update."
msgstr "仅修改你需要更新的字段"
#: assets/templates/assets/_asset_group_bulk_update_modal.html:11
#: assets/templates/assets/system_user_asset.html:21
#: assets/views/admin_user.py:29 assets/views/admin_user.py:47
#: assets/views/admin_user.py:63 assets/views/admin_user.py:78
#: assets/views/admin_user.py:102 assets/views/asset.py:49
#: assets/views/asset.py:95 assets/views/asset.py:155 assets/views/asset.py:172
#: assets/views/asset.py:196 assets/views/domain.py:29
#: assets/views/domain.py:45 assets/views/domain.py:61
#: assets/views/domain.py:74 assets/views/domain.py:98
#: assets/views/domain.py:126 assets/views/domain.py:150
#: assets/views/label.py:26 assets/views/label.py:42 assets/views/label.py:58
#: assets/views/system_user.py:28 assets/views/system_user.py:44
#: assets/views/system_user.py:60 assets/views/system_user.py:74
#: templates/_nav.html:20
msgid "Assets"
msgstr "资产管理"
#: assets/templates/assets/_asset_group_bulk_update_modal.html:13
msgid "Select Asset"
msgstr "选择资产"
#: assets/templates/assets/_asset_group_bulk_update_modal.html:21
#: assets/templates/assets/user_asset_list.html:48
#: users/templates/users/user_granted_asset.html:47
msgid "System users"
msgstr "系统用户"
...
...
@@ -569,17 +586,17 @@ msgstr "如果设置了id,则会使用该行信息更新该id的资产"
#: assets/templates/assets/_asset_list_modal.html:22
#: assets/templates/assets/asset_list.html:88
#: assets/templates/assets/user_asset_list.html:22
msgid "Hardware"
msgstr "硬件"
#: assets/templates/assets/_asset_list_modal.html:23
#: assets/templates/assets/asset_detail.html:143
#: assets/templates/assets/asset_list.html:89
#: assets/templates/assets/user_asset_list.html:23 perms/models.py:20
#: perms/models.py:77
#: perms/templates/perms/asset_permission_create_update.html:51
#: perms/templates/perms/asset_permission_detail.html:116
#: assets/templates/assets/user_asset_list.html:47 perms/models.py:25
#: perms/models.py:70
#: perms/templates/perms/asset_permission_create_update.html:47
#: perms/templates/perms/asset_permission_detail.html:120
#: perms/templates/perms/asset_permission_list.html:59
#: terminal/templates/terminal/terminal_list.html:34
#: users/templates/users/_select_user_modal.html:18
#: users/templates/users/user_detail.html:128
...
...
@@ -596,7 +613,6 @@ msgstr "激活中"
#: assets/templates/assets/asset_list.html:90
#: assets/templates/assets/system_user_asset.html:52
#: assets/templates/assets/system_user_list.html:30
#: users/templates/users/user_granted_asset.html:47
#: users/templates/users/user_group_granted_asset.html:47
msgid "Reachable"
msgstr "可连接"
...
...
@@ -610,7 +626,7 @@ msgstr "可连接"
#: assets/templates/assets/system_user_list.html:34
#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64
#: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:42
#: perms/templates/perms/asset_permission_list.html:
72
#: perms/templates/perms/asset_permission_list.html:
60
#: terminal/templates/terminal/session_list.html:80
#: terminal/templates/terminal/terminal_list.html:36
#: users/templates/users/user_group_list.html:15
...
...
@@ -656,7 +672,7 @@ msgstr "激活所选"
#: common/templates/common/email_setting.html:60
#: common/templates/common/ldap_setting.html:60
#: common/templates/common/terminal_setting.html:103
#: perms/templates/perms/asset_permission_create_update.html:7
2
#: perms/templates/perms/asset_permission_create_update.html:7
0
#: terminal/templates/terminal/session_list.html:120
#: terminal/templates/terminal/terminal_update.html:48
#: users/templates/users/_user.html:44
...
...
@@ -683,7 +699,7 @@ msgstr "提交"
#: assets/templates/assets/system_user_detail.html:26
#: assets/templates/assets/system_user_list.html:88
#: perms/templates/perms/asset_permission_detail.html:30
#: perms/templates/perms/asset_permission_list.html:1
2
1
#: perms/templates/perms/asset_permission_list.html:1
9
1
#: terminal/templates/terminal/terminal_detail.html:16
#: terminal/templates/terminal/terminal_list.html:71
#: users/templates/users/user_detail.html:25
...
...
@@ -709,7 +725,7 @@ msgstr "更新"
#: assets/templates/assets/system_user_list.html:89
#: ops/templates/ops/task_list.html:72
#: perms/templates/perms/asset_permission_detail.html:34
#: perms/templates/perms/asset_permission_list.html:1
2
2
#: perms/templates/perms/asset_permission_list.html:1
9
2
#: terminal/templates/terminal/terminal_list.html:73
#: users/templates/users/user_detail.html:30
#: users/templates/users/user_group_detail.html:32
...
...
@@ -723,7 +739,7 @@ msgstr "删除"
#: assets/templates/assets/asset_create.html:16
#: assets/templates/assets/asset_update.html:21
#: assets/templates/assets/gateway_create_update.html:37
#: perms/templates/perms/asset_permission_create_update.html:3
8
#: perms/templates/perms/asset_permission_create_update.html:3
3
msgid "Basic"
msgstr "基本"
...
...
@@ -745,7 +761,7 @@ msgstr "自动生成密钥"
#: assets/templates/assets/asset_create.html:59
#: assets/templates/assets/asset_update.html:63
#: assets/templates/assets/gateway_create_update.html:53
#: perms/templates/perms/asset_permission_create_update.html:4
9
#: perms/templates/perms/asset_permission_create_update.html:4
5
#: terminal/templates/terminal/terminal_update.html:42
msgid "Other"
msgstr "其它"
...
...
@@ -762,7 +778,7 @@ msgstr "其它"
#: common/templates/common/email_setting.html:59
#: common/templates/common/ldap_setting.html:59
#: common/templates/common/terminal_setting.html:101
#: perms/templates/perms/asset_permission_create_update.html:
71
#: perms/templates/perms/asset_permission_create_update.html:
69
#: terminal/templates/terminal/terminal_update.html:47
#: users/templates/users/_user.html:43
#: users/templates/users/user_bulk_update.html:23
...
...
@@ -802,7 +818,7 @@ msgstr "资产列表"
#: assets/templates/assets/admin_user_assets.html:66
#: assets/templates/assets/system_user_asset.html:64
#: assets/templates/assets/system_user_detail.html:112
#: perms/templates/perms/asset_permission_detail.html:11
0
#: perms/templates/perms/asset_permission_detail.html:11
4
msgid "Quick update"
msgstr "快速更新"
...
...
@@ -822,9 +838,14 @@ msgstr "测试"
msgid "Replace node assets admin user with this"
msgstr "替换资产的管理员"
#: assets/templates/assets/admin_user_detail.html:91
#: perms/templates/perms/asset_permission_asset.html:116
msgid "Select nodes"
msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:200
#: assets/templates/assets/asset_list.html:60
0
#: assets/templates/assets/asset_list.html:60
3
#: assets/templates/assets/system_user_detail.html:183
#: assets/templates/assets/system_user_list.html:138 templates/_modal.html:16
#: terminal/templates/terminal/session_detail.html:108
...
...
@@ -855,19 +876,6 @@ msgstr "不可达"
msgid "Ratio"
msgstr "比例"
#: assets/templates/assets/asset_create.html:29
#: assets/templates/assets/asset_update.html:34 perms/models.py:74
#: perms/templates/perms/asset_permission_create_update.html:40
#: perms/templates/perms/asset_permission_list.html:67
msgid "Node"
msgstr "节点"
#: assets/templates/assets/asset_create.html:35
#: assets/templates/assets/asset_list.html:75
#: assets/templates/assets/asset_update.html:40
msgid "Label"
msgstr "标签"
#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:197
msgid "Asset detail"
msgstr "资产详情"
...
...
@@ -949,15 +957,15 @@ msgstr "重命名节点"
msgid "Delete node"
msgstr "删除节点"
#: assets/templates/assets/asset_list.html:20
3
#: assets/templates/assets/asset_list.html:20
2
msgid "Create node failed"
msgstr "创建节点失败"
#: assets/templates/assets/asset_list.html:21
6
#: assets/templates/assets/asset_list.html:21
5
msgid "Have child node, cancel"
msgstr "存在子节点,不能删除"
#: assets/templates/assets/asset_list.html:59
5
#: assets/templates/assets/asset_list.html:59
8
#: assets/templates/assets/system_user_list.html:133
#: users/templates/users/user_detail.html:334
#: users/templates/users/user_detail.html:359
...
...
@@ -966,20 +974,20 @@ msgstr "存在子节点,不能删除"
msgid "Are you sure?"
msgstr "你确认吗?"
#: assets/templates/assets/asset_list.html:59
6
#: assets/templates/assets/asset_list.html:59
9
msgid "This will delete the selected assets !!!"
msgstr "删除选择资产"
#: assets/templates/assets/asset_list.html:60
4
#: assets/templates/assets/asset_list.html:60
7
msgid "Asset Deleted."
msgstr "已被删除"
#: assets/templates/assets/asset_list.html:60
5
#: assets/templates/assets/asset_list.html:61
0
#: assets/templates/assets/asset_list.html:60
8
#: assets/templates/assets/asset_list.html:61
3
msgid "Asset Delete"
msgstr "删除"
#: assets/templates/assets/asset_list.html:6
09
#: assets/templates/assets/asset_list.html:6
12
msgid "Asset Deleting failed."
msgstr "删除失败"
...
...
@@ -1088,10 +1096,6 @@ msgstr "删除系统用户"
msgid "System Users Deleting failed."
msgstr "系统用户删除失败"
#: assets/templates/assets/user_asset_list.html:24
msgid "Connective"
msgstr "连接性"
#: assets/views/admin_user.py:30
msgid "Admin user list"
msgstr "管理用户列表"
...
...
@@ -1120,7 +1124,7 @@ msgstr "批量更新资产"
msgid "Update asset"
msgstr "更新资产"
#: assets/views/asset.py:30
0
#: assets/views/asset.py:30
8
msgid "already exists"
msgstr "已经存在"
...
...
@@ -1182,18 +1186,33 @@ msgstr "远端地址"
msgid "Operate"
msgstr "操作"
#: audits/models.py:14 audits/templates/audits/ftp_log_list.html:76
#: audits/models.py:14 audits/templates/audits/ftp_log_list.html:56
#: audits/templates/audits/ftp_log_list.html:76
msgid "Filename"
msgstr "文件名"
#: audits/templates/audits/ftp_log_list.html:77
#: audits/models.py:15 audits/templates/audits/ftp_log_list.html:77
#: ops/templates/ops/task_list.html:39
msgid "Success"
msgstr "成功"
#: audits/templates/audits/ftp_log_list.html:78
#: ops/templates/ops/adhoc_history.html:52
#: ops/templates/ops/adhoc_history_detail.html:61
#: ops/templates/ops/task_history.html:58 terminal/models.py:132
#: ops/templates/ops/task_history.html:58 perms/models.py:26
#: perms/templates/perms/asset_permission_detail.html:86 terminal/models.py:132
#: terminal/templates/terminal/session_list.html:77
msgid "Date start"
msgstr "开始日期"
#: audits/views.py:50 templates/_nav.html:64
msgid "Audits"
msgstr "日志审计"
#: audits/views.py:51 templates/_nav.html:67
msgid "FTP log"
msgstr "FTP日志"
#: common/api.py:18
msgid "Test mail sent to {}, please check"
msgstr "邮件已经发送{}, 请检查"
...
...
@@ -1655,10 +1674,6 @@ msgstr "搜索"
msgid "Versions"
msgstr "版本"
#: ops/templates/ops/task_list.html:39
msgid "Success"
msgstr "成功"
#: ops/templates/ops/task_list.html:40
#: users/templates/users/login_log_list.html:54
msgid "Date"
...
...
@@ -1685,24 +1700,37 @@ msgstr "任务列表"
msgid "Task run history"
msgstr "执行历史"
#: perms/forms.py:22 perms/models.py:16 perms/models.py:75
#: perms/templates/perms/asset_permission_list.html:68 templates/_nav.html:14
#: users/models/group.py:25 users/models/user.py:37
#: perms/forms.py:18 users/forms.py:176 users/forms.py:181 users/forms.py:193
#: users/forms.py:223
msgid "Select users"
msgstr "选择用户"
#: perms/forms.py:34 perms/models.py:21 perms/models.py:68
#: perms/templates/perms/asset_permission_list.html:55
#: perms/templates/perms/asset_permission_list.html:136 templates/_nav.html:14
#: users/models/group.py:25 users/models/user.py:42
#: users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:179
#: users/templates/users/user_list.html:26
msgid "User group"
msgstr "用户组"
#: perms/models.py:21 perms/models.py:78
#: perms/templates/perms/asset_permission_detail.html:86
#: perms/templates/perms/asset_permission_list.html:71 users/models/user.py:49
#: users/templates/users/user_detail.html:95
#: perms/forms.py:56
msgid "User or group at least one required"
msgstr ""
#: perms/forms.py:65
msgid "Asset or group at least one required"
msgstr ""
#: perms/models.py:27 perms/models.py:71
#: perms/templates/perms/asset_permission_detail.html:90
#: users/models/user.py:54 users/templates/users/user_detail.html:95
#: users/templates/users/user_profile.html:96
msgid "Date expired"
msgstr "失效日期"
#: perms/models.py:8
8
templates/_nav.html:34
#: perms/models.py:8
1
templates/_nav.html:34
msgid "Asset permission"
msgstr "资产授权"
...
...
@@ -1723,7 +1751,7 @@ msgid "Add asset to this permission"
msgstr "添加资产"
#: perms/templates/perms/asset_permission_asset.html:97
#: perms/templates/perms/asset_permission_detail.html:15
3
#: perms/templates/perms/asset_permission_detail.html:15
7
#: perms/templates/perms/asset_permission_user.html:97
#: perms/templates/perms/asset_permission_user.html:125
#: users/templates/users/user_group_detail.html:95
...
...
@@ -1731,12 +1759,8 @@ msgid "Add"
msgstr "添加"
#: perms/templates/perms/asset_permission_asset.html:108
msgid "Add asset group to this permission"
msgstr "添加资产组"
#: perms/templates/perms/asset_permission_asset.html:116 users/forms.py:275
msgid "Select asset groups"
msgstr "选择资产组"
msgid "Add node to this permission"
msgstr "添加节点"
#: perms/templates/perms/asset_permission_asset.html:125
#: users/templates/users/user_detail.html:196
...
...
@@ -1756,18 +1780,18 @@ msgid "Asset count"
msgstr "资产数量"
#: perms/templates/perms/asset_permission_detail.html:78
msgid "
Asset group
count"
msgstr "
资产组
数量"
msgid "
Node
count"
msgstr "
节点
数量"
#: perms/templates/perms/asset_permission_detail.html:82
msgid "System user count"
msgstr "系统用户数量"
#: perms/templates/perms/asset_permission_detail.html:14
4 users/forms.py:27
8
#: perms/templates/perms/asset_permission_detail.html:148
msgid "Select system users"
msgstr "选择系统用户"
#: perms/templates/perms/asset_permission_list.html:
58
#: perms/templates/perms/asset_permission_list.html:
46
msgid "Create permission"
msgstr "创建授权规则"
...
...
@@ -1792,22 +1816,31 @@ msgstr "添加用户组"
msgid "Select user groups"
msgstr "选择用户组"
#: perms/views.py:23 perms/views.py:47 perms/views.py:67 templates/_nav.html:31
#: perms/views.py:25 perms/views.py:55 perms/views.py:70 perms/views.py:85
#: perms/views.py:120 perms/views.py:151 templates/_nav.html:31
msgid "Perms"
msgstr "权限管理"
#: perms/views.py:2
4
#: perms/views.py:2
6
msgid "Asset permission list"
msgstr "资产授权列表"
#: perms/views.py:
48
#: perms/views.py:
56
msgid "Create asset permission"
msgstr "创建权限规则"
#: perms/views.py:
68
#: perms/views.py:
71 perms/views.py:86
msgid "Update asset permission"
msgstr "更新资产授权"
#: perms/views.py:121
msgid "Asset permission user list"
msgstr "资产授权用户列表"
#: perms/views.py:152
msgid "Asset permission asset list"
msgstr "资产授权资产列表"
#: templates/_header_bar.html:18
msgid "Supports"
msgstr "商业支持"
...
...
@@ -1816,13 +1849,13 @@ msgstr "商业支持"
msgid "Docs"
msgstr "文档"
#: templates/_header_bar.html:37 templates/_nav_user.html:9 users/forms.py:9
4
#: templates/_header_bar.html:37 templates/_nav_user.html:9 users/forms.py:9
3
#: users/templates/users/_user.html:36
#: users/templates/users/user_password_update.html:37
#: users/templates/users/user_profile.html:17
#: users/templates/users/user_profile_update.html:37
#: users/templates/users/user_profile_update.html:57
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:31
7
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:31
8
msgid "Profile"
msgstr "个人信息"
...
...
@@ -1879,9 +1912,9 @@ msgstr "关闭"
#: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:44
#: users/views/group.py:62 users/views/group.py:79 users/views/group.py:95
#: users/views/login.py:20
9 users/views/login.py:258
users/views/user.py:60
#: users/views/user.py:75 users/views/user.py:9
4 users/views/user.py:150
#: users/views/user.py:30
5 users/views/user.py:352 users/views/user.py:374
#: users/views/login.py:20
5 users/views/login.py:254
users/views/user.py:60
#: users/views/user.py:75 users/views/user.py:9
5 users/views/user.py:151
#: users/views/user.py:30
6 users/views/user.py:353 users/views/user.py:375
msgid "Users"
msgstr "用户管理"
...
...
@@ -1925,14 +1958,6 @@ msgstr "终端管理"
msgid "Job Center"
msgstr "作业中心"
#: templates/_nav.html:64
msgid "Audits"
msgstr "日志审计"
#: templates/_nav.html:67
msgid "FTP log"
msgstr "FTP日志"
#: templates/captcha/image.html:3
msgid "Play CAPTCHA as audio file"
msgstr "语言播放验证码"
...
...
@@ -2199,7 +2224,7 @@ msgstr ""
msgid "Invalid token or cache refreshed."
msgstr ""
#: users/forms.py:2
8 users/models/user.py:38
#: users/forms.py:2
7 users/models/user.py:43
#: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:87
#: users/templates/users/user_list.html:25
...
...
@@ -2207,55 +2232,55 @@ msgstr ""
msgid "Role"
msgstr "角色"
#: users/forms.py:
30 users/forms.py:140
#: users/forms.py:
29 users/forms.py:139
msgid "ssh public key"
msgstr "ssh公钥"
#: users/forms.py:3
1 users/forms.py:141
#: users/forms.py:3
0 users/forms.py:140
msgid "ssh-rsa AAAA..."
msgstr ""
#: users/forms.py:3
2
#: users/forms.py:3
1
msgid "Paste user id_rsa.pub here."
msgstr "复制用户公钥到这里"
#: users/forms.py:
50
users/templates/users/user_detail.html:187
#: users/forms.py:
49
users/templates/users/user_detail.html:187
msgid "Join user groups"
msgstr "添加到用户组"
#: users/forms.py:
60 users/forms.py:155
#: users/forms.py:
59 users/forms.py:154
msgid "Public key should not be the same as your old one."
msgstr "不能和原来的密钥相同"
#: users/forms.py:6
4 users/forms.py:159
users/serializers.py:42
#: users/forms.py:6
3 users/forms.py:158
users/serializers.py:42
msgid "Not a valid ssh public key"
msgstr "ssh密钥不合法"
#: users/forms.py:
100
#: users/forms.py:
99
msgid "Old password"
msgstr "原来密码"
#: users/forms.py:10
5
#: users/forms.py:10
4
msgid "New password"
msgstr "新密码"
#: users/forms.py:1
10
#: users/forms.py:1
09
msgid "Confirm password"
msgstr "确认密码"
#: users/forms.py:1
20
#: users/forms.py:1
19
msgid "Old password error"
msgstr "原来密码错误"
#: users/forms.py:12
8
#: users/forms.py:12
7
msgid "Password does not match"
msgstr "密码不一致"
#: users/forms.py:14
2
#: users/forms.py:14
1
msgid "Paste your id_rsa.pub here."
msgstr "复制你的公钥到这里"
#: users/forms.py:1
70 users/models/user.py:46
#: users/forms.py:1
69 users/models/user.py:51
#: users/templates/users/user_password_update.html:43
#: users/templates/users/user_profile.html:71
#: users/templates/users/user_profile_update.html:43
...
...
@@ -2263,10 +2288,6 @@ msgstr "复制你的公钥到这里"
msgid "Public key"
msgstr "ssh公钥"
#: users/forms.py:177 users/forms.py:182 users/forms.py:194 users/forms.py:224
msgid "Select users"
msgstr "选择用户"
#: users/models/authentication.py:36
msgid "Private Token"
msgstr "ssh密钥"
...
...
@@ -2291,7 +2312,7 @@ msgstr "Agent"
msgid "Date login"
msgstr "登录日期"
#: users/models/user.py:29 users/models/user.py:2
62
#: users/models/user.py:29 users/models/user.py:2
81
msgid "Administrator"
msgstr "管理员"
...
...
@@ -2299,24 +2320,36 @@ msgstr "管理员"
msgid "Application"
msgstr "应用程序"
#: users/models/user.py:36 users/templates/users/user_detail.html:71
#: users/models/user.py:34
msgid "Disable"
msgstr "禁用"
#: users/models/user.py:35
msgid "Enable"
msgstr "启用"
#: users/models/user.py:36
msgid "Force enable"
msgstr "强制启用"
#: users/models/user.py:41 users/templates/users/user_detail.html:71
#: users/templates/users/user_profile.html:59
msgid "Email"
msgstr "邮件"
#: users/models/user.py:
39
#: users/models/user.py:
44
msgid "Avatar"
msgstr "头像"
#: users/models/user.py:4
0
users/templates/users/user_detail.html:82
#: users/models/user.py:4
5
users/templates/users/user_detail.html:82
msgid "Wechat"
msgstr "微信"
#: users/models/user.py:4
2
#: users/models/user.py:4
7
msgid "Enable OTP"
msgstr "二次验证"
#: users/models/user.py:2
65
#: users/models/user.py:2
84
msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员"
...
...
@@ -2431,7 +2464,7 @@ msgid "Reset link will be generated and sent to the user. "
msgstr "生成重置密码连接,通过邮件发送给用户"
#: users/templates/users/user_detail.html:19
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:15
1
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:15
2
msgid "User detail"
msgstr "用户详情"
...
...
@@ -2550,8 +2583,8 @@ msgstr "用户删除失败"
msgid "OTP"
msgstr ""
#: users/templates/users/user_profile.html:100 users/views/user.py:18
0
#: users/views/user.py:23
4
#: users/templates/users/user_profile.html:100 users/views/user.py:18
1
#: users/views/user.py:23
5
msgid "User groups"
msgstr "用户组"
...
...
@@ -2587,7 +2620,7 @@ msgstr "更新密钥"
msgid "Or reset by server"
msgstr "或者重置并下载密钥"
#: users/templates/users/user_update.html:4 users/views/user.py:9
4
#: users/templates/users/user_update.html:4 users/views/user.py:9
5
msgid "Update user"
msgstr "更新用户"
...
...
@@ -2733,78 +2766,76 @@ msgstr "更新用户组"
msgid "User group granted asset"
msgstr "用户组授权资产"
#: users/views/login.py:5
7
#: users/views/login.py:5
5
msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie"
#: users/views/login.py:9
9
#: users/views/login.py:9
7
msgid "Logout success"
msgstr "退出登录成功"
#: users/views/login.py:
100
#: users/views/login.py:
98
msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面"
#: users/views/login.py:11
6
#: users/views/login.py:11
4
msgid "Email address invalid, please input again"
msgstr "邮箱地址错误,重新输入"
#: users/views/login.py:12
9
#: users/views/login.py:12
7
msgid "Send reset password message"
msgstr "发送重置密码邮件"
#: users/views/login.py:1
30
#: users/views/login.py:1
28
msgid "Send reset password mail success, login your mail box and follow it "
msgstr ""
"发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)"
#: users/views/login.py:14
4
#: users/views/login.py:14
2
msgid "Reset password success"
msgstr "重置密码成功"
#: users/views/login.py:14
5
#: users/views/login.py:14
3
msgid "Reset password success, return to login page"
msgstr "重置密码成功,返回到登录页面"
#: users/views/login.py:16
2 users/views/login.py:175
#: users/views/login.py:16
0 users/views/login.py:173
msgid "Token invalid or expired"
msgstr "Token错误或失效"
#: users/views/login.py:1
71
#: users/views/login.py:1
69
msgid "Password not same"
msgstr "密码不一致"
#: users/views/login.py:20
9
#: users/views/login.py:20
5
msgid "First login"
msgstr "首次登陆"
#: users/views/login.py:25
9
#: users/views/login.py:25
5
msgid "Login log list"
msgstr "登录日志"
#: users/views/user.py:10
4
#: users/views/user.py:10
5
msgid "Bulk update user success"
msgstr "批量更新用户成功"
#: users/views/user.py:2
09
#: users/views/user.py:2
10
msgid "Invalid file."
msgstr "文件不合法"
#: users/views/user.py:30
6
#: users/views/user.py:30
7
msgid "User granted assets"
msgstr "用户授权资产"
#: users/views/user.py:33
5
#: users/views/user.py:33
6
msgid "Profile setting"
msgstr "个人信息设置"
#: users/views/user.py:35
3
#: users/views/user.py:35
4
msgid "Password update"
msgstr "密码更新"
#: users/views/user.py:37
5
#: users/views/user.py:37
6
msgid "Public key update"
msgstr "密钥更新"
#~ msgid "Task has been send, seen left asset status"
#~ msgstr "任务已下发,查看左侧资产状态"
apps/perms/api.py
View file @
24bdaeca
...
...
@@ -3,13 +3,14 @@
from
django.shortcuts
import
get_object_or_404
from
rest_framework.views
import
APIView
,
Response
from
rest_framework.generics
import
ListAPIView
,
get_object_or_404
from
rest_framework.generics
import
ListAPIView
,
get_object_or_404
,
RetrieveUpdateAPIView
from
rest_framework
import
viewsets
from
common.utils
import
set_or_append_attr_bulk
from
users.permissions
import
IsValidUser
,
IsSuperUser
,
IsSuperUserOrAppUser
from
.utils
import
Node
PermissionUtil
from
.models
import
Node
Permission
from
.hands
import
AssetGrantedSerializer
,
User
,
UserGroup
,
Asset
,
\
from
.utils
import
Asset
PermissionUtil
from
.models
import
Asset
Permission
from
.hands
import
AssetGrantedSerializer
,
User
,
UserGroup
,
Asset
,
Node
,
\
NodeGrantedSerializer
,
SystemUser
,
NodeSerializer
from
.
import
serializers
...
...
@@ -18,7 +19,7 @@ class AssetPermissionViewSet(viewsets.ModelViewSet):
"""
资产授权列表的增删改查api
"""
queryset
=
Node
Permission
.
objects
.
all
()
queryset
=
Asset
Permission
.
objects
.
all
()
serializer_class
=
serializers
.
AssetPermissionCreateUpdateSerializer
permission_classes
=
(
IsSuperUser
,)
...
...
@@ -29,12 +30,28 @@ class AssetPermissionViewSet(viewsets.ModelViewSet):
def
get_queryset
(
self
):
queryset
=
super
()
.
get_queryset
()
node_id
=
self
.
request
.
query_params
.
get
(
'node_id'
)
asset_id
=
self
.
request
.
query_params
.
get
(
'asset'
)
node_id
=
self
.
request
.
query_params
.
get
(
'node'
)
inherit_nodes
=
set
()
if
not
asset_id
and
not
node_id
:
return
queryset
if
node_id
:
queryset
=
queryset
.
filter
(
node__id
=
node_id
)
permissions
=
set
()
if
asset_id
:
asset
=
get_object_or_404
(
Asset
,
pk
=
asset_id
)
permissions
=
set
(
queryset
.
filter
(
assets
=
asset
))
for
node
in
asset
.
nodes
.
all
():
inherit_nodes
.
update
(
set
(
node
.
ancestor_with_node
))
elif
node_id
:
node
=
get_object_or_404
(
Node
,
pk
=
node_id
)
permissions
=
set
(
queryset
.
filter
(
nodes
=
node
))
inherit_nodes
=
node
.
ancestor
return
queryset
for
n
in
inherit_nodes
:
_permissions
=
queryset
.
filter
(
nodes
=
n
)
set_or_append_attr_bulk
(
_permissions
,
"inherit"
,
n
.
value
)
permissions
.
update
(
_permissions
)
return
permissions
class
UserGrantedAssetsApi
(
ListAPIView
):
...
...
@@ -53,7 +70,7 @@ class UserGrantedAssetsApi(ListAPIView):
else
:
user
=
self
.
request
.
user
for
k
,
v
in
Node
PermissionUtil
.
get_user_assets
(
user
)
.
items
():
for
k
,
v
in
Asset
PermissionUtil
.
get_user_assets
(
user
)
.
items
():
if
k
.
is_unixlike
():
system_users_granted
=
[
s
for
s
in
v
if
s
.
protocol
==
'ssh'
]
else
:
...
...
@@ -78,38 +95,11 @@ class UserGrantedNodesApi(ListAPIView):
user
=
get_object_or_404
(
User
,
id
=
user_id
)
else
:
user
=
self
.
request
.
user
nodes
=
NodePermissionUtil
.
get_user_node
s
(
user
)
nodes
=
AssetPermissionUtil
.
get_user_nodes_with_asset
s
(
user
)
return
nodes
.
keys
()
class
UserGrantedNodesWithAssetsApi
(
ListAPIView
):
"""
授权用户的资产组,注:这里的资产组并非是授权列表中授权的,
而是把所有资产取出来,然后反查出所有资产组,然后合并得到,
结果里也包含资产组下授权的资产
数据结构如下:
[
{
"id": 1,
"value": "node",
... 其它属性
"assets_granted": [
{
"id": 1,
"hostname": "testserver",
"ip": "192.168.1.1",
"port": 22,
"system_users_granted": [
"id": 1,
"name": "web",
"username": "web",
"protocol": "ssh",
]
}
]
}
]
"""
permission_classes
=
(
IsSuperUserOrAppUser
,)
serializer_class
=
NodeGrantedSerializer
...
...
@@ -121,18 +111,16 @@ class UserGrantedNodesWithAssetsApi(ListAPIView):
else
:
user
=
get_object_or_404
(
User
,
id
=
user_id
)
nodes
=
NodePermissionUtil
.
get_user_nodes_with_assets
(
user
)
assets
=
{}
for
k
,
v
in
NodePermissionUtil
.
get_user_assets
(
user
)
.
items
():
if
k
.
is_unixlike
():
system_users_granted
=
[
s
for
s
in
v
if
s
.
protocol
==
'ssh'
]
else
:
system_users_granted
=
[
s
for
s
in
v
if
s
.
protocol
==
'rdp'
]
assets
[
k
]
=
system_users_granted
for
node
,
v
in
nodes
.
items
():
for
asset
in
v
[
'assets'
]:
asset
.
system_users_granted
=
assets
[
asset
]
node
.
assets_granted
=
v
[
'assets'
]
nodes
=
AssetPermissionUtil
.
get_user_nodes_with_assets
(
user
)
for
node
,
_assets
in
nodes
.
items
():
assets
=
_assets
.
keys
()
for
k
,
v
in
_assets
.
items
():
if
k
.
is_unixlike
():
system_users_granted
=
[
s
for
s
in
v
if
s
.
protocol
==
'ssh'
]
else
:
system_users_granted
=
[
s
for
s
in
v
if
s
.
protocol
==
'rdp'
]
k
.
system_users_granted
=
system_users_granted
node
.
assets_granted
=
assets
queryset
.
append
(
node
)
return
queryset
...
...
@@ -142,6 +130,31 @@ class UserGrantedNodesWithAssetsApi(ListAPIView):
return
super
()
.
get_permissions
()
class
UserGrantedNodeAssetsApi
(
ListAPIView
):
permission_classes
=
(
IsSuperUserOrAppUser
,)
serializer_class
=
AssetGrantedSerializer
def
get_queryset
(
self
):
user_id
=
self
.
kwargs
.
get
(
'pk'
,
''
)
node_id
=
self
.
kwargs
.
get
(
'node_id'
)
if
user_id
:
user
=
get_object_or_404
(
User
,
id
=
user_id
)
else
:
user
=
self
.
request
.
user
node
=
get_object_or_404
(
Node
,
id
=
node_id
)
nodes
=
AssetPermissionUtil
.
get_user_nodes_with_assets
(
user
)
assets
=
nodes
.
get
(
node
,
[])
for
asset
,
system_users
in
assets
.
items
():
asset
.
system_users_granted
=
system_users
return
assets
def
get_permissions
(
self
):
if
self
.
kwargs
.
get
(
'pk'
)
is
None
:
self
.
permission_classes
=
(
IsValidUser
,)
return
super
()
.
get_permissions
()
class
UserGroupGrantedAssetsApi
(
ListAPIView
):
permission_classes
=
(
IsSuperUser
,)
serializer_class
=
AssetGrantedSerializer
...
...
@@ -154,7 +167,7 @@ class UserGroupGrantedAssetsApi(ListAPIView):
return
queryset
user_group
=
get_object_or_404
(
UserGroup
,
id
=
user_group_id
)
assets
=
Node
PermissionUtil
.
get_user_group_assets
(
user_group
)
assets
=
Asset
PermissionUtil
.
get_user_group_assets
(
user_group
)
for
k
,
v
in
assets
.
items
():
k
.
system_users_granted
=
v
queryset
.
append
(
k
)
...
...
@@ -171,8 +184,8 @@ class UserGroupGrantedNodesApi(ListAPIView):
if
group_id
:
group
=
get_object_or_404
(
UserGroup
,
id
=
group_id
)
nodes
=
NodePermissionUtil
.
get_user_group_node
s
(
group
)
queryset
=
nodes
.
keys
()
nodes
=
AssetPermissionUtil
.
get_user_group_nodes_with_asset
s
(
group
)
return
nodes
.
keys
()
return
queryset
...
...
@@ -188,15 +201,33 @@ class UserGroupGrantedNodesWithAssetsApi(ListAPIView):
return
queryset
user_group
=
get_object_or_404
(
UserGroup
,
id
=
user_group_id
)
nodes
=
NodePermissionUtil
.
get_user_group_nodes_with_assets
(
user_group
)
for
node
,
v
in
nodes
.
items
():
for
asset
in
v
[
'assets'
]:
asset
.
system_users_granted
=
v
[
'system_users'
]
node
.
assets_granted
=
v
[
'assets'
]
nodes
=
AssetPermissionUtil
.
get_user_group_nodes_with_assets
(
user_group
)
for
node
,
_assets
in
nodes
.
items
():
assets
=
_assets
.
keys
()
for
asset
,
system_users
in
_assets
.
items
():
asset
.
system_users_granted
=
system_users
node
.
assets_granted
=
assets
queryset
.
append
(
node
)
return
queryset
class
UserGroupGrantedNodeAssetsApi
(
ListAPIView
):
permission_classes
=
(
IsSuperUserOrAppUser
,)
serializer_class
=
AssetGrantedSerializer
def
get_queryset
(
self
):
user_group_id
=
self
.
kwargs
.
get
(
'pk'
,
''
)
node_id
=
self
.
kwargs
.
get
(
'node_id'
)
user_group
=
get_object_or_404
(
UserGroup
,
id
=
user_group_id
)
node
=
get_object_or_404
(
Node
,
id
=
node_id
)
nodes
=
AssetPermissionUtil
.
get_user_group_nodes_with_assets
(
user_group
)
assets
=
nodes
.
get
(
node
,
[])
for
asset
,
system_users
in
assets
.
items
():
asset
.
system_users_granted
=
system_users
return
assets
class
ValidateUserAssetPermissionView
(
APIView
):
permission_classes
=
(
IsSuperUserOrAppUser
,)
...
...
@@ -210,8 +241,82 @@ class ValidateUserAssetPermissionView(APIView):
asset
=
get_object_or_404
(
Asset
,
id
=
asset_id
)
system_user
=
get_object_or_404
(
SystemUser
,
id
=
system_id
)
assets_granted
=
Node
PermissionUtil
.
get_user_assets
(
user
)
assets_granted
=
Asset
PermissionUtil
.
get_user_assets
(
user
)
if
system_user
in
assets_granted
.
get
(
asset
,
[]):
return
Response
({
'msg'
:
True
},
status
=
200
)
else
:
return
Response
({
'msg'
:
False
},
status
=
403
)
class
AssetPermissionRemoveUserApi
(
RetrieveUpdateAPIView
):
"""
将用户从授权中移除,Detail页面会调用
"""
permission_classes
=
(
IsSuperUser
,)
serializer_class
=
serializers
.
AssetPermissionUpdateUserSerializer
queryset
=
AssetPermission
.
objects
.
all
()
def
update
(
self
,
request
,
*
args
,
**
kwargs
):
perm
=
self
.
get_object
()
serializer
=
self
.
serializer_class
(
data
=
request
.
data
)
if
serializer
.
is_valid
():
users
=
serializer
.
validated_data
.
get
(
'users'
)
if
users
:
perm
.
users
.
remove
(
*
tuple
(
users
))
return
Response
({
"msg"
:
"ok"
})
else
:
return
Response
({
"error"
:
serializer
.
errors
})
class
AssetPermissionAddUserApi
(
RetrieveUpdateAPIView
):
permission_classes
=
(
IsSuperUser
,)
serializer_class
=
serializers
.
AssetPermissionUpdateUserSerializer
queryset
=
AssetPermission
.
objects
.
all
()
def
update
(
self
,
request
,
*
args
,
**
kwargs
):
perm
=
self
.
get_object
()
serializer
=
self
.
serializer_class
(
data
=
request
.
data
)
if
serializer
.
is_valid
():
users
=
serializer
.
validated_data
.
get
(
'users'
)
if
users
:
perm
.
users
.
add
(
*
tuple
(
users
))
return
Response
({
"msg"
:
"ok"
})
else
:
return
Response
({
"error"
:
serializer
.
errors
})
class
AssetPermissionRemoveAssetApi
(
RetrieveUpdateAPIView
):
"""
将用户从授权中移除,Detail页面会调用
"""
permission_classes
=
(
IsSuperUser
,)
serializer_class
=
serializers
.
AssetPermissionUpdateAssetSerializer
queryset
=
AssetPermission
.
objects
.
all
()
def
update
(
self
,
request
,
*
args
,
**
kwargs
):
perm
=
self
.
get_object
()
serializer
=
self
.
serializer_class
(
data
=
request
.
data
)
if
serializer
.
is_valid
():
assets
=
serializer
.
validated_data
.
get
(
'assets'
)
if
assets
:
perm
.
assets
.
remove
(
*
tuple
(
assets
))
return
Response
({
"msg"
:
"ok"
})
else
:
return
Response
({
"error"
:
serializer
.
errors
})
class
AssetPermissionAddAssetApi
(
RetrieveUpdateAPIView
):
permission_classes
=
(
IsSuperUser
,)
serializer_class
=
serializers
.
AssetPermissionUpdateAssetSerializer
queryset
=
AssetPermission
.
objects
.
all
()
def
update
(
self
,
request
,
*
args
,
**
kwargs
):
perm
=
self
.
get_object
()
serializer
=
self
.
serializer_class
(
data
=
request
.
data
)
if
serializer
.
is_valid
():
assets
=
serializer
.
validated_data
.
get
(
'assets'
)
if
assets
:
perm
.
assets
.
add
(
*
tuple
(
assets
))
return
Response
({
"msg"
:
"ok"
})
else
:
return
Response
({
"error"
:
serializer
.
errors
})
apps/perms/forms.py
View file @
24bdaeca
...
...
@@ -4,27 +4,64 @@ from __future__ import absolute_import, unicode_literals
from
django
import
forms
from
django.utils.translation
import
ugettext_lazy
as
_
from
.models
import
NodePermission
from
.hands
import
User
from
.models
import
AssetPermission
class
AssetPermissionForm
(
forms
.
ModelForm
):
users
=
forms
.
ModelMultipleChoiceField
(
queryset
=
User
.
objects
.
exclude
(
role
=
User
.
ROLE_APP
),
label
=
_
(
"User"
),
widget
=
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select users'
)
}
),
required
=
False
,
)
class
Meta
:
model
=
NodePermission
fields
=
[
'node'
,
'user_group'
,
'system_user'
,
'is_active'
,
'date_expired'
,
'comment'
,
]
model
=
AssetPermission
exclude
=
(
'id'
,
'date_created'
,
'created_by'
)
widgets
=
{
'
node'
:
forms
.
Select
(
attrs
=
{
'
style'
:
'display:none'
}
'
users'
:
forms
.
SelectMultiple
(
attrs
=
{
'
class'
:
'select2'
,
'data-placeholder'
:
_
(
"User"
)
}
),
'user_group
'
:
forms
.
Select
(
'user_group
s'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
"User group"
)}
),
'system_user'
:
forms
.
Select
(
'assets'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
"Asset"
)}
),
'nodes'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
"Node"
)}
),
'system_users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'System user'
)}
),
}
labels
=
{
'nodes'
:
_
(
"Node"
),
}
def
clean_user_groups
(
self
):
users
=
self
.
cleaned_data
.
get
(
'users'
)
user_groups
=
self
.
cleaned_data
.
get
(
'user_groups'
)
if
not
users
and
not
user_groups
:
raise
forms
.
ValidationError
(
_
(
"User or group at least one required"
))
return
self
.
cleaned_data
[
"user_groups"
]
def
clean_asset_groups
(
self
):
assets
=
self
.
cleaned_data
.
get
(
'assets'
)
asset_groups
=
self
.
cleaned_data
.
get
(
'asset_groups'
)
if
not
assets
and
not
asset_groups
:
raise
forms
.
ValidationError
(
_
(
"Asset or group at least one required"
))
def
clean_system_user
(
self
):
return
self
.
cleaned_data
[
'system_user'
]
return
self
.
cleaned_data
[
"asset_groups"
]
apps/perms/models.py
View file @
24bdaeca
...
...
@@ -4,70 +4,63 @@ from django.db import models
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils
import
timezone
from
common.utils
import
date_expired_default
from
common.utils
import
date_expired_default
,
set_or_append_attr_bulk
class
ValidManager
(
models
.
Manager
):
def
get_queryset
(
self
):
return
super
()
.
get_queryset
()
.
filter
(
is_active
=
True
)
\
.
filter
(
date_start__lt
=
timezone
.
now
())
\
.
filter
(
date_expired__gt
=
timezone
.
now
())
class
AssetPermission
(
models
.
Model
):
from
users.models
import
User
,
UserGroup
from
assets.models
import
Asset
,
AssetGroup
,
SystemUser
,
Cluster
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Name'
))
users
=
models
.
ManyToManyField
(
User
,
related_name
=
'asset_permissions'
,
blank
=
True
,
verbose_name
=
_
(
"User"
))
user_groups
=
models
.
ManyToManyField
(
UserGroup
,
related_name
=
'asset_permissions'
,
blank
=
True
,
verbose_name
=
_
(
"User group"
))
assets
=
models
.
ManyToManyField
(
Asset
,
related_name
=
'granted_by_permissions'
,
blank
=
True
,
verbose_name
=
_
(
"Asset"
))
asset_groups
=
models
.
ManyToManyField
(
AssetGroup
,
related_name
=
'granted_by_permissions'
,
blank
=
True
,
verbose_name
=
_
(
"Asset group
"
))
system_users
=
models
.
ManyToManyField
(
SystemUser
,
related_name
=
'granted_by_permissions'
,
verbose_name
=
_
(
"System user"
))
users
=
models
.
ManyToManyField
(
'users.User'
,
related_name
=
'asset_permissions'
,
blank
=
True
,
verbose_name
=
_
(
"User"
))
user_groups
=
models
.
ManyToManyField
(
'users.UserGroup'
,
related_name
=
'asset_permissions'
,
blank
=
True
,
verbose_name
=
_
(
"User group"
))
assets
=
models
.
ManyToManyField
(
'assets.Asset'
,
related_name
=
'granted_by_permissions'
,
blank
=
True
,
verbose_name
=
_
(
"Asset"
))
nodes
=
models
.
ManyToManyField
(
'assets.Node'
,
related_name
=
'granted_by_permissions'
,
blank
=
True
,
verbose_name
=
_
(
"Nodes
"
))
system_users
=
models
.
ManyToManyField
(
'assets.SystemUser'
,
related_name
=
'granted_by_permissions'
,
verbose_name
=
_
(
"System user"
))
is_active
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
'Active'
))
date_start
=
models
.
DateTimeField
(
default
=
timezone
.
now
,
verbose_name
=
_
(
"Date start"
))
date_expired
=
models
.
DateTimeField
(
default
=
date_expired_default
,
verbose_name
=
_
(
'Date expired'
))
created_by
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
verbose_name
=
_
(
'Created by'
))
date_created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
_
(
'Date created'
))
comment
=
models
.
TextField
(
verbose_name
=
_
(
'Comment'
),
blank
=
True
)
objects
=
models
.
Manager
()
valid
=
ValidManager
()
def
__str__
(
self
):
return
self
.
name
@property
def
id_str
(
self
):
return
str
(
self
.
id
)
@property
def
is_valid
(
self
):
if
self
.
date_expired
>
timezone
.
now
()
and
self
.
is_active
:
if
self
.
date_expired
>
timezone
.
now
()
>
self
.
date_start
and
self
.
is_active
:
return
True
return
False
def
get_granted_users
(
self
):
return
list
(
set
(
self
.
users
.
all
())
|
self
.
get_granted_user_groups_member
())
def
get_granted_user_groups_member
(
self
):
users
=
set
()
for
user_group
in
self
.
user_groups
.
all
():
for
user
in
user_group
.
users
.
all
():
setattr
(
user
,
'is_inherit_from_user_groups'
,
True
)
setattr
(
user
,
'inherit_from_user_groups'
,
getattr
(
user
,
'inherit_from_user_groups'
,
set
())
.
add
(
user_group
))
users
.
add
(
user
)
def
get_all_users
(
self
):
users
=
set
(
self
.
users
.
all
())
for
group
in
self
.
user_groups
.
all
():
_users
=
group
.
users
.
all
()
set_or_append_attr_bulk
(
_users
,
'inherit'
,
group
.
name
)
users
.
update
(
set
(
_users
))
return
users
def
get_granted_assets
(
self
):
return
list
(
set
(
self
.
assets
.
all
())
|
self
.
get_granted_asset_groups_member
())
def
get_granted_asset_groups_member
(
self
):
assets
=
set
()
for
asset_group
in
self
.
asset_groups
.
all
():
for
asset
in
asset_group
.
assets
.
all
():
setattr
(
asset
,
'is_inherit_from_asset_groups'
,
True
)
setattr
(
asset
,
'inherit_from_asset_groups'
,
getattr
(
asset
,
'inherit_from_user_groups'
,
set
())
.
add
(
asset_group
))
assets
.
add
(
asset
)
def
get_all_assets
(
self
):
assets
=
set
(
self
.
assets
.
all
())
for
node
in
self
.
nodes
.
all
():
_assets
=
node
.
get_all_assets
()
set_or_append_attr_bulk
(
_assets
,
'inherit'
,
node
.
value
)
assets
.
update
(
set
(
_assets
))
return
assets
def
check_system_user_in_assets
(
self
):
errors
=
{}
assets
=
self
.
get_granted_assets
()
clusters
=
set
([
asset
.
cluster
for
asset
in
assets
])
for
system_user
in
self
.
system_users
.
all
():
cluster_remain
=
clusters
-
set
(
system_user
.
cluster
.
all
())
if
cluster_remain
:
errors
[
system_user
]
=
cluster_remain
return
errors
class
NodePermission
(
models
.
Model
):
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
...
...
apps/perms/serializers.py
View file @
24bdaeca
# -*- coding: utf-8 -*-
#
from
django.utils.translation
import
ugettext_lazy
as
_
from
rest_framework
import
serializers
from
common.utils
import
get_object_or_none
from
common.fields
import
StringIDField
from
.models
import
AssetPermission
,
NodePermission
from
.models
import
AssetPermission
from
common.fields
import
StringManyToManyField
class
AssetPermissionCreateUpdateSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
NodePermission
fields
=
[
'id'
,
'node'
,
'user_group'
,
'system_user'
,
'is_active'
,
'date_expired'
]
model
=
AssetPermission
exclude
=
(
'id'
,
'created_by'
,
'date_created'
)
class
AssetPermissionListSerializer
(
serializers
.
ModelSerializer
):
node
=
StringIDField
(
read_only
=
True
)
user_group
=
StringIDField
(
read_only
=
True
)
system_user
=
StringIDField
(
read_only
=
True
)
users
=
StringManyToManyField
(
many
=
True
,
read_only
=
True
)
user_groups
=
StringManyToManyField
(
many
=
True
,
read_only
=
True
)
assets
=
StringManyToManyField
(
many
=
True
,
read_only
=
True
)
nodes
=
StringManyToManyField
(
many
=
True
,
read_only
=
True
)
system_users
=
StringManyToManyField
(
many
=
True
,
read_only
=
True
)
inherit
=
serializers
.
SerializerMethodField
()
class
Meta
:
model
=
Node
Permission
model
=
Asset
Permission
fields
=
'__all__'
@staticmethod
def
get_inherit
(
obj
):
if
hasattr
(
obj
,
'inherit'
):
return
obj
.
inherit
else
:
return
None
class
AssetPermissionUpdateUserSerializer
(
serializers
.
ModelSerializer
):
...
...
@@ -40,14 +45,3 @@ class AssetPermissionUpdateAssetSerializer(serializers.ModelSerializer):
model
=
AssetPermission
fields
=
[
'id'
,
'assets'
]
class
UserAssetPermissionCreateUpdateSerializer
(
AssetPermissionCreateUpdateSerializer
):
is_inherited
=
serializers
.
SerializerMethodField
()
@staticmethod
def
get_is_inherited
(
obj
):
if
getattr
(
obj
,
'inherited'
,
''
):
return
True
else
:
return
False
apps/perms/signals_handler.py
View file @
24bdaeca
# -*- coding: utf-8 -*-
#
from
django.db.models.signals
import
post_save
,
post_delete
from
django.db.models.signals
import
m2m_changed
from
django.dispatch
import
receiver
from
common.utils
import
get_logger
from
.models
import
Node
Permission
from
.models
import
Asset
Permission
logger
=
get_logger
(
__file__
)
@receiver
(
post_save
,
sender
=
NodePermission
,
dispatch_uid
=
"my_unique_identifier"
)
def
on_asset_permission_create_or_update
(
sender
,
instance
=
None
,
**
kwargs
):
if
instance
and
instance
.
node
and
instance
.
system_user
:
instance
.
system_user
.
nodes
.
add
(
instance
.
node
)
@receiver
(
m2m_changed
,
sender
=
AssetPermission
.
nodes
.
through
)
def
on_permission_nodes_changed
(
sender
,
instance
=
None
,
**
kwargs
):
if
isinstance
(
instance
,
AssetPermission
)
and
kwargs
[
'action'
]
==
'post_add'
:
logger
.
debug
(
"Asset permission nodes change signal received"
)
nodes
=
kwargs
[
'model'
]
.
objects
.
filter
(
pk__in
=
kwargs
[
'pk_set'
])
system_users
=
instance
.
system_users
.
all
()
for
system_user
in
system_users
:
system_user
.
nodes
.
add
(
*
tuple
(
nodes
))
@receiver
(
m2m_changed
,
sender
=
AssetPermission
.
assets
.
through
)
def
on_permission_assets_changed
(
sender
,
instance
=
None
,
**
kwargs
):
if
isinstance
(
instance
,
AssetPermission
)
and
kwargs
[
'action'
]
==
'post_add'
:
logger
.
debug
(
"Asset permission assets change signal received"
)
assets
=
kwargs
[
'model'
]
.
objects
.
filter
(
pk__in
=
kwargs
[
'pk_set'
])
system_users
=
instance
.
system_users
.
all
()
for
system_user
in
system_users
:
system_user
.
assets
.
add
(
*
tuple
(
assets
))
@receiver
(
m2m_changed
,
sender
=
AssetPermission
.
system_users
.
through
)
def
on_permission_system_users_changed
(
sender
,
instance
=
None
,
**
kwargs
):
if
isinstance
(
instance
,
AssetPermission
)
and
kwargs
[
'action'
]
==
'post_add'
:
logger
.
debug
(
"Asset permission system_users change signal received"
)
system_users
=
kwargs
[
'model'
]
.
objects
.
filter
(
pk__in
=
kwargs
[
'pk_set'
])
assets
=
instance
.
assets
.
all
()
nodes
=
instance
.
nodes
.
all
()
for
system_user
in
system_users
:
system_user
.
nodes
.
add
(
*
tuple
(
nodes
))
system_user
.
assets
.
add
(
*
tuple
(
assets
))
apps/perms/templates/perms/asset_permission_asset.html
View file @
24bdaeca
...
...
@@ -57,12 +57,12 @@
</tr>
</thead>
<tbody>
{% for asset in
page_obj
%}
{% for asset in
object_list
%}
<tr>
<td>
{{ asset.hostname }}
</td>
<td>
{{ asset.ip }}
</td>
<td>
<button
title=
"{{ asset.inherit
_from_asset_groups }}"
data-gid=
"{{ asset.id }}"
class=
"btn btn-danger btn-xs btn-remove-asset {% if asset.is_inherit_from_asset_groups
%} disabled {% endif %}"
type=
"button"
style=
"float: right;"
><i
class=
"fa fa-minus"
></i></button>
<button
title=
"{{ asset.inherit
}}"
data-gid=
"{{ asset.id }}"
class=
"btn btn-danger btn-xs btn-remove-asset {% if asset.inherit
%} disabled {% endif %}"
type=
"button"
style=
"float: right;"
><i
class=
"fa fa-minus"
></i></button>
</td>
</tr>
{% endfor %}
...
...
@@ -105,7 +105,7 @@
<div
class=
"panel panel-info"
>
<div
class=
"panel-heading"
>
<i
class=
"fa fa-info-circle"
></i>
{% trans 'Add
asset group
to this permission' %}
<i
class=
"fa fa-info-circle"
></i>
{% trans 'Add
node
to this permission' %}
</div>
<div
class=
"panel-body"
>
<table
class=
"table group_edit"
>
...
...
@@ -113,25 +113,25 @@
<form>
<tr>
<td
colspan=
"2"
class=
"no-borders"
>
<select
data-placeholder=
"{% trans 'Select
asset group
s' %}"
class=
"select2 group"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
{% for
asset_group in asset_group
s_remain %}
<option
value=
"{{
asset_group.id }}"
id=
"opt_{{ asset_group.id }}"
>
{{ asset_group.nam
e }}
</option>
<select
data-placeholder=
"{% trans 'Select
node
s' %}"
class=
"select2 group"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
{% for
node in node
s_remain %}
<option
value=
"{{
node.id }}"
id=
"opt_{{ node.id }}"
>
{{ node.valu
e }}
</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td
colspan=
"2"
class=
"no-borders"
>
<button
type=
"button"
class=
"btn btn-info btn-sm"
id=
"btn-add-
group
"
>
{% trans 'Join' %}
</button>
<button
type=
"button"
class=
"btn btn-info btn-sm"
id=
"btn-add-
node
"
>
{% trans 'Join' %}
</button>
</td>
</tr>
</form>
{% for
asset_group in asset_groups
%}
{% for
node in asset_permission.nodes.all
%}
<tr>
<td
><b
class=
"bdg_user_group"
data-gid=
{{
asset_group
.
id
}}
>
{{ asset_group.nam
e }}
</b></td>
<td
><b
class=
"bdg_user_group"
data-gid=
{{
node
.
id
}}
>
{{ node.valu
e }}
</b></td>
<td>
<button
class=
"btn btn-danger btn-xs btn-remove-
group
"
type=
"button"
style=
"float: right;"
><i
class=
"fa fa-minus"
></i></button>
<button
class=
"btn btn-danger btn-xs btn-remove-
node
"
type=
"button"
style=
"float: right;"
><i
class=
"fa fa-minus"
></i></button>
</td>
</tr>
{% endfor %}
...
...
@@ -179,10 +179,10 @@ function removeAssets(assets) {
});
}
function
update
Group
(
group
s
)
{
function
update
Nodes
(
node
s
)
{
var
the_url
=
"{% url 'api-perms:asset-permission-detail' pk=asset_permission.id %}"
;
var
body
=
{
asset_groups
:
group
s
nodes
:
node
s
};
APIUpdateAttr
({
url
:
the_url
,
...
...
@@ -231,17 +231,17 @@ $(document).ready(function () {
var
assets
=
[
asset_id
];
removeAssets
(
assets
)
})
.
on
(
'click'
,
'#btn-add-
group
'
,
function
()
{
.
on
(
'click'
,
'#btn-add-
node
'
,
function
()
{
if
(
Object
.
keys
(
jumpserver
.
nodes_selected
).
length
===
0
)
{
return
false
;
}
var
group
s
=
$
(
'.bdg_group'
).
map
(
function
()
{
var
node
s
=
$
(
'.bdg_group'
).
map
(
function
()
{
return
$
(
this
).
data
(
'gid'
);
}).
get
();
$
.
map
(
jumpserver
.
nodes_selected
,
function
(
group_name
,
index
)
{
group
s
.
push
(
index
);
node
s
.
push
(
index
);
$
(
'#opt_'
+
index
).
remove
();
$
(
'.group_edit tbody'
).
append
(
'<tr>'
+
...
...
@@ -251,17 +251,17 @@ $(document).ready(function () {
)
});
update
Group
(
group
s
);
update
Nodes
(
node
s
);
})
.
on
(
'click'
,
'.btn-remove-
group
'
,
function
()
{
.
on
(
'click'
,
'.btn-remove-
node
'
,
function
()
{
var
$this
=
$
(
this
);
var
$tr
=
$this
.
closest
(
'tr'
);
var
group
s
=
$
(
'.bdg_group'
).
map
(
function
()
{
var
node
s
=
$
(
'.bdg_group'
).
map
(
function
()
{
if
(
$
(
this
).
data
(
'gid'
)
!==
$this
.
data
(
'gid'
)){
return
$
(
this
).
data
(
'gid'
);
}
}).
get
();
update
Group
(
group
s
);
update
Nodes
(
node
s
);
$tr
.
remove
()
})
</script>
...
...
apps/perms/templates/perms/asset_permission_create_update.html
View file @
24bdaeca
...
...
@@ -28,23 +28,19 @@
</div>
</div>
<div
class=
"ibox-content"
>
{% if form.non_field_errors %}
<div
class=
"alert alert-danger"
>
{{ form.non_field_errors }}
</div>
{% endif %}
<form
method=
"post"
class=
"form-horizontal"
action=
""
>
{% csrf_token %}
<h3>
{% trans 'Basic' %}
</h3>
<div
class=
"form-group"
>
<label
class=
"col-md-2 control-label"
for=
"id_name"
>
{% trans 'Node' %}
</label>
<div
class=
"col-md-9"
>
<input
type=
"text"
class=
"form-control"
readonly
value=
"{{ form.node.initial }}"
>
</div>
</div>
{{ form.node }}
{% bootstrap_field form.user_group layout="horizontal" %}
{% bootstrap_field form.system_user layout="horizontal" %}
{% bootstrap_field form.name layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'User' %}
</h3>
{% bootstrap_field form.users layout="horizontal" %}
{% bootstrap_field form.user_groups layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Asset' %}
</h3>
{% bootstrap_field form.assets layout="horizontal" %}
{% bootstrap_field form.nodes layout="horizontal" %}
{% bootstrap_field form.system_users layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Other' %}
</h3>
<div
class=
"form-group"
>
...
...
@@ -53,17 +49,19 @@
{{ form.is_active }}
</div>
</div>
<div
class=
"form-group {% if form.date_expired.errors %} has-error {% endif %}"
id=
"date_5"
>
<div
class=
"form-group {% if form.date_expired.errors or form.date_start.errors %} has-error {% endif %}"
id=
"date_5"
>
<label
for=
"{{ form.date_expired.id_for_label }}"
class=
"col-sm-2 control-label"
>
{{ form.date_expired.label }}
</label>
<div
class=
"col-sm-9"
>
<div
class=
"input-
group date
"
>
<div
class=
"input-
daterange input-group"
id=
"datepicker
"
>
<span
class=
"input-group-addon"
><i
class=
"fa fa-calendar"
></i></span>
<input
id=
"{{ form.date_expired.id_for_label }}"
name=
"{{ form.date_expired.html_name }}"
type=
"text"
class=
"form-control"
value=
"{{ form.date_expired.value|date:'Y-m-d'|default:form.date_expired.value }}"
>
<input
type=
"text"
class=
"input-sm form-control"
name=
"date_start"
value=
"{{ form.date_start.value|date:'Y-m-d' }}"
>
<span
class=
"input-group-addon"
>
to
</span>
<input
type=
"text"
class=
"input-sm form-control"
name=
"date_expired"
value=
"{{ form.date_expired.value|date:'Y-m-d' }}"
>
</div>
<span
class=
"help-block "
>
{{ form.date_expired.errors }}
</span>
<span
class=
"help-block "
>
{{ form.date_start.errors }}
</span>
</div>
</div>
</div>
{% bootstrap_field form.comment layout="horizontal" %}
<div
class=
"form-group"
>
...
...
@@ -84,15 +82,14 @@
<script>
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
();
$
(
'.input-group.date'
).
datepicker
({
$
(
'#datepicker'
).
datepicker
({
format
:
"yyyy-mm-dd"
,
todayBtn
:
"linked"
,
keyboardNavigation
:
false
,
forceParse
:
false
,
calendarWeeks
:
true
,
autoclose
:
true
})
})
;
})
</script>
{% endblock %}
\ No newline at end of file
apps/perms/templates/perms/asset_permission_detail.html
View file @
24bdaeca
...
...
@@ -15,19 +15,19 @@
<div
class=
"panel-options"
>
<ul
class=
"nav nav-tabs"
>
<li
class=
"active"
>
<a
href=
"{% url 'perms:asset-permission-detail' pk=
asset_permission
.id %}"
class=
"text-center"
><i
class=
"fa fa-laptop"
></i>
{% trans 'Detail' %}
</a>
<a
href=
"{% url 'perms:asset-permission-detail' pk=
object
.id %}"
class=
"text-center"
><i
class=
"fa fa-laptop"
></i>
{% trans 'Detail' %}
</a>
</li>
<li>
<a
href=
"{% url 'perms:asset-permission-user-list' pk=
asset_permission
.id %}"
class=
"text-center"
>
<a
href=
"{% url 'perms:asset-permission-user-list' pk=
object
.id %}"
class=
"text-center"
>
<i
class=
"fa fa-bar-chart-o"
></i>
{% trans 'Users and user groups' %}
</a>
</li>
<li>
<a
href=
"{% url 'perms:asset-permission-asset-list' pk=
asset_permission.id
%}"
class=
"text-center"
>
<a
href=
"{% url 'perms:asset-permission-asset-list' pk=
object.id
%}"
class=
"text-center"
>
<i
class=
"fa fa-bar-chart-o"
></i>
{% trans 'Assets and asset groups' %}
</a>
</li>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-default"
href=
"{% url 'perms:asset-permission-update' pk=
asset_permission
.id %}"
><i
class=
"fa fa-edit"
></i>
{% trans 'Update' %}
</a>
<a
class=
"btn btn-outline btn-default"
href=
"{% url 'perms:asset-permission-update' pk=
object
.id %}"
><i
class=
"fa fa-edit"
></i>
{% trans 'Update' %}
</a>
</li>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-danger btn-delete-perm"
>
...
...
@@ -40,7 +40,7 @@
<div
class=
"col-sm-7"
style=
"padding-left: 0;"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-title"
>
<span
class=
"label"
><b>
{{
asset_permission
.name }}
</b></span>
<span
class=
"label"
><b>
{{
object
.name }}
</b></span>
<div
class=
"ibox-tools"
>
<a
class=
"collapse-link"
>
<i
class=
"fa fa-chevron-up"
></i>
...
...
@@ -60,43 +60,47 @@
<tbody>
<tr
class=
"no-borders-tr"
>
<td>
{% trans 'Name' %}:
</td>
<td><b>
{{
asset_permission
.name }}
</b></td>
<td><b>
{{
object
.name }}
</b></td>
</tr>
<tr>
<td>
{% trans 'User count' %}:
</td>
<td><b>
{{
asset_permission
.users.count }}
</b></td>
<td><b>
{{
object
.users.count }}
</b></td>
</tr>
<tr>
<td>
{% trans 'User group count' %}:
</td>
<td><b>
{{
asset_permission
.users.count }}
</b></td>
<td><b>
{{
object
.users.count }}
</b></td>
</tr>
<tr>
<td>
{% trans 'Asset count' %}:
</td>
<td><b>
{{
asset_permission
.assets.count }}
</b></td>
<td><b>
{{
object
.assets.count }}
</b></td>
</tr>
<tr>
<td>
{% trans '
Asset group
count' %}:
</td>
<td><b>
{{
asset_permission.asset_group
s.count }}
</b></td>
<td>
{% trans '
Node
count' %}:
</td>
<td><b>
{{
object.node
s.count }}
</b></td>
</tr>
<tr>
<td>
{% trans 'System user count' %}:
</td>
<td><b>
{{ asset_permission.system_users.count }}
</b></td>
<td><b>
{{ object.system_users.count }}
</b></td>
</tr>
<tr>
<td>
{% trans 'Date start' %}:
</td>
<td><b>
{{ object.date_start }}
</b></td>
</tr>
<tr>
<td>
{% trans 'Date expired' %}:
</td>
<td><b>
{{
asset_permission
.date_expired }}
</b></td>
<td><b>
{{
object
.date_expired }}
</b></td>
</tr>
<tr>
<td>
{% trans 'Date created' %}:
</td>
<td><b>
{{
asset_permission
.date_created }}
</b></td>
<td><b>
{{
object
.date_created }}
</b></td>
</tr>
<tr>
<td>
{% trans 'Created by' %}:
</td>
<td><b>
{{
asset_permission
.created_by }}
</b></td>
<td><b>
{{
object
.created_by }}
</b></td>
</tr>
<tr>
<td>
{% trans 'Comment' %}:
</td>
<td><b>
{{
asset_permission
.comment }}
</b></td>
<td><b>
{{
object
.comment }}
</b></td>
</tr>
</tbody>
</table>
...
...
@@ -117,7 +121,7 @@
<td><span
style=
"float: right"
>
<div
class=
"switch"
>
<div
class=
"onoffswitch"
>
<input
type=
"checkbox"
{%
if
asset_permission
.
is_active
%}
checked
{%
endif
%}
class=
"onoffswitch-checkbox"
id=
"is_active"
>
<input
type=
"checkbox"
{%
if
object
.
is_active
%}
checked
{%
endif
%}
class=
"onoffswitch-checkbox"
id=
"is_active"
>
<label
class=
"onoffswitch-label"
for=
"is_active"
>
<span
class=
"onoffswitch-inner"
></span>
<span
class=
"onoffswitch-switch"
></span>
...
...
@@ -155,7 +159,7 @@
</tr>
</form>
{% for system_user in
system_users
%}
{% for system_user in
object.system_users.all
%}
<tr
{%
if
forloop
.
counter =
=
1
%}
class=
"no-borders-tr"
{%
endif
%}
>
<td
><b
class=
"bdg-system-user"
data-uid=
{{
system_user
.
id
}}
>
{{ system_user.name }}
</b></td>
<td>
...
...
@@ -179,7 +183,7 @@
jumpserver
.
system_users_selected
=
{};
function
updateSystemUser
(
system_users
)
{
var
the_url
=
"{% url 'api-perms:asset-permission-detail' pk=
asset_permission
.id %}"
;
var
the_url
=
"{% url 'api-perms:asset-permission-detail' pk=
object
.id %}"
;
var
body
=
{
system_users
:
Object
.
assign
([],
system_users
)
};
...
...
@@ -203,7 +207,7 @@ $(document).ready(function () {
.
on
(
'click'
,
'.btn-delete-perm'
,
function
()
{
var
$this
=
$
(
this
);
var
name
=
"{{ asset_permission.name }}"
;
var
uid
=
"{{
asset_permission
.id }}"
;
var
uid
=
"{{
object
.id }}"
;
var
the_url
=
'{% url "api-perms:asset-permission-detail" pk=DEFAULT_PK %}'
.
replace
(
'{{ DEFAULT_PK }}'
,
uid
);
var
redirect_url
=
"{% url 'perms:asset-permission-list' %}"
;
objectDelete
(
$this
,
name
,
the_url
,
redirect_url
);
...
...
@@ -238,7 +242,7 @@ $(document).ready(function () {
updateSystemUser
(
system_users
);
$tr
.
remove
()
}).
on
(
'click'
,
'#is_active'
,
function
()
{
var
the_url
=
'{% url "api-perms:asset-permission-detail" pk=
asset_permission
.id %}'
;
var
the_url
=
'{% url "api-perms:asset-permission-detail" pk=
object
.id %}'
;
var
checked
=
$
(
this
).
prop
(
'checked'
);
var
body
=
{
'is_active'
:
checked
...
...
apps/perms/templates/perms/asset_permission_list.html
View file @
24bdaeca
...
...
@@ -3,41 +3,29 @@
{% load i18n %}
{% block custom_head_css_js %}
<link
href=
"{% static "
css
/
plugins
/
footable
/
footable
.
core
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static 'css/plugins/datepicker/datepicker3.css' %}"
rel=
"stylesheet"
>
<link
href=
"{% static 'css/plugins/select2/select2.min.css' %}"
rel=
"stylesheet"
>
<script
src=
"{% static 'js/plugins/select2/select2.full.min.js' %}"
></script>
<link
href=
"{% static 'css/plugins/jstree/style.min.css' %}"
rel=
"stylesheet"
>
<link
href=
"{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}"
rel=
"stylesheet"
>
<script
type=
"text/javascript"
src=
"{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"
></script>
<style
type=
"text/css"
>
div
#rMenu
{
position
:
absolute
;
visibility
:
hidden
;
text-align
:
left
;
top
:
100%
;
left
:
0
;
z-index
:
1000
;
float
:
left
;
padding
:
5px
0
;
margin
:
2px
0
0
;
list-style
:
none
;
background-clip
:
padding-box
;
<style>
.toggle
{
cursor
:
pointer
;
}
div
#rMenu
li
{
margin
:
1px
0
;
cursor
:
pointer
;
{#
list-style
:
none
outside
none
;
#
}
.detail-key
{
width
:
70px
;
}
.dropdown
a
:hover
{
background-color
:
#f1f1f1
}
</style>
</style>
{% endblock %}
{% block content %}
<div
class=
"wrapper wrapper-content"
>
<div
class=
"row"
>
<div
class=
"col-lg-3"
id=
"split-left"
>
<div
class=
"col-lg-3"
id=
"split-left"
style=
"padding-left: 3px"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-content mailbox-content"
style=
"padding-top: 0"
>
<div
class=
"ibox-content mailbox-content"
style=
"padding-top: 0
;padding-left: 1px
"
>
<div
class=
"file-manager "
>
<div
id=
"assetTree"
class=
"ztree"
>
</div>
...
...
@@ -61,16 +49,16 @@
<table
class=
"table table-striped table-bordered table-hover"
id=
"permission_list_table"
style=
"width: 100%"
>
<thead>
<tr>
<th
class=
"text-center"
>
<input
type=
"checkbox"
id=
"check_all"
class=
"ipt_check_all"
>
</th>
<th
class=
"text-center"
>
{% trans 'Node
' %}
</th>
<th
class=
"text-center"
>
{% trans 'User group
' %}
</th>
<th
class=
"text-center"
>
{% trans 'System user'
%}
</th>
<th
class=
"text-center"
>
{% trans 'Is active
' %}
</th>
<th
class=
"text-center"
>
{% trans 'Date expired
' %}
</th>
<th
class=
"text-center"
>
{% trans 'Action' %}
</th>
</tr>
<th></th
>
<th>
{% trans 'Name' %}
</th
>
<th
class=
"text-center"
>
{% trans 'User' %}
</th>
<th
class=
"text-center"
>
{% trans 'User group
' %}
</th>
<th
class=
"text-center"
>
{% trans 'Asset
' %}
</th>
<th
class=
"text-center"
>
{% trans 'Node'
%}
</th>
<th
class=
"text-center"
>
{% trans 'System user
' %}
</th>
<th
class=
"text-center"
>
{% trans 'Active
' %}
</th>
<th
class=
"text-center"
>
{% trans 'Action' %}
</th>
</tr>
</thead>
<tbody>
</tbody>
...
...
@@ -82,54 +70,142 @@
{% endblock %}
{% block custom_foot_js %}
<script
src=
"{% static "
js
/
plugins
/
footable
/
footable
.
all
.
min
.
js
"
%}"
></script>
<script
src=
"{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"
></script>
<script>
var
zTree
,
rMenu
,
table
,
show
=
0
;
var
zTree
,
table
,
show
=
0
;
function
onSelected
(
event
,
treeNode
)
{
setCookie
(
'node_selected'
,
treeNode
.
id
);
var
url
=
table
.
ajax
.
url
();
if
(
treeNode
.
is_asset
)
{
url
=
setUrlParam
(
url
,
'node'
,
""
);
url
=
setUrlParam
(
url
,
'asset'
,
treeNode
.
id
)
}
else
{
url
=
setUrlParam
(
url
,
'asset'
,
""
);
url
=
setUrlParam
(
url
,
'node'
,
treeNode
.
id
)
}
setCookie
(
'node_selected'
,
treeNode
.
id
);
table
.
ajax
.
url
(
url
);
table
.
ajax
.
reload
();
}
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
[
"pId"
]
=
value
[
"parent"
];
value
[
"name"
]
=
value
[
"value"
];
value
[
"isParent"
]
=
value
[
"assets_amount"
]
!==
0
;
value
[
"iconSkin"
]
=
value
[
"is_asset"
]
?
"file"
:
null
;
});
return
childNodes
;
}
function
beforeAsync
(
treeId
,
treeNode
)
{
return
true
;
}
function
makeLabel
(
data
)
{
return
"<label class='detail-key'><b>"
+
data
[
0
]
+
": </b></label>"
+
data
[
1
]
+
"</br>"
}
function
format
(
d
)
{
var
data
=
""
;
if
(
d
.
users
.
length
>
0
)
{
data
+=
makeLabel
([
"{% trans 'User' %}"
,
d
.
users
.
join
(
", "
)])
}
if
(
d
.
user_groups
.
length
>
0
)
{
data
+=
makeLabel
([
"{% trans 'User group' %}"
,
d
.
user_groups
.
join
(
", "
)])
}
if
(
d
.
assets
.
length
>
0
)
{
data
+=
makeLabel
([
"{% trans 'Asset' %}"
,
d
.
assets
.
join
(
", "
)])
}
if
(
d
.
nodes
.
length
>
0
)
{
data
+=
makeLabel
([
"{% trans 'Node' %}"
,
d
.
nodes
.
join
(
", "
)])
}
if
(
d
.
system_users
.
length
>
0
)
{
data
+=
makeLabel
([
"{% trans 'System user' %}"
,
d
.
system_users
.
join
(
", "
)])
}
return
data
}
function
initTable
()
{
var
options
=
{
ele
:
$
(
'#permission_list_table'
),
toggle
:
true
,
columnDefs
:
[
{
targets
:
1
,
createdCell
:
function
(
td
,
cellData
)
{
var
html
=
'<a href="{% url '
assets
:
asset
-
list
' %}?node=99899">'
+
cellData
.
name
+
'</a>'
;
$
(
td
).
html
(
html
.
replace
(
"99899"
,
cellData
.
pk
));
{
targets
:
0
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
$
(
td
).
addClass
(
"toggle"
);
$
(
td
).
html
(
"<i class='fa fa-angle-right'></i>"
);
}},
{
targets
:
1
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
detail_btn
=
'<a href="{% url "perms:asset-permission-detail" pk=DEFAULT_PK %}">'
+
cellData
+
'</a>'
;
$
(
td
).
html
(
detail_btn
.
replace
(
'{{ DEFAULT_PK }}'
,
rowData
.
id
));
}},
{
targets
:
2
,
createdCell
:
function
(
td
,
cellData
)
{
var
html
=
'<a href="{% url "users:user-group-detail" pk=DEFAULT_PK %}">'
+
cellData
.
name
+
'</a>'
;
$
(
td
).
html
(
html
.
replace
(
"{{ DEFAULT_PK }}"
,
cellData
.
pk
))
var
num
=
cellData
.
length
;
$
(
td
).
html
(
num
);
}},
{
targets
:
3
,
createdCell
:
function
(
td
,
cellData
)
{
var
html
=
'<a href="{% url '
assets
:
system
-
user
-
detail
' pk=DEFAULT_PK %}">'
+
cellData
.
name
+
'</a>'
;
$
(
td
).
html
(
html
.
replace
(
"{{ DEFAULT_PK }}"
,
cellData
.
pk
)
);
var
num
=
cellData
.
length
;
$
(
td
).
html
(
num
);
}},
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
)
{
var
num
=
cellData
.
length
;
$
(
td
).
html
(
num
);
}},
{
targets
:
5
,
createdCell
:
function
(
td
,
cellData
)
{
var
num
=
cellData
.
length
;
$
(
td
).
html
(
num
);
}},
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
)
{
var
num
=
cellData
.
length
;
$
(
td
).
html
(
num
);
}},
{
targets
:
7
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
!
cellData
)
{
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
}
else
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
}},
{
targets
:
5
,
createdCell
:
function
(
td
,
cellData
)
{
var
date_expired
=
cellData
.
split
(
" "
);
if
(
date_expired
&&
date_expired
.
length
===
3
)
{
$
(
td
).
html
(
date_expired
[
0
]);
}
else
{
$
(
td
).
html
(
cellData
);
}
}},
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
name
=
rowData
.
user_group
.
name
+
"=>"
+
rowData
.
system_user
.
name
+
"=>"
+
rowData
.
node
.
name
;
{
targets
:
8
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
update_btn
=
'<a href="{% url "perms:asset-permission-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
var
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>'
var
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}"
mark=1
data-name="99991938">{% trans "Delete" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
)
.
replace
(
'99991938'
,
name
);
.
replace
(
'99991938'
,
rowData
.
name
);
if
(
rowData
.
inherit
)
{
del_btn
=
del_btn
.
replace
(
"mark"
,
"disabled"
)
}
$
(
td
).
html
(
update_btn
+
del_btn
);
}}
],
ajax_url
:
'{% url "api-perms:asset-permission-list" %}'
,
columns
:
[
{
data
:
"id"
},
{
data
:
"node"
},
{
data
:
"user_group"
},
{
data
:
"system_user"
},
{
data
:
"is_active"
},
{
data
:
"date_expired"
},
{
data
:
"id"
}
{
data
:
"id"
},
{
data
:
"name"
},
{
data
:
"users"
},
{
data
:
"user_groups"
},
{
data
:
"assets"
},
{
data
:
"nodes"
},
{
data
:
"system_users"
},
{
data
:
"is_active"
,
orderable
:
false
},
{
data
:
"id"
,
orderable
:
false
}
],
select
:
{},
op_html
:
$
(
'#actions'
).
html
()
};
table
=
jumpserver
.
initDataTable
(
options
);
...
...
@@ -137,32 +213,6 @@ function initTable() {
}
function
onSelected
(
event
,
treeNode
)
{
var
url
=
table
.
ajax
.
url
();
url
=
setUrlParam
(
url
,
"node_id"
,
treeNode
.
id
);
setCookie
(
'node_selected'
,
treeNode
.
id
);
table
.
ajax
.
url
(
url
);
table
.
ajax
.
reload
();
}
function
selectQueryNode
()
{
var
query_node_id
=
$
.
getUrlParam
(
"node"
);
var
cookie_node_id
=
getCookie
(
'node_selected'
);
var
node
;
var
node_id
;
if
(
query_node_id
!==
null
)
{
node_id
=
query_node_id
}
else
if
(
cookie_node_id
!==
null
)
{
node_id
=
cookie_node_id
;
}
node
=
zTree
.
getNodesByParam
(
"id"
,
node_id
,
null
);
if
(
node
){
zTree
.
selectNode
(
node
[
0
]);
}
}
function
initTree
()
{
var
setting
=
{
view
:
{
...
...
@@ -174,25 +224,32 @@ function initTree() {
enable
:
true
}
},
async
:
{
enable
:
true
,
url
:
"{% url 'api-assets:node-children-2' %}?assets=1"
,
autoParam
:[
"id"
,
"name=n"
,
"level=lv"
],
dataFilter
:
filter
,
type
:
'get'
},
callback
:
{
onSelected
:
onSelected
onSelected
:
onSelected
,
beforeAsync
:
beforeAsync
}
};
var
zNodes
=
[];
$
.
get
(
"{% url 'api-assets:node-
list
' %}"
,
function
(
data
,
status
){
$
.
get
(
"{% url 'api-assets:node-
children-2
' %}"
,
function
(
data
,
status
){
$
.
each
(
data
,
function
(
index
,
value
)
{
value
[
"pId"
]
=
value
[
"parent"
];
{
#
if
(
value
[
"key"
]
===
"0"
)
{
#
}
value
[
"open"
]
=
true
;
{
#
}
#
}
value
[
"name"
]
=
value
[
"value"
]
value
[
"isParent"
]
=
value
[
"assets_amount"
]
!==
0
;
value
[
"name"
]
=
value
[
"value"
];
value
[
"open"
]
=
value
[
"key"
]
===
"0"
;
});
zNodes
=
data
;
{
#
$
.
fn
.
zTree
.
init
(
$
(
"#assetTree"
),
setting
);
#
}
$
.
fn
.
zTree
.
init
(
$
(
"#assetTree"
),
setting
,
zNodes
);
zTree
=
$
.
fn
.
zTree
.
getZTreeObj
(
"assetTree"
);
rMenu
=
$
(
"#rMenu"
);
selectQueryNode
();
selectQueryNode
();
});
}
...
...
@@ -226,12 +283,41 @@ $(document).ready(function(){
.
on
(
'click'
,
'.btn-create-permission'
,
function
()
{
var
url
=
"{% url 'perms:asset-permission-create' %}"
;
var
nodes
=
zTree
.
getSelectedNodes
();
var
current_node
;
if
(
nodes
&&
nodes
.
length
===
1
){
current_node
=
nodes
[
0
];
url
+=
"?node_id="
+
current_node
.
id
;
}
var
_nodes
=
[];
var
_assets
=
[];
$
.
each
(
nodes
,
function
(
id
,
node
)
{
if
(
node
.
is_asset
)
{
_assets
.
push
(
node
.
id
)
}
else
{
_nodes
.
push
(
node
.
id
)
}
});
url
+=
"?assets="
+
_assets
.
join
(
","
)
+
"&nodes="
+
_nodes
.
join
(
","
);
window
.
open
(
url
,
'_self'
);
}).
on
(
'click'
,
'.toggle'
,
function
(
e
)
{
e
.
preventDefault
();
var
detailRows
=
[];
var
tr
=
$
(
this
).
closest
(
'tr'
);
var
row
=
table
.
row
(
tr
);
var
idx
=
$
.
inArray
(
tr
.
attr
(
'id'
),
detailRows
);
if
(
row
.
child
.
isShown
())
{
tr
.
removeClass
(
'details'
);
row
.
child
.
hide
();
// Remove from the 'open' array
detailRows
.
splice
(
idx
,
1
);
}
else
{
tr
.
addClass
(
'details'
);
$
(
'.toggle i'
).
removeClass
(
'fa-angle-right'
).
addClass
(
'fa-angle-down'
);
row
.
child
(
format
(
row
.
data
())).
show
();
// Add to the 'open' array
if
(
idx
===
-
1
)
{
detailRows
.
push
(
tr
.
attr
(
'id'
));
}
}
})
</script>
...
...
apps/perms/templates/perms/asset_permission_user.html
View file @
24bdaeca
...
...
@@ -57,12 +57,12 @@
</tr>
</thead>
<tbody>
{% for user in
page_obj
%}
{% for user in
object_list
%}
<tr>
<td>
{{ user.name }}
</td>
<td>
{{ user.username }}
</td>
<td>
<button
class=
"btn btn-danger btn-xs btn-remove-user {% if user.i
s_inherit_from_user_groups
%} disabled {% endif %}"
data-gid=
"{{ user.id }}"
type=
"button"
style=
"float: right;"
><i
class=
"fa fa-minus"
></i></button>
<button
class=
"btn btn-danger btn-xs btn-remove-user {% if user.i
nherit
%} disabled {% endif %}"
data-gid=
"{{ user.id }}"
type=
"button"
style=
"float: right;"
><i
class=
"fa fa-minus"
></i></button>
</td>
</tr>
{% endfor %}
...
...
@@ -127,7 +127,7 @@
</tr>
</form>
{% for user_group in
user_groups
%}
{% for user_group in
asset_permission.user_groups.all
%}
<tr>
<td
><b
class=
"bdg_group"
data-gid=
{{
user_group
.
id
}}
>
{{ user_group.name }}
</b></td>
<td>
...
...
apps/perms/urls/api_urls.py
View file @
24bdaeca
...
...
@@ -11,17 +11,50 @@ router.register('v1/asset-permissions', api.AssetPermissionViewSet, 'asset-permi
urlpatterns
=
[
# 查询某个用户授权的资产和资产组
url
(
r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
UserGrantedAssetsApi
.
as_view
(),
name
=
'user-assets'
),
url
(
r'^v1/user/assets/$'
,
api
.
UserGrantedAssetsApi
.
as_view
(),
name
=
'my-assets'
),
url
(
r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$'
,
api
.
UserGrantedNodesApi
.
as_view
(),
name
=
'user-nodes'
),
url
(
r'^v1/user/nodes/$'
,
api
.
UserGrantedNodesApi
.
as_view
(),
name
=
'my-nodes'
),
url
(
r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$'
,
api
.
UserGrantedNodesWithAssetsApi
.
as_view
(),
name
=
'user-nodes-assets'
),
url
(
r'^v1/user/nodes-assets/$'
,
api
.
UserGrantedNodesWithAssetsApi
.
as_view
(),
name
=
'my-nodes-assets'
),
url
(
r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
UserGrantedAssetsApi
.
as_view
(),
name
=
'user-assets'
),
url
(
r'^v1/user/assets/$'
,
api
.
UserGrantedAssetsApi
.
as_view
(),
name
=
'my-assets'
),
url
(
r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$'
,
api
.
UserGrantedNodesApi
.
as_view
(),
name
=
'user-nodes'
),
url
(
r'^v1/user/nodes/$'
,
api
.
UserGrantedNodesApi
.
as_view
(),
name
=
'my-nodes'
),
url
(
r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
UserGrantedNodeAssetsApi
.
as_view
(),
name
=
'user-node-assets'
),
url
(
r'^v1/user/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
UserGrantedNodeAssetsApi
.
as_view
(),
name
=
'my-node-assets'
),
url
(
r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$'
,
api
.
UserGrantedNodesWithAssetsApi
.
as_view
(),
name
=
'user-nodes-assets'
),
url
(
r'^v1/user/nodes-assets/$'
,
api
.
UserGrantedNodesWithAssetsApi
.
as_view
(),
name
=
'my-nodes-assets'
),
# 查询某个用户组授权的资产和资产组
url
(
r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
UserGroupGrantedAssetsApi
.
as_view
(),
name
=
'user-group-assets'
),
url
(
r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$'
,
api
.
UserGroupGrantedNodesApi
.
as_view
(),
name
=
'user-group-nodes'
),
url
(
r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$'
,
api
.
UserGroupGrantedNodesWithAssetsApi
.
as_view
(),
name
=
'user-group-nodes-assets'
),
url
(
r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
UserGroupGrantedAssetsApi
.
as_view
(),
name
=
'user-group-assets'
),
url
(
r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$'
,
api
.
UserGroupGrantedNodesApi
.
as_view
(),
name
=
'user-group-nodes'
),
url
(
r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$'
,
api
.
UserGroupGrantedNodesWithAssetsApi
.
as_view
(),
name
=
'user-group-nodes-assets'
),
url
(
r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
UserGroupGrantedNodeAssetsApi
.
as_view
(),
name
=
'user-group-node-assets'
),
# 用户和资产授权变更
url
(
r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/user/remove/$'
,
api
.
AssetPermissionRemoveUserApi
.
as_view
(),
name
=
'asset-permission-remove-user'
),
url
(
r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/user/add/$'
,
api
.
AssetPermissionAddUserApi
.
as_view
(),
name
=
'asset-permission-add-user'
),
url
(
r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/asset/remove/$'
,
api
.
AssetPermissionRemoveAssetApi
.
as_view
(),
name
=
'asset-permission-remove-asset'
),
url
(
r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/asset/add/$'
,
api
.
AssetPermissionAddAssetApi
.
as_view
(),
name
=
'asset-permission-add-asset'
),
# 验证用户是否有某个资产和系统用户的权限
url
(
r'v1/asset-permission/user/validate/$'
,
api
.
ValidateUserAssetPermissionView
.
as_view
(),
name
=
'validate-user-asset-permission'
),
...
...
apps/perms/urls/views_urls.py
View file @
24bdaeca
...
...
@@ -9,10 +9,10 @@ urlpatterns = [
url
(
r'^asset-permission$'
,
views
.
AssetPermissionListView
.
as_view
(),
name
=
'asset-permission-list'
),
url
(
r'^asset-permission/create$'
,
views
.
AssetPermissionCreateView
.
as_view
(),
name
=
'asset-permission-create'
),
url
(
r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/update$'
,
views
.
AssetPermissionUpdateView
.
as_view
(),
name
=
'asset-permission-update'
),
#
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})$', views.AssetPermissionDetailView.as_view(),name='asset-permission-detail'),
url
(
r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})$'
,
views
.
AssetPermissionDetailView
.
as_view
(),
name
=
'asset-permission-detail'
),
url
(
r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/delete$'
,
views
.
AssetPermissionDeleteView
.
as_view
(),
name
=
'asset-permission-delete'
),
#
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/user$', views.AssetPermissionUserView.as_view(), name='asset-permission-user-list'),
#
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/asset$', views.AssetPermissionAssetView.as_view(), name='asset-permission-asset-list'),
url
(
r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/user$'
,
views
.
AssetPermissionUserView
.
as_view
(),
name
=
'asset-permission-user-list'
),
url
(
r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/asset$'
,
views
.
AssetPermissionAssetView
.
as_view
(),
name
=
'asset-permission-asset-list'
),
]
apps/perms/utils.py
View file @
24bdaeca
...
...
@@ -2,17 +2,204 @@
from
__future__
import
absolute_import
,
unicode_literals
import
collections
from
collections
import
defaultdict
from
django.utils
import
timezone
from
django.utils.translation
import
ugettext
as
_
import
copy
from
common.utils
import
setattr_bulk
,
get_logger
from
.models
import
Node
Permission
from
common.utils
import
set
_or_append_
attr_bulk
,
get_logger
from
.models
import
Asset
Permission
logger
=
get_logger
(
__file__
)
class
AssetPermissionUtil
:
@staticmethod
def
get_user_permissions
(
user
):
return
AssetPermission
.
valid
.
all
()
.
filter
(
users
=
user
)
@staticmethod
def
get_user_group_permissions
(
user_group
):
return
AssetPermission
.
valid
.
all
()
.
filter
(
user_groups
=
user_group
)
@staticmethod
def
get_asset_permissions
(
asset
):
return
AssetPermission
.
valid
.
all
()
.
filter
(
assets
=
asset
)
@staticmethod
def
get_node_permissions
(
node
):
return
AssetPermission
.
valid
.
all
()
.
filter
(
nodes
=
node
)
@staticmethod
def
get_system_user_permissions
(
system_user
):
return
AssetPermission
.
objects
.
all
()
.
filter
(
system_users
=
system_user
)
@classmethod
def
get_user_group_nodes
(
cls
,
group
):
nodes
=
defaultdict
(
set
)
permissions
=
cls
.
get_user_group_permissions
(
group
)
for
perm
in
permissions
:
_nodes
=
perm
.
nodes
.
all
()
_system_users
=
perm
.
system_users
.
all
()
set_or_append_attr_bulk
(
_nodes
,
'permission'
,
perm
.
id
)
for
node
in
_nodes
:
nodes
[
node
]
.
update
(
set
(
_system_users
))
return
nodes
@classmethod
def
get_user_group_assets_direct
(
cls
,
group
):
assets
=
defaultdict
(
set
)
permissions
=
cls
.
get_user_group_permissions
(
group
)
for
perm
in
permissions
:
_assets
=
perm
.
assets
.
all
()
_system_users
=
perm
.
system_users
.
all
()
set_or_append_attr_bulk
(
_assets
,
'permission'
,
perm
.
id
)
for
asset
in
_assets
:
assets
[
asset
]
.
update
(
set
(
_system_users
))
return
assets
@classmethod
def
get_user_group_nodes_assets
(
cls
,
group
):
assets
=
defaultdict
(
set
)
nodes
=
cls
.
get_user_group_nodes
(
group
)
for
node
,
_system_users
in
nodes
.
items
():
_assets
=
node
.
get_all_assets
()
set_or_append_attr_bulk
(
_assets
,
'inherit_node'
,
node
.
id
)
set_or_append_attr_bulk
(
_assets
,
'permission'
,
getattr
(
node
,
'permission'
,
None
))
for
asset
in
_assets
:
assets
[
asset
]
.
update
(
set
(
_system_users
))
return
assets
@classmethod
def
get_user_group_assets
(
cls
,
group
):
assets
=
defaultdict
(
set
)
_assets
=
cls
.
get_user_group_assets_direct
(
group
)
_nodes_assets
=
cls
.
get_user_group_nodes_assets
(
group
)
for
asset
,
_system_users
in
_assets
.
items
():
assets
[
asset
]
.
update
(
set
(
_system_users
))
for
asset
,
_system_users
in
_nodes_assets
.
items
():
assets
[
asset
]
.
update
(
set
(
_system_users
))
return
assets
@classmethod
def
get_user_group_nodes_with_assets
(
cls
,
user
):
"""
:param user:
:return: {node: {asset: set(su1, su2)}}
"""
nodes
=
defaultdict
(
dict
)
_assets
=
cls
.
get_user_group_assets
(
user
)
for
asset
,
_system_users
in
_assets
.
items
():
_nodes
=
asset
.
get_nodes
()
for
node
in
_nodes
:
if
asset
in
nodes
[
node
]:
nodes
[
node
][
asset
]
.
update
(
_system_users
)
else
:
nodes
[
node
][
asset
]
=
_system_users
return
nodes
@classmethod
def
get_user_assets_direct
(
cls
,
user
):
assets
=
defaultdict
(
set
)
permissions
=
list
(
cls
.
get_user_permissions
(
user
))
for
perm
in
permissions
:
_assets
=
perm
.
assets
.
all
()
_system_users
=
perm
.
system_users
.
all
()
set_or_append_attr_bulk
(
_assets
,
'permission'
,
perm
.
id
)
for
asset
in
_assets
:
assets
[
asset
]
.
update
(
set
(
_system_users
))
return
assets
@classmethod
def
get_user_nodes_direct
(
cls
,
user
):
nodes
=
defaultdict
(
set
)
permissions
=
cls
.
get_user_permissions
(
user
)
for
perm
in
permissions
:
_nodes
=
perm
.
nodes
.
all
()
_system_users
=
perm
.
system_users
.
all
()
set_or_append_attr_bulk
(
_nodes
,
'permission'
,
perm
.
id
)
for
node
in
_nodes
:
nodes
[
node
]
.
update
(
set
(
_system_users
))
return
nodes
@classmethod
def
get_user_nodes_assets_direct
(
cls
,
user
):
assets
=
defaultdict
(
set
)
nodes
=
cls
.
get_user_nodes_direct
(
user
)
for
node
,
_system_users
in
nodes
.
items
():
_assets
=
node
.
get_all_assets
()
set_or_append_attr_bulk
(
_assets
,
'inherit_node'
,
node
.
id
)
set_or_append_attr_bulk
(
_assets
,
'permission'
,
getattr
(
node
,
'permission'
,
None
))
for
asset
in
_assets
:
assets
[
asset
]
.
update
(
set
(
_system_users
))
return
assets
@classmethod
def
get_user_assets_inherit_group
(
cls
,
user
):
assets
=
defaultdict
(
set
)
for
group
in
user
.
groups
.
all
():
_assets
=
cls
.
get_user_group_assets
(
group
)
set_or_append_attr_bulk
(
_assets
,
'inherit_group'
,
group
.
id
)
for
asset
,
_system_users
in
_assets
.
items
():
assets
[
asset
]
.
update
(
_system_users
)
return
assets
@classmethod
def
get_user_assets
(
cls
,
user
):
assets
=
defaultdict
(
set
)
_assets_direct
=
cls
.
get_user_assets_direct
(
user
)
_nodes_assets_direct
=
cls
.
get_user_nodes_assets_direct
(
user
)
_assets_inherit_group
=
cls
.
get_user_assets_inherit_group
(
user
)
for
asset
,
_system_users
in
_assets_direct
.
items
():
assets
[
asset
]
.
update
(
_system_users
)
for
asset
,
_system_users
in
_nodes_assets_direct
.
items
():
assets
[
asset
]
.
update
(
_system_users
)
for
asset
,
_system_users
in
_assets_inherit_group
.
items
():
assets
[
asset
]
.
update
(
_system_users
)
return
assets
@classmethod
def
get_user_nodes_with_assets
(
cls
,
user
):
"""
:param user:
:return: {node: {asset: set(su1, su2)}}
"""
nodes
=
defaultdict
(
dict
)
_assets
=
cls
.
get_user_assets
(
user
)
for
asset
,
_system_users
in
_assets
.
items
():
_nodes
=
asset
.
get_nodes
()
for
node
in
_nodes
:
if
asset
in
nodes
[
node
]:
nodes
[
node
][
asset
]
.
update
(
_system_users
)
else
:
nodes
[
node
][
asset
]
=
_system_users
return
nodes
@classmethod
def
get_system_user_assets
(
cls
,
system_user
):
assets
=
set
()
permissions
=
cls
.
get_system_user_permissions
(
system_user
)
for
perm
in
permissions
:
assets
.
update
(
set
(
perm
.
assets
.
all
()))
nodes
=
perm
.
nodes
.
all
()
for
node
in
nodes
:
assets
.
update
(
set
(
node
.
get_all_assets
()))
return
assets
@classmethod
def
get_node_system_users
(
cls
,
node
):
system_users
=
set
()
permissions
=
cls
.
get_node_permissions
(
node
)
for
perm
in
permissions
:
system_users
.
update
(
perm
.
system_users
.
all
())
return
system_users
# Abandon
class
NodePermissionUtil
:
"""
"""
@staticmethod
def
get_user_group_permissions
(
user_group
):
...
...
apps/perms/views.py
View file @
24bdaeca
...
...
@@ -3,20 +3,22 @@
from
__future__
import
unicode_literals
,
absolute_import
from
django.utils.translation
import
ugettext
as
_
from
django.views.generic
import
ListView
,
CreateView
,
UpdateView
from
django.views.generic.edit
import
DeleteView
from
django.views.generic
import
ListView
,
CreateView
,
UpdateView
,
DetailView
from
django.views.generic.edit
import
DeleteView
,
SingleObjectMixin
from
django.urls
import
reverse_lazy
from
django.conf
import
settings
from
common.
utils
import
get_object_or_none
from
.hands
import
AdminUserRequiredMixin
,
Node
from
.models
import
AssetPermission
,
NodePermission
from
common.
mixins
import
AdminUserRequiredMixin
from
.hands
import
Node
,
Asset
,
SystemUser
,
User
,
UserGroup
from
.models
import
AssetPermission
from
.forms
import
AssetPermissionForm
class
AssetPermissionListView
(
AdminUserRequiredMixin
,
ListView
):
model
=
NodePermission
context_object_name
=
'asset_permission_list'
model
=
AssetPermission
template_name
=
'perms/asset_permission_list.html'
paginate_by
=
settings
.
DISPLAY_PER_PAGE
user
=
user_group
=
asset
=
node
=
system_user
=
q
=
""
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
...
...
@@ -28,18 +30,24 @@ class AssetPermissionListView(AdminUserRequiredMixin, ListView):
class
AssetPermissionCreateView
(
AdminUserRequiredMixin
,
CreateView
):
model
=
Node
Permission
model
=
Asset
Permission
form_class
=
AssetPermissionForm
template_name
=
'perms/asset_permission_create_update.html'
success_url
=
reverse_lazy
(
'perms:asset-permission-list'
)
def
get_form
(
self
,
form_class
=
None
):
form
=
super
()
.
get_form
(
form_class
=
form_class
)
node_id
=
self
.
request
.
GET
.
get
(
"node_id"
)
node
=
get_object_or_none
(
Node
,
id
=
node_id
)
if
not
node
:
node
=
Node
.
root
()
form
[
'node'
]
.
initial
=
node
nodes_id
=
self
.
request
.
GET
.
get
(
"nodes"
)
assets_id
=
self
.
request
.
GET
.
get
(
"assets"
)
if
nodes_id
:
nodes_id
=
nodes_id
.
split
(
","
)
nodes
=
Node
.
objects
.
filter
(
id__in
=
nodes_id
)
form
[
'nodes'
]
.
initial
=
nodes
if
assets_id
:
assets_id
=
assets_id
.
split
(
","
)
assets
=
Asset
.
objects
.
filter
(
id__in
=
assets_id
)
form
[
'assets'
]
.
initial
=
assets
return
form
def
get_context_data
(
self
,
**
kwargs
):
...
...
@@ -52,16 +60,11 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, CreateView):
class
AssetPermissionUpdateView
(
AdminUserRequiredMixin
,
UpdateView
):
model
=
Node
Permission
model
=
Asset
Permission
form_class
=
AssetPermissionForm
template_name
=
'perms/asset_permission_create_update.html'
success_url
=
reverse_lazy
(
"perms:asset-permission-list"
)
def
get_form
(
self
,
form_class
=
None
):
form
=
super
()
.
get_form
(
form_class
=
form_class
)
form
[
'node'
]
.
initial
=
form
.
instance
.
node
return
form
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
_
(
'Perms'
),
...
...
@@ -71,9 +74,84 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
return
super
()
.
get_context_data
(
**
kwargs
)
class
AssetPermissionDetailView
(
AdminUserRequiredMixin
,
DetailView
):
model
=
AssetPermission
form_class
=
AssetPermissionForm
template_name
=
'perms/asset_permission_detail.html'
success_url
=
reverse_lazy
(
"perms:asset-permission-list"
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
_
(
'Perms'
),
'action'
:
_
(
'Update asset permission'
),
'system_users_remain'
:
SystemUser
.
objects
.
exclude
(
granted_by_permissions
=
self
.
object
),
}
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
class
AssetPermissionDeleteView
(
AdminUserRequiredMixin
,
DeleteView
):
model
=
AssetPermission
template_name
=
'delete_confirm.html'
success_url
=
reverse_lazy
(
'perms:asset-permission-list'
)
class
AssetPermissionUserView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
template_name
=
'perms/asset_permission_user.html'
context_object_name
=
'asset_permission'
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
object
=
None
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
AssetPermission
.
objects
.
all
())
return
super
()
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_queryset
(
self
):
queryset
=
self
.
object
.
get_all_users
()
return
queryset
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
_
(
'Perms'
),
'action'
:
_
(
'Asset permission user list'
),
'users_remain'
:
User
.
objects
.
exclude
(
asset_permissions
=
self
.
object
)
.
exclude
(
role
=
User
.
ROLE_APP
),
'user_groups_remain'
:
UserGroup
.
objects
.
exclude
(
asset_permissions
=
self
.
object
)
}
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
class
AssetPermissionAssetView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
template_name
=
'perms/asset_permission_asset.html'
context_object_name
=
'asset_permission'
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
object
=
None
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
AssetPermission
.
objects
.
all
())
return
super
()
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_queryset
(
self
):
queryset
=
self
.
object
.
get_all_assets
()
return
queryset
def
get_context_data
(
self
,
**
kwargs
):
assets_granted
=
self
.
get_queryset
()
context
=
{
'app'
:
_
(
'Perms'
),
'action'
:
_
(
'Asset permission asset list'
),
'assets_remain'
:
Asset
.
objects
.
exclude
(
id__in
=
[
a
.
id
for
a
in
assets_granted
]),
'nodes_remain'
:
Node
.
objects
.
exclude
(
granted_by_permissions
=
self
.
object
),
}
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
\ No newline at end of file
apps/static/css/plugins/ztree/awesomeStyle/awesome.css
View file @
24bdaeca
...
...
@@ -212,49 +212,49 @@ website: http://code.google.com/p/jquerytree/
height
:
20px
;
}
.ztree
li
span
.button.root_open
::before
{
content
:
"\f
078
"
;
content
:
"\f
107
"
;
padding-top
:
10px
;
padding-left
:
2px
;
display
:
inline-block
;
}
.ztree
li
span
.button.root_close
::before
{
content
:
"\f
054
"
;
content
:
"\f
105
"
;
padding-top
:
10px
;
padding-left
:
2px
;
display
:
inline-block
;
}
.ztree
li
span
.button.roots_open
::before
{
content
:
"\f
078
"
;
content
:
"\f
107
"
;
padding-top
:
10px
;
padding-left
:
2px
;
display
:
inline-block
;
}
.ztree
li
span
.button.roots_close
::before
{
content
:
"\f
054
"
;
content
:
"\f
105
"
;
padding-top
:
10px
;
padding-left
:
2px
;
display
:
inline-block
;
}
.ztree
li
span
.button.center_open
::before
{
content
:
"\f
078
"
;
content
:
"\f
107
"
;
padding-top
:
10px
;
padding-left
:
2px
;
display
:
inline-block
;
}
.ztree
li
span
.button.center_close
::before
{
content
:
"\f
054
"
;
content
:
"\f
105
"
;
padding-top
:
10px
;
padding-left
:
2px
;
display
:
inline-block
;
}
.ztree
li
span
.button.bottom_open
::before
{
content
:
"\f
078
"
;
content
:
"\f
107
"
;
padding-top
:
10px
;
padding-left
:
2px
;
display
:
inline-block
;
}
.ztree
li
span
.button.bottom_close
::before
{
content
:
"\f
054
"
;
content
:
"\f
105
"
;
padding-top
:
10px
;
padding-left
:
2px
;
display
:
inline-block
;
...
...
@@ -300,7 +300,31 @@ website: http://code.google.com/p/jquerytree/
color
:
#676a6c
;
}
.ztree
li
span
.button.ico_docu
::before
{
content
:
"\f114"
;
content
:
"\f07b"
;
font-family
:
FontAwesome
;
padding-top
:
10px
;
padding-left
:
2px
;
display
:
inline-block
;
color
:
#676a6c
;
}
.ztree
li
span
.button.file_ico_docu
::before
{
content
:
"\f022"
;
font-family
:
FontAwesome
;
padding-top
:
10px
;
padding-left
:
2px
;
display
:
inline-block
;
color
:
#676a6c
;
}
.ztree
li
span
.button.linux_ico_docu
::before
{
content
:
"\f17c"
;
font-family
:
FontAwesome
;
padding-top
:
10px
;
padding-left
:
2px
;
display
:
inline-block
;
color
:
#676a6c
;
}
.ztree
li
span
.button.windows_ico_docu
::before
{
content
:
"\f17a"
;
font-family
:
FontAwesome
;
padding-top
:
10px
;
padding-left
:
2px
;
...
...
apps/static/css/plugins/ztree/awesomeStyle/awesome.less
View file @
24bdaeca
...
...
@@ -39,11 +39,11 @@ website: http://code.google.com/p/jquerytree/
margin:0; padding:5px; color:@color-normal; background-color: @color-bg;
li {
padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0;
ul {
ul {
margin: 0px; padding:0 0 0 18px;
}
ul.line { }
a {padding-right:3px; margin:0; cursor:pointer; height:@h; color:@color-normal; background-color: transparent;
a {padding-right:3px; margin:0; cursor:pointer; height:@h; color:@color-normal; background-color: transparent;
text-decoration:none; vertical-align:top; display: inline-block;
input.rename {height:14px; width:80px; padding:0; margin:0;
color: @color-bg; background-color: @color-normal;
...
...
@@ -64,11 +64,11 @@ website: http://code.google.com/p/jquerytree/
span.button {line-height:0; margin:0; padding: 0; width:@w; height:@h; display: inline-block; vertical-align:top;
border:0px solid; cursor: pointer;outline:none;
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
&::before{color: @color-normal; font-family: FontAwesome; padding-top:@pad-top;}
&.chk { margin:0px; cursor: auto; width: 12px;
display: inline-block;padding-top:@pad-top;padding-left:@pad-left;
&.checkbox_false_full::before {content: @fa-square-o;}
&.checkbox_false_full_focus::before {content: @fa-square-o; color:@color-highlight;}
&.checkbox_false_part::before {content: @fa-square-o;color: @color-partial;}
...
...
@@ -82,7 +82,7 @@ website: http://code.google.com/p/jquerytree/
&.checkbox_true_part::before {content: @fa-check-square-o;color: @color-partial}
&.checkbox_true_part_focus::before {content: @fa-check-square-o;color: @color-partfocus;}
&.checkbox_true_disable::before {content: @fa-check-square-o;color: @color-disabled}
&.radio_false_full::before {content: @fa-circle-o;}
&.radio_false_full_focus::before {content: @fa-circle-o;color: @color-highlight}
&.radio_false_part::before {content: @fa-circle-o;color: @color-partial}
...
...
@@ -93,17 +93,17 @@ website: http://code.google.com/p/jquerytree/
&.radio_true_part::before {content: @fa-dot-circle-o;color: @color-partial}
&.radio_true_part_focus::before {content: @fa-dot-circle-o;color: @color-partial;}
&.radio_true_disable::before {content: @fa-circle-thin;color: @color-disabled}
}
&.switch {width:@w; height:@h}
&.root_open::before{content: @fa-
chevron
-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.root_close::before{content: @fa-
chevron
-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.roots_open::before{content: @fa-
chevron
-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.roots_close::before{content: @fa-
chevron
-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.center_open::before{content: @fa-
chevron
-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.center_close::before{content: @fa-
chevron
-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.bottom_open::before{content: @fa-
chevron
-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.bottom_close::before{content: @fa-
chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.root_open::before{content: @fa-
angle
-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.root_close::before{content: @fa-
angle
-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.roots_open::before{content: @fa-
angle
-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.roots_close::before{content: @fa-
angle
-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.center_open::before{content: @fa-
angle
-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.center_close::before{content: @fa-
angle
-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.bottom_open::before{content: @fa-
angle
-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.bottom_close::before{content: @fa-
angle-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.noline_open{}
&.noline_close{}
&.root_docu{ background:none;}
...
...
@@ -111,11 +111,15 @@ website: http://code.google.com/p/jquerytree/
&.center_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.bottom_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.noline_docu{ background:none;}
&.ico_open::before {content: @fa-folder-open;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.ico_close::before {content: @fa-folder;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.ico_docu::before{content: @fa-folder-o;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.ico_docu::before{content: @fa-folder;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.file_ico_docu::before{content: @fa-list-alt;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.linux_ico_docu::before{content: @fa-linux;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.windows_ico_docu::before{content: @fa-windows;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.edit {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;}
&.edit::before{content: @fa-pencil-square-o;font-family: FontAwesome;}
...
...
apps/static/js/jumpserver.js
View file @
24bdaeca
...
...
@@ -62,7 +62,6 @@ function GetTableDataBox() {
}
}
for
(
i
in
id_list
)
{
console
.
log
(
tabProduct
);
tableData
.
push
(
GetRowData
(
tabProduct
.
rows
[
id_list
[
i
]]));
}
...
...
@@ -240,6 +239,13 @@ $.fn.serializeObject = function()
});
return
o
;
};
function
makeLabel
(
data
)
{
return
"<label class='detail-key'><b>"
+
data
[
0
]
+
": </b></label>"
+
data
[
1
]
+
"</br>"
}
var
jumpserver
=
{};
jumpserver
.
checked
=
false
;
jumpserver
.
selected
=
{};
...
...
@@ -281,7 +287,7 @@ jumpserver.initDataTable = function (options) {
buttons
:
[],
columnDefs
:
columnDefs
,
ajax
:
{
url
:
options
.
ajax_url
,
url
:
options
.
ajax_url
,
dataSrc
:
""
},
columns
:
options
.
columns
||
[],
...
...
apps/terminal/templates/terminal/command_list.html
View file @
24bdaeca
...
...
@@ -18,7 +18,7 @@
{% endblock %}
{% block table_search %}
<form
id=
"search_form"
method=
"get"
action=
""
class=
"pull-right form-inline"
>
<form
id=
"search_form"
method=
"get"
action=
""
class=
"pull-right form-inline"
style=
"padding-bottom: 8px"
>
<div
class=
"form-group"
id=
"date"
>
<div
class=
"input-daterange input-group"
id=
"datepicker"
>
<span
class=
"input-group-addon"
><i
class=
"fa fa-calendar"
></i></span>
...
...
@@ -64,7 +64,7 @@
</form>
{% endblock %}
{% block table_container %}
<table
class=
"footable table table-stripped t
oggle-arrow-tiny"
data-page=
"false"
>
<table
class=
"footable table table-stripped t
able-bordered toggle-arrow-tiny"
data-page=
"false"
>
<thead>
<tr>
<th
data-toggle=
"true"
>
ID
</th>
...
...
apps/users/api.py
View file @
24bdaeca
...
...
@@ -26,11 +26,15 @@ logger = get_logger(__name__)
class
UserViewSet
(
IDInFilterMixin
,
BulkModelViewSet
):
queryset
=
User
.
objects
.
exclude
(
role
=
"App"
)
# queryset = User.objects.all().exclude(role="App").order_by("date_joined")
serializer_class
=
UserSerializer
permission_classes
=
(
IsSuperUser
OrAppUser
,
IsAuthenticated
)
permission_classes
=
(
IsSuperUser
,
)
filter_fields
=
(
'username'
,
'email'
,
'name'
,
'id'
)
def
get_permissions
(
self
):
if
self
.
action
==
"retrieve"
:
self
.
permission_classes
=
(
IsSuperUserOrAppUser
,)
return
super
()
.
get_permissions
()
class
ChangeUserPasswordApi
(
generics
.
RetrieveUpdateAPIView
):
permission_classes
=
(
IsSuperUser
,)
...
...
@@ -57,7 +61,6 @@ class UserResetPasswordApi(generics.UpdateAPIView):
def
perform_update
(
self
,
serializer
):
# Note: we are not updating the user object here.
# We just do the reset-password stuff.
import
uuid
from
.utils
import
send_reset_password_mail
user
=
self
.
get_object
()
user
.
password_raw
=
str
(
uuid
.
uuid4
())
...
...
@@ -68,6 +71,7 @@ class UserResetPasswordApi(generics.UpdateAPIView):
class
UserResetPKApi
(
generics
.
UpdateAPIView
):
queryset
=
User
.
objects
.
all
()
serializer_class
=
UserSerializer
permission_classes
=
(
IsAuthenticated
,)
def
perform_update
(
self
,
serializer
):
from
.utils
import
send_reset_ssh_key_mail
...
...
@@ -91,6 +95,7 @@ class UserUpdatePKApi(generics.UpdateAPIView):
class
UserGroupViewSet
(
IDInFilterMixin
,
BulkModelViewSet
):
queryset
=
UserGroup
.
objects
.
all
()
serializer_class
=
UserGroupSerializer
permission_classes
=
(
IsSuperUser
,)
class
UserGroupUpdateUserApi
(
generics
.
RetrieveUpdateAPIView
):
...
...
apps/users/forms.py
View file @
24bdaeca
...
...
@@ -6,7 +6,6 @@ from django.utils.translation import gettext_lazy as _
from
captcha.fields
import
CaptchaField
from
common.utils
import
validate_ssh_public_key
from
perms.models
import
AssetPermission
from
.models
import
User
,
UserGroup
...
...
@@ -253,30 +252,30 @@ class UserGroupForm(forms.ModelForm):
}
class
UserGroupPrivateAssetPermissionForm
(
forms
.
ModelForm
):
def
save
(
self
,
commit
=
True
):
self
.
instance
=
super
(
UserGroupPrivateAssetPermissionForm
,
self
)
\
.
save
(
commit
=
commit
)
self
.
instance
.
user_groups
=
[
self
.
user_group
]
self
.
instance
.
save
()
return
self
.
instance
class
Meta
:
model
=
AssetPermission
fields
=
[
'assets'
,
'asset_groups'
,
'system_users'
,
'name'
,
]
widgets
=
{
'assets'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select assets'
)}),
'asset_groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select asset groups'
)}),
'system_users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select system users'
)}),
}
#
class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
#
def save(self, commit=True):
#
self.instance = super(UserGroupPrivateAssetPermissionForm, self)\
#
.save(commit=commit)
#
self.instance.user_groups = [self.user_group]
#
self.instance.save()
#
return self.instance
#
#
class Meta:
#
model = AssetPermission
#
fields = [
#
'assets', 'asset_groups', 'system_users', 'name',
#
]
#
widgets = {
#
'assets': forms.SelectMultiple(
#
attrs={'class': 'select2',
#
'data-placeholder': _('Select assets')}),
#
'asset_groups': forms.SelectMultiple(
#
attrs={'class': 'select2',
#
'data-placeholder': _('Select asset groups')}),
#
'system_users': forms.SelectMultiple(
#
attrs={'class': 'select2',
#
'data-placeholder': _('Select system users')}),
#
}
class
FileForm
(
forms
.
Form
):
...
...
apps/users/models/user.py
View file @
24bdaeca
...
...
@@ -30,6 +30,11 @@ class User(AbstractUser):
(
ROLE_USER
,
_
(
'User'
)),
(
ROLE_APP
,
_
(
'Application'
))
)
OTP_LEVEL_CHOICES
=
(
(
0
,
_
(
'Disable'
)),
(
1
,
_
(
'Enable'
)),
(
2
,
_
(
"Force enable"
)),
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
username
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Username'
))
name
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
'Name'
))
...
...
@@ -39,8 +44,8 @@ class User(AbstractUser):
avatar
=
models
.
ImageField
(
upload_to
=
"avatar"
,
null
=
True
,
verbose_name
=
_
(
'Avatar'
))
wechat
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
verbose_name
=
_
(
'Wechat'
))
phone
=
models
.
CharField
(
max_length
=
20
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Phone'
))
enable_otp
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
'Enable OTP'
))
secret_key_otp
=
models
.
CharField
(
max_length
=
16
,
blank
=
True
)
otp_level
=
models
.
SmallIntegerField
(
default
=
0
,
choices
=
OTP_LEVEL_CHOICES
,
verbose_name
=
_
(
'Enable OTP'
))
otp_secret_key
=
models
.
CharField
(
max_length
=
16
,
blank
=
True
)
# Todo: Auto generate key, let user download
_private_key
=
models
.
CharField
(
max_length
=
5000
,
blank
=
True
,
verbose_name
=
_
(
'Private key'
))
_public_key
=
models
.
CharField
(
max_length
=
5000
,
blank
=
True
,
verbose_name
=
_
(
'Public key'
))
...
...
@@ -50,7 +55,7 @@ class User(AbstractUser):
created_by
=
models
.
CharField
(
max_length
=
30
,
default
=
''
,
verbose_name
=
_
(
'Created by'
))
def
__str__
(
self
):
return
self
.
username
return
'{0.name}({0.username})'
.
format
(
self
)
@property
def
password_raw
(
self
):
...
...
@@ -202,6 +207,20 @@ class User(AbstractUser):
def
generate_reset_token
(
self
):
return
signer
.
sign_t
({
'reset'
:
str
(
self
.
id
),
'email'
:
self
.
email
},
expires_in
=
3600
)
@property
def
otp_enabled
(
self
):
return
self
.
otp_level
>
0
def
enabled_otp
(
self
):
self
.
otp_level
=
1
def
force_enable_otp
(
self
):
self
.
otp_level
=
2
@property
def
otp_force_enabled
(
self
):
return
self
.
otp_level
==
2
def
to_json
(
self
):
return
OrderedDict
({
'id'
:
self
.
id
,
...
...
@@ -222,7 +241,7 @@ class User(AbstractUser):
def
create_app_user
(
cls
,
name
,
comment
):
app
=
cls
.
objects
.
create
(
username
=
name
,
name
=
name
,
email
=
'{}@local.domain'
.
format
(
name
),
is_active
=
False
,
role
=
'App'
,
enable_otp
=
False
,
comment
=
comment
,
is_active
=
False
,
role
=
'App'
,
comment
=
comment
,
is_first_login
=
False
,
created_by
=
'System'
)
access_key
=
app
.
create_access_key
()
...
...
apps/users/signals_handler.py
View file @
24bdaeca
...
...
@@ -2,19 +2,29 @@
#
from
django.dispatch
import
receiver
from
django.db.models.signals
import
post_save
#
from django.db.models.signals import post_save
from
common.utils
import
get_logger
from
.models
import
User
from
.signals
import
post_user_create
# from .models import User
logger
=
get_logger
(
__file__
)
@receiver
(
post_save
,
sender
=
User
)
def
on_user_created
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
created
:
logger
.
debug
(
"Receive user `{}` create signal"
.
format
(
instance
.
name
))
from
.utils
import
send_user_created_mail
logger
.
info
(
" - Sending welcome mail ..."
.
format
(
instance
.
name
))
if
instance
.
email
:
send_user_created_mail
(
instance
)
\ No newline at end of file
# @receiver(post_save, sender=User)
# def on_user_created(sender, instance=None, created=False, **kwargs):
# if created:
# logger.debug("Receive user `{}` create signal".format(instance.name))
# from .utils import send_user_created_mail
# logger.info(" - Sending welcome mail ...".format(instance.name))
# if instance.email:
# send_user_created_mail(instance)
@receiver
(
post_user_create
)
def
on_user_create
(
sender
,
user
=
None
,
**
kwargs
):
logger
.
debug
(
"Receive user `{}` create signal"
.
format
(
user
.
name
))
from
.utils
import
send_user_created_mail
logger
.
info
(
" - Sending welcome mail ..."
.
format
(
user
.
name
))
if
user
.
email
:
send_user_created_mail
(
user
)
apps/users/templates/users/user_granted_asset.html
View file @
24bdaeca
...
...
@@ -44,7 +44,7 @@
<th
class=
"text-center"
>
{% trans 'Hostname' %}
</th>
<th
class=
"text-center"
>
{% trans 'IP' %}
</th>
<th
class=
"text-center"
>
{% trans 'Active' %}
</th>
<th
class=
"text-center"
>
{% trans '
Reachable
' %}
</th>
<th
class=
"text-center"
>
{% trans '
System users
' %}
</th>
</tr>
</thead>
<tbody>
...
...
@@ -63,6 +63,8 @@
<script>
var
zTree
;
var
inited
=
false
;
var
url
;
var
asset_table
;
function
initTable
()
{
if
(
inited
){
...
...
@@ -86,31 +88,28 @@ function initTable() {
}
}},
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
cellData
===
'Unknown'
){
$
(
td
).
html
(
'<i class="fa fa-circle text-warning"></i>'
)
}
else
if
(
!
cellData
)
{
$
(
td
).
html
(
'<i class="fa fa-circle text-danger"></i>'
)
}
else
{
$
(
td
).
html
(
'<i class="fa fa-circle text-navy"></i>'
)
}
var
users
=
[];
$
.
each
(
cellData
,
function
(
id
,
data
)
{
users
.
push
(
data
.
name
);
});
$
(
td
).
html
(
users
.
join
(
', '
))
}}
],
ajax_url
:
'{% url "api-assets:asset-list" %}'
,
ajax_url
:
url
,
columns
:
[
{
data
:
"id"
},
{
data
:
"hostname"
},
{
data
:
"ip"
},
{
data
:
"is_active"
,
orderable
:
false
},
{
data
:
"
is_connective
"
,
orderable
:
false
}
{
data
:
"
system_users_granted
"
,
orderable
:
false
}
]
};
asset_table
=
jumpserver
.
initServerSideDataTable
(
options
);
return
asset_table
return
jumpserver
.
initDataTable
(
options
);
}
function
onSelected
(
event
,
treeNode
)
{
initTable
();
var
url
=
asset_table
.
ajax
.
url
();
url
=
setUrlParam
(
url
,
"node_id"
,
treeNode
.
id
);
url
=
'{% url "api-perms:user-node-assets" pk=object.id node_id=DEFAULT_PK %}'
;
url
=
url
.
replace
(
"{{ DEFAULT_PK }}"
,
treeNode
.
id
);
setCookie
(
'node_selected'
,
treeNode
.
id
);
asset_table
=
initTable
();
asset_table
.
ajax
.
url
(
url
);
asset_table
.
ajax
.
reload
();
}
...
...
apps/users/templates/users/user_group_granted_asset.html
View file @
24bdaeca
...
...
@@ -63,6 +63,7 @@
<script>
var
zTree
;
var
inited
=
false
;
var
url
;
function
initTable
()
{
if
(
inited
){
...
...
@@ -86,31 +87,29 @@ function initTable() {
}
}},
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
cellData
===
'Unknown'
){
$
(
td
).
html
(
'<i class="fa fa-circle text-warning"></i>'
)
}
else
if
(
!
cellData
)
{
$
(
td
).
html
(
'<i class="fa fa-circle text-danger"></i>'
)
}
else
{
$
(
td
).
html
(
'<i class="fa fa-circle text-navy"></i>'
)
}
var
users
=
[];
$
.
each
(
cellData
,
function
(
id
,
data
)
{
users
.
push
(
data
.
name
);
});
$
(
td
).
html
(
users
.
join
(
', '
))
}}
],
ajax_url
:
'{% url "api-assets:asset-list" %}'
,
ajax_url
:
url
,
columns
:
[
{
data
:
"id"
},
{
data
:
"hostname"
},
{
data
:
"ip"
},
{
data
:
"is_active"
,
orderable
:
false
},
{
data
:
"
is_connective
"
,
orderable
:
false
}
{
data
:
"
system_users_granted
"
,
orderable
:
false
}
]
};
asset_table
=
jumpserver
.
init
ServerSide
DataTable
(
options
);
asset_table
=
jumpserver
.
initDataTable
(
options
);
return
asset_table
}
function
onSelected
(
event
,
treeNode
)
{
initTable
();
var
url
=
asset_table
.
ajax
.
url
();
url
=
setUrlParam
(
url
,
"node_id"
,
treeNode
.
id
);
url
=
'{% url "api-perms:user-group-node-assets" pk=object.id node_id=DEFAULT_PK %}'
;
url
=
url
.
replace
(
"{{ DEFAULT_PK }}"
,
treeNode
.
id
);
setCookie
(
'node_selected'
,
treeNode
.
id
);
asset_table
=
initTable
();
asset_table
.
ajax
.
url
(
url
);
asset_table
.
ajax
.
reload
();
}
...
...
apps/users/templates/users/user_profile.html
View file @
24bdaeca
...
...
@@ -65,7 +65,7 @@
</tr>
<tr>
<td
class=
"text-navy"
>
{% trans 'OTP' %}
</td>
<td>
{{ user.
enable_otp
|yesno:"Yes,No,Unkown" }}
</td>
<td>
{{ user.
otp_enabled
|yesno:"Yes,No,Unkown" }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
{% trans 'Public key' %}
</td>
...
...
apps/users/views/login.py
View file @
24bdaeca
...
...
@@ -2,7 +2,6 @@
from
__future__
import
unicode_literals
import
os
from
django
import
forms
from
django.shortcuts
import
render
from
django.contrib.auth
import
login
as
auth_login
,
logout
as
auth_logout
from
django.contrib.auth.mixins
import
LoginRequiredMixin
...
...
@@ -20,10 +19,9 @@ from django.views.generic.base import TemplateView
from
django.views.generic.edit
import
FormView
from
formtools.wizard.views
import
SessionWizardView
from
django.conf
import
settings
from
django.utils
import
timezone
from
common.utils
import
get_object_or_none
from
common.mixins
import
DatetimeSearchMixin
from
common.mixins
import
DatetimeSearchMixin
,
AdminUserRequiredMixin
from
..models
import
User
,
LoginLog
from
..utils
import
send_reset_password_mail
from
..tasks
import
write_login_log_async
...
...
@@ -194,8 +192,6 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
for
field
in
form
:
if
field
.
value
():
setattr
(
user
,
field
.
name
,
field
.
value
())
if
field
.
name
==
'enable_otp'
:
user
.
enable_otp
=
field
.
value
()
user
.
is_first_login
=
False
user
.
is_public_key_valid
=
True
user
.
save
()
...
...
@@ -228,7 +224,7 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
return
form
class
LoginLogListView
(
DatetimeSearchMixin
,
ListView
):
class
LoginLogListView
(
AdminUserRequiredMixin
,
DatetimeSearchMixin
,
ListView
):
template_name
=
'users/login_log_list.html'
model
=
LoginLog
paginate_by
=
settings
.
DISPLAY_PER_PAGE
...
...
apps/users/views/user.py
View file @
24bdaeca
...
...
@@ -79,6 +79,7 @@ class UserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
user
=
form
.
save
(
commit
=
False
)
user
.
created_by
=
self
.
request
.
user
.
username
or
'System'
user
.
save
()
post_user_create
.
send
(
self
.
__class__
,
user
=
user
)
return
super
()
.
form_valid
(
form
)
...
...
utils/2018_04_11_migrate_permissions.sh
0 → 100644
View file @
24bdaeca
#!/bin/bash
#
python ../apps/manage.py shell
<<
EOF
from perms.models import *
for old in NodePermission.objects.all():
perm = asset_perm_model.objects.using(db_alias).create(
name="{}-{}-{}".format(
old.node.value,
old.user_group.name,
old.system_user.name
),
is_active=old.is_active,
date_expired=old.date_expired,
created_by=old.date_expired,
date_created=old.date_created,
comment=old.comment,
)
perm.user_groups.add(old.user_group)
perm.nodes.add(old.node)
perm.system_users.add(old.system_user)
EOF
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