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
f450accb
Commit
f450accb
authored
Apr 18, 2018
by
BaiJiangjie
Browse files
Options
Browse Files
Download
Plain Diff
[Merge] with dev
parents
0bbfc743
48e87857
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
38 changed files
with
586 additions
and
259 deletions
+586
-259
__init__.py
apps/__init__.py
+1
-1
node.py
apps/assets/api/node.py
+14
-0
asset.py
apps/assets/models/asset.py
+2
-2
node.py
apps/assets/models/node.py
+3
-3
user.py
apps/assets/models/user.py
+1
-1
tasks.py
apps/assets/tasks.py
+3
-0
_asset_list_modal.html
apps/assets/templates/assets/_asset_list_modal.html
+98
-105
asset_detail.html
apps/assets/templates/assets/asset_detail.html
+2
-2
asset_list.html
apps/assets/templates/assets/asset_list.html
+0
-0
domain_create_update.html
apps/assets/templates/assets/domain_create_update.html
+16
-4
domain_gateway_list.html
apps/assets/templates/assets/domain_gateway_list.html
+0
-5
label_create_update.html
apps/assets/templates/assets/label_create_update.html
+21
-4
system_user_detail.html
apps/assets/templates/assets/system_user_detail.html
+2
-2
api_urls.py
apps/assets/urls/api_urls.py
+1
-0
asset.py
apps/assets/views/asset.py
+11
-8
fields.py
apps/common/fields.py
+28
-2
django.mo
apps/i18n/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/i18n/zh/LC_MESSAGES/django.po
+0
-0
urls.py
apps/jumpserver/urls.py
+4
-3
api.py
apps/perms/api.py
+80
-1
forms.py
apps/perms/forms.py
+13
-0
models.py
apps/perms/models.py
+17
-1
asset_permission_asset.html
apps/perms/templates/perms/asset_permission_asset.html
+48
-61
asset_permission_create_update.html
...perms/templates/perms/asset_permission_create_update.html
+32
-14
asset_permission_detail.html
apps/perms/templates/perms/asset_permission_detail.html
+0
-0
asset_permission_user.html
apps/perms/templates/perms/asset_permission_user.html
+6
-6
api_urls.py
apps/perms/urls/api_urls.py
+42
-12
views_urls.py
apps/perms/urls/views_urls.py
+2
-2
views.py
apps/perms/views.py
+65
-4
jumpserver.js
apps/static/js/jumpserver.js
+39
-5
_footer.html
apps/templates/_footer.html
+1
-1
_modal.html
apps/templates/_modal.html
+7
-0
_nav.html
apps/templates/_nav.html
+1
-1
api.py
apps/terminal/api.py
+1
-1
user.py
apps/users/models/user.py
+10
-2
quickstart.rst
docs/quickstart.rst
+5
-2
step_by_step.rst
docs/step_by_step.rst
+3
-3
2018_04_11_migrate_permissions.sh
utils/2018_04_11_migrate_permissions.sh
+7
-1
No files found.
apps/__init__.py
View file @
f450accb
...
@@ -2,4 +2,4 @@
...
@@ -2,4 +2,4 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
__version__
=
"1.
0
.0"
__version__
=
"1.
2
.0"
apps/assets/api/node.py
View file @
f450accb
...
@@ -32,6 +32,7 @@ __all__ = [
...
@@ -32,6 +32,7 @@ __all__ = [
'NodeViewSet'
,
'NodeChildrenApi'
,
'NodeViewSet'
,
'NodeChildrenApi'
,
'NodeAssetsApi'
,
'NodeWithAssetsApi'
,
'NodeAssetsApi'
,
'NodeWithAssetsApi'
,
'NodeAddAssetsApi'
,
'NodeRemoveAssetsApi'
,
'NodeAddAssetsApi'
,
'NodeRemoveAssetsApi'
,
'NodeReplaceAssetsApi'
,
'NodeAddChildrenApi'
,
'RefreshNodeHardwareInfoApi'
,
'NodeAddChildrenApi'
,
'RefreshNodeHardwareInfoApi'
,
'TestNodeConnectiveApi'
'TestNodeConnectiveApi'
]
]
...
@@ -191,6 +192,19 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView):
...
@@ -191,6 +192,19 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView):
instance
.
assets
.
remove
(
*
tuple
(
assets
))
instance
.
assets
.
remove
(
*
tuple
(
assets
))
class
NodeReplaceAssetsApi
(
generics
.
UpdateAPIView
):
serializer_class
=
serializers
.
NodeAssetsSerializer
queryset
=
Node
.
objects
.
all
()
permission_classes
=
(
IsSuperUser
,)
instance
=
None
def
perform_update
(
self
,
serializer
):
assets
=
serializer
.
validated_data
.
get
(
'assets'
)
instance
=
self
.
get_object
()
for
asset
in
assets
:
asset
.
nodes
.
set
([
instance
])
class
RefreshNodeHardwareInfoApi
(
APIView
):
class
RefreshNodeHardwareInfoApi
(
APIView
):
permission_classes
=
(
IsSuperUser
,)
permission_classes
=
(
IsSuperUser
,)
model
=
Node
model
=
Node
...
...
apps/assets/models/asset.py
View file @
f450accb
...
@@ -49,6 +49,7 @@ class Asset(models.Model):
...
@@ -49,6 +49,7 @@ class Asset(models.Model):
ip
=
models
.
GenericIPAddressField
(
max_length
=
32
,
verbose_name
=
_
(
'IP'
),
db_index
=
True
)
ip
=
models
.
GenericIPAddressField
(
max_length
=
32
,
verbose_name
=
_
(
'IP'
),
db_index
=
True
)
hostname
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Hostname'
))
hostname
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Hostname'
))
port
=
models
.
IntegerField
(
default
=
22
,
verbose_name
=
_
(
'Port'
))
port
=
models
.
IntegerField
(
default
=
22
,
verbose_name
=
_
(
'Port'
))
platform
=
models
.
CharField
(
max_length
=
128
,
choices
=
PLATFORM_CHOICES
,
default
=
'Linux'
,
verbose_name
=
_
(
'Platform'
))
domain
=
models
.
ForeignKey
(
"assets.Domain"
,
null
=
True
,
blank
=
True
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Domain"
),
on_delete
=
models
.
SET_NULL
)
domain
=
models
.
ForeignKey
(
"assets.Domain"
,
null
=
True
,
blank
=
True
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Domain"
),
on_delete
=
models
.
SET_NULL
)
nodes
=
models
.
ManyToManyField
(
'assets.Node'
,
default
=
default_node
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Nodes"
))
nodes
=
models
.
ManyToManyField
(
'assets.Node'
,
default
=
default_node
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Nodes"
))
is_active
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
'Is active'
))
is_active
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
'Is active'
))
...
@@ -72,7 +73,6 @@ class Asset(models.Model):
...
@@ -72,7 +73,6 @@ class Asset(models.Model):
disk_total
=
models
.
CharField
(
max_length
=
1024
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Disk total'
))
disk_total
=
models
.
CharField
(
max_length
=
1024
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Disk total'
))
disk_info
=
models
.
CharField
(
max_length
=
1024
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Disk info'
))
disk_info
=
models
.
CharField
(
max_length
=
1024
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Disk info'
))
platform
=
models
.
CharField
(
max_length
=
128
,
choices
=
PLATFORM_CHOICES
,
default
=
'Linux'
,
verbose_name
=
_
(
'Platform'
))
os
=
models
.
CharField
(
max_length
=
128
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'OS'
))
os
=
models
.
CharField
(
max_length
=
128
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'OS'
))
os_version
=
models
.
CharField
(
max_length
=
16
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'OS version'
))
os_version
=
models
.
CharField
(
max_length
=
16
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'OS version'
))
os_arch
=
models
.
CharField
(
max_length
=
16
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'OS arch'
))
os_arch
=
models
.
CharField
(
max_length
=
16
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'OS arch'
))
...
@@ -84,7 +84,7 @@ class Asset(models.Model):
...
@@ -84,7 +84,7 @@ class Asset(models.Model):
comment
=
models
.
TextField
(
max_length
=
128
,
default
=
''
,
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
comment
=
models
.
TextField
(
max_length
=
128
,
default
=
''
,
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
def
__str__
(
self
):
def
__str__
(
self
):
return
self
.
hostname
return
'{0.hostname}({0.ip})'
.
format
(
self
)
@property
@property
def
is_valid
(
self
):
def
is_valid
(
self
):
...
...
apps/assets/models/node.py
View file @
f450accb
...
@@ -19,7 +19,7 @@ class Node(models.Model):
...
@@ -19,7 +19,7 @@ class Node(models.Model):
is_asset
=
False
is_asset
=
False
def
__str__
(
self
):
def
__str__
(
self
):
return
self
.
value
return
self
.
full_
value
@property
@property
def
name
(
self
):
def
name
(
self
):
...
@@ -30,7 +30,7 @@ class Node(models.Model):
...
@@ -30,7 +30,7 @@ class Node(models.Model):
if
self
==
self
.
__class__
.
root
():
if
self
==
self
.
__class__
.
root
():
return
self
.
value
return
self
.
value
else
:
else
:
return
'{}
/{}'
.
format
(
self
.
value
,
self
.
parent
.
full_
value
)
return
'{}
/ {}'
.
format
(
self
.
parent
.
full_value
,
self
.
value
)
@property
@property
def
level
(
self
):
def
level
(
self
):
...
@@ -72,7 +72,7 @@ class Node(models.Model):
...
@@ -72,7 +72,7 @@ class Node(models.Model):
assets
=
Asset
.
objects
.
all
()
assets
=
Asset
.
objects
.
all
()
else
:
else
:
nodes
=
self
.
get_family
()
nodes
=
self
.
get_family
()
assets
=
Asset
.
objects
.
filter
(
nodes__in
=
nodes
)
assets
=
Asset
.
objects
.
filter
(
nodes__in
=
nodes
)
.
distinct
()
return
assets
return
assets
def
has_assets
(
self
):
def
has_assets
(
self
):
...
...
apps/assets/models/user.py
View file @
f450accb
...
@@ -109,7 +109,7 @@ class SystemUser(AssetUser):
...
@@ -109,7 +109,7 @@ class SystemUser(AssetUser):
shell
=
models
.
CharField
(
max_length
=
64
,
default
=
'/bin/bash'
,
verbose_name
=
_
(
'Shell'
))
shell
=
models
.
CharField
(
max_length
=
64
,
default
=
'/bin/bash'
,
verbose_name
=
_
(
'Shell'
))
def
__str__
(
self
):
def
__str__
(
self
):
return
self
.
name
return
'{0.name}({0.username})'
.
format
(
self
)
def
to_json
(
self
):
def
to_json
(
self
):
return
{
return
{
...
...
apps/assets/tasks.py
View file @
f450accb
...
@@ -96,6 +96,9 @@ def update_assets_hardware_info_util(assets, task_name=None):
...
@@ -96,6 +96,9 @@ def update_assets_hardware_info_util(assets, task_name=None):
task_name
=
_
(
"更新资产硬件信息"
)
task_name
=
_
(
"更新资产硬件信息"
)
tasks
=
const
.
UPDATE_ASSETS_HARDWARE_TASKS
tasks
=
const
.
UPDATE_ASSETS_HARDWARE_TASKS
hostname_list
=
[
asset
.
hostname
for
asset
in
assets
if
asset
.
is_active
and
asset
.
is_unixlike
()]
hostname_list
=
[
asset
.
hostname
for
asset
in
assets
if
asset
.
is_active
and
asset
.
is_unixlike
()]
if
not
hostname_list
:
logger
.
info
(
"Not hosts get, may be asset is not active or not unixlike platform"
)
return
{}
task
,
created
=
update_or_create_ansible_task
(
task
,
created
=
update_or_create_ansible_task
(
task_name
,
hosts
=
hostname_list
,
tasks
=
tasks
,
pattern
=
'all'
,
task_name
,
hosts
=
hostname_list
,
tasks
=
tasks
,
pattern
=
'all'
,
options
=
const
.
TASK_OPTIONS
,
run_as_admin
=
True
,
created_by
=
'System'
,
options
=
const
.
TASK_OPTIONS
,
run_as_admin
=
True
,
created_by
=
'System'
,
...
...
apps/assets/templates/assets/_asset_list_modal.html
View file @
f450accb
{% extends '_modal.html' %}
{% extends '_modal.html' %}
{% load i18n %}
{% load i18n %}
{% load static %}
{% block modal_class %}modal-lg{% endblock %}
{% block modal_class %}modal-lg{% endblock %}
{% block modal_id %}asset_list_modal{% endblock %}
{% block modal_id %}asset_list_modal{% endblock %}
{
#{% block modal_title%}{% trans "Please select assets" %}{% endblock %}#
}
{
% block modal_title%}{% trans "Asset list" %}{% endblock %
}
{% block modal_body %}
{% block modal_body %}
{#
<div
class=
"btn-group"
style=
"float: right"
>
#}
<link
href=
"{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}"
rel=
"stylesheet"
>
{#
<button
data-toggle=
"dropdown"
class=
"btn btn-default btn-sm dropdown-toggle"
>
{% trans 'Label' %}
<span
class=
"caret"
></span></button>
#}
<script
type=
"text/javascript"
src=
"{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"
></script>
{#
<ul
class=
"dropdown-menu labels"
>
#}
<script
src=
"{% static 'js/jquery.form.min.js' %}"
></script>
{# {% for label in labels %}#}
<style>
{#
<li><a
style=
"font-weight: bolder"
>
{{ label.name }}:{{ label.value }}
</a></li>
#}
.inmodal
.modal-header
{
{# {% endfor %}#}
padding
:
10px
10px
;
{#
</ul>
#}
text-align
:
center
;
{#
</div>
#}
}
<table
class=
"table table-striped table-bordered table-hover "
id=
"asset_modal_table"
width=
"100%"
>
<thead>
#assetTree2
.ztree
*
{
<tr>
background-color
:
#f8fafb
;
<th
class=
"text-center"
><input
type=
"checkbox"
class=
"ipt_check_all"
></th>
}
<th
class=
"text-center"
>
{% trans 'Hostname' %}
</th>
#assetTree2
.ztree
{
<th
class=
"text-center"
>
{% trans 'IP' %}
</th>
background-color
:
#f8fafb
;
<th
class=
"text-center"
>
{% trans 'Hardware' %}
</th>
}
<th
class=
"text-center"
>
{% trans 'Active' %}
</th>
</style>
<th
class=
"text-center"
>
{% trans 'Reachable' %}
</th>
<th
class=
"text-center"
>
{% trans 'Action' %}
</th>
<div
class=
"wrapper wrapper-content"
>
</tr>
<div
class=
"row"
>
</thead>
<div
class=
"col-lg-3"
id=
"split-left"
style=
"padding-left: 3px"
>
<tbody>
<div
class=
"ibox float-e-margins"
>
</tbody>
<div
class=
"ibox-content mailbox-content"
style=
"padding-top: 0;padding-left: 1px"
>
</table>
<div
class=
"file-manager "
>
<div
id=
"actions"
class=
"hide"
>
<div
id=
"assetTree2"
class=
"ztree"
>
<div
class=
"input-group"
>
</div>
<select
class=
"form-control m-b"
style=
"width: auto"
id=
"slct_bulk_update"
>
<div
class=
"clearfix"
></div>
<option
value=
"delete"
>
{% trans 'Delete selected' %}
</option>
</div>
<option
value=
"update"
>
{% trans 'Update selected' %}
</option>
</div>
<option
value=
"deactive"
>
{% trans 'Deactive selected' %}
</option>
</div>
<option
value=
"active"
>
{% trans 'Active selected' %}
</option>
</div>
</select>
<div
class=
"col-lg-9 animated fadeInRight"
id=
"split-right"
>
<div
class=
"input-group-btn pull-left"
style=
"padding-left: 5px;"
>
<div
class=
"mail-box-header"
>
<button
id=
'btn_bulk_update'
style=
"height: 32px;"
class=
"btn btn-sm btn-primary"
>
<table
class=
"table table-striped table-bordered table-hover "
id=
"asset_list_modal_table"
style=
"width: 100%"
>
{% trans 'Submit' %}
<thead>
</button>
<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>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var
modal_table
;
function
initModalTable
()
{
<script>
var
zTree2
,
asset_table2
=
0
;
function
initTable2
()
{
var
options
=
{
var
options
=
{
ele
:
$
(
'#asset_modal_table'
),
ele
:
$
(
'#asset_list_modal_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
:
3
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
$
(
td
).
html
(
rowData
.
hardware_info
)
}},
{
targets
:
4
,
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
)
{
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
:
6
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
update_btn
=
'<a href="{% url "assets:asset-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
"{{ DEFAULT_PK }}"
,
cellData
);
var
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs btn_asset_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
$
(
td
).
html
(
update_btn
+
del_btn
)
}}
],
ajax_url
:
'{% url "api-assets:asset-list" %}'
,
ajax_url
:
'{% url "api-assets:asset-list" %}'
,
columns
:
[
columns
:
[
{
data
:
"id"
},
{
data
:
"hostname"
},
{
data
:
"ip"
},
{
data
:
"id"
},
{
data
:
"hostname"
},
{
data
:
"ip"
}
{
data
:
"cpu_cores"
},
{
data
:
"is_active"
,
orderable
:
false
},
{
data
:
"is_connective"
,
orderable
:
false
},
{
data
:
"id"
,
orderable
:
false
}
],
],
op_html
:
$
(
'#actions'
).
html
()
pageLength
:
10
};
};
modal_table
=
jumpserver
.
initServerSideDataTable
(
options
);
asset_table2
=
jumpserver
.
initServerSideDataTable
(
options
);
return
modal_table
;
return
asset_table2
}
}
$
(
document
).
ready
(
function
(){
function
onSelected2
(
event
,
treeNode
)
{
initModalTable
();
var
url
=
asset_table2
.
ajax
.
url
();
}).
on
(
'click'
,
'#btn_select_assets'
,
function
()
{
url
=
setUrlParam
(
url
,
"node_id"
,
treeNode
.
id
);
var
data_table
=
$
(
'#asset_modal_table'
).
DataTable
();
setCookie
(
'node_selected'
,
treeNode
.
id
);
var
id_list
=
[];
asset_table2
.
ajax
.
url
(
url
);
data_table
.
rows
({
selected
:
true
}).
every
(
function
(){
asset_table2
.
ajax
.
reload
();
id_list
.
push
(
this
.
data
().
id
);
}
});
var
current_node
;
var
nodes
=
zTree
.
getSelectedNodes
();
if
(
nodes
&&
nodes
.
length
===
1
)
{
current_node
=
nodes
[
0
]
}
else
{
return
}
var
data
=
{
'assets'
:
id_list
};
var
success
=
function
()
{
function
initTree2
()
{
modal_table
.
ajax
.
reload
()
var
setting
=
{
view
:
{
dblClickExpand
:
false
,
showLine
:
true
},
data
:
{
simpleData
:
{
enable
:
true
}
},
callback
:
{
onSelected
:
onSelected2
}
};
};
APIUpdateAttr
({
var
zNodes
=
[];
'url'
:
'/api/assets/v1/nodes/'
+
current_node
.
id
+
'/assets/add/'
,
$
.
get
(
"{% url 'api-assets:node-list' %}"
,
function
(
data
,
status
){
'method'
:
'PUT'
,
$
.
each
(
data
,
function
(
index
,
value
)
{
'body'
:
JSON
.
stringify
(
data
),
value
[
"pId"
]
=
value
[
"parent"
];
'success'
:
success
value
[
"open"
]
=
true
;
})
value
[
"name"
]
=
value
[
"value"
]
+
' ('
+
value
[
'assets_amount'
]
+
')'
;
value
[
'value'
]
=
value
[
'value'
];
});
zNodes
=
data
;
$
.
fn
.
zTree
.
init
(
$
(
"#assetTree2"
),
setting
,
zNodes
);
zTree2
=
$
.
fn
.
zTree
.
getZTreeObj
(
"assetTree2"
);
});
}
$
(
document
).
ready
(
function
(){
initTable2
();
initTree2
();
})
})
</script>
</script>
{% endblock %}
{% block modal_button %}
{{ block.super }}
{% endblock %}
{% endblock %}
{% block modal_confirm_id %}btn_select_assets{% endblock %}
{% block modal_confirm_id %}btn_asset_modal_confirm{% endblock %}
apps/assets/templates/assets/asset_detail.html
View file @
f450accb
...
@@ -305,9 +305,9 @@ $(document).ready(function () {
...
@@ -305,9 +305,9 @@ $(document).ready(function () {
success_message
:
success
success_message
:
success
});
});
if
(
status
===
"False"
)
{
if
(
status
===
"False"
)
{
$
(
".ibox-content > table > tbody > tr:nth-child(13) > td:last >b"
).
html
(
'True'
);
$
(
".ibox-content > table > tbody > tr:nth-child(13) > td:last >b"
).
html
(
'True'
);
}
else
{
}
else
{
$
(
".ibox-content > table > tbody > tr:nth-child(13) > td:last >b"
).
html
(
'False'
);
$
(
".ibox-content > table > tbody > tr:nth-child(13) > td:last >b"
).
html
(
'False'
);
}
}
}).
on
(
'click'
,
'#btn-update-nodes'
,
function
()
{
}).
on
(
'click'
,
'#btn-update-nodes'
,
function
()
{
if
(
Object
.
keys
(
jumpserver
.
nodes_selected
).
length
===
0
)
{
if
(
Object
.
keys
(
jumpserver
.
nodes_selected
).
length
===
0
)
{
...
...
apps/assets/templates/assets/asset_list.html
View file @
f450accb
This diff is collapsed.
Click to expand it.
apps/assets/templates/assets/domain_create_update.html
View file @
f450accb
...
@@ -18,14 +18,25 @@
...
@@ -18,14 +18,25 @@
</div>
</div>
</div>
</div>
</form>
</form>
{% include 'assets/_asset_list_modal.html' %}
{% endblock %}
{% endblock %}
{% block custom_foot_js %}
{% block custom_foot_js %}
<script
type=
"text/javascript"
>
<script
type=
"text/javascript"
>
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
({
console
.
log
(
$
.
fn
.
select2
.
defaults
);
closeOnSelect
:
false
$
(
'.select2'
).
select2
().
off
(
"select2:open"
);
});
}).
on
(
'click'
,
'.select2-selection__rendered'
,
function
(
e
)
{
e
.
preventDefault
();
$
(
"#asset_list_modal"
).
modal
();
})
.
on
(
'click'
,
'#btn_asset_modal_confirm'
,
function
()
{
var
assets
=
asset_table2
.
selected
;
$
.
each
(
assets
,
function
(
id
,
data
)
{
$
(
'.select2'
).
val
(
assets
).
trigger
(
'change'
);
});
});
$
(
"#asset_list_modal"
).
modal
(
'hide'
);
})
</script>
</script>
{% endblock %}
{% endblock %}
\ No newline at end of file
apps/assets/templates/assets/domain_gateway_list.html
View file @
f450accb
...
@@ -81,11 +81,6 @@ function initTable() {
...
@@ -81,11 +81,6 @@ function initTable() {
var
options
=
{
var
options
=
{
ele
:
$
(
'#domain_list_table'
),
ele
:
$
(
'#domain_list_table'
),
columnDefs
:
[
columnDefs
:
[
{
targets
:
1
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
detail_btn
=
'<a href="{% url "assets:domain-detail" pk=DEFAULT_PK %}">'
+
cellData
+
'</a>'
;
$
(
td
).
html
(
detail_btn
.
replace
(
'{{ DEFAULT_PK }}'
,
rowData
.
id
));
}},
{
targets
:
7
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
{
targets
:
7
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
update_btn
=
'<a href="{% url "assets:domain-gateway-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
var
update_btn
=
'<a href="{% url "assets:domain-gateway-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
var
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs btn-delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
var
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs btn-delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
...
...
apps/assets/templates/assets/label_create_update.html
View file @
f450accb
...
@@ -3,6 +3,8 @@
...
@@ -3,6 +3,8 @@
{% load bootstrap3 %}
{% load bootstrap3 %}
{% load i18n %}
{% load i18n %}
{% block form %}
{% block form %}
<form
id=
"groupForm"
method=
"post"
class=
"form-horizontal"
>
<form
id=
"groupForm"
method=
"post"
class=
"form-horizontal"
>
{% csrf_token %}
{% csrf_token %}
...
@@ -18,14 +20,28 @@
...
@@ -18,14 +20,28 @@
</div>
</div>
</div>
</div>
</form>
</form>
{% include 'assets/_asset_list_modal.html' %}
{% endblock %}
{% endblock %}
{% block custom_foot_js %}
{% block custom_foot_js %}
<script
type=
"text/javascript"
>
<script
type=
"text/javascript"
>
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
({
$
(
'.select2'
).
select2
({
closeOnSelect
:
false
closeOnSelect
:
false
});
})
}).
on
(
'click'
,
'.select2-selection__rendered'
,
function
(
e
)
{
e
.
preventDefault
();
$
(
"#asset_list_modal"
).
modal
();
})
.
on
(
'click'
,
'#btn_asset_modal_confirm'
,
function
()
{
var
assets
=
asset_table2
.
selected
;
$
(
'.select2 option:selected'
).
each
(
function
(
i
,
data
)
{
assets
.
push
(
$
(
data
).
attr
(
'value'
))
});
$
.
each
(
assets
,
function
(
id
,
data
)
{
$
(
'.select2'
).
val
(
assets
).
trigger
(
'change'
);
});
});
$
(
"#asset_list_modal"
).
modal
(
'hide'
);
})
</script>
</script>
{% endblock %}
{% endblock %}
\ No newline at end of file
apps/assets/templates/assets/system_user_detail.html
View file @
f450accb
...
@@ -173,7 +173,7 @@
...
@@ -173,7 +173,7 @@
<td
colspan=
"2"
class=
"no-borders"
>
<td
colspan=
"2"
class=
"no-borders"
>
<select
data-placeholder=
"{% trans 'Add to node' %}"
id=
"node_selected"
class=
"select2"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
<select
data-placeholder=
"{% trans 'Add to node' %}"
id=
"node_selected"
class=
"select2"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
{% for node in nodes_remain %}
{% for node in nodes_remain %}
<option
value=
"{{ node.id }}"
id=
"opt_{{ node.id }}"
>
{{ node
.name
}}
</option>
<option
value=
"{{ node.id }}"
id=
"opt_{{ node.id }}"
>
{{ node }}
</option>
{% endfor %}
{% endfor %}
</select>
</select>
</td>
</td>
...
@@ -187,7 +187,7 @@
...
@@ -187,7 +187,7 @@
{% for node in system_user.nodes.all %}
{% for node in system_user.nodes.all %}
<tr>
<tr>
<td
><b
class=
"bdg_node"
data-gid=
{{
node
.
id
}}
>
{{ node
.name
}}
</b></td>
<td
><b
class=
"bdg_node"
data-gid=
{{
node
.
id
}}
>
{{ node }}
</b></td>
<td>
<td>
<button
class=
"btn btn-danger pull-right btn-xs btn-remove-from-node"
type=
"button"
><i
class=
"fa fa-minus"
></i></button>
<button
class=
"btn btn-danger pull-right btn-xs btn-remove-from-node"
type=
"button"
><i
class=
"fa fa-minus"
></i></button>
</td>
</td>
...
...
apps/assets/urls/api_urls.py
View file @
f450accb
...
@@ -40,6 +40,7 @@ urlpatterns = [
...
@@ -40,6 +40,7 @@ urlpatterns = [
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})/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/$'
,
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/add/$'
,
api
.
NodeAddAssetsApi
.
as_view
(),
name
=
'node-add-assets'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/replace/$'
,
api
.
NodeReplaceAssetsApi
.
as_view
(),
name
=
'node-replace-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})/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'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/refresh-hardware-info/$'
,
api
.
RefreshNodeHardwareInfoApi
.
as_view
(),
name
=
'node-refresh-hardware-info'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$'
,
api
.
TestNodeConnectiveApi
.
as_view
(),
name
=
'node-test-connective'
),
url
(
r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$'
,
api
.
TestNodeConnectiveApi
.
as_view
(),
name
=
'node-test-connective'
),
...
...
apps/assets/views/asset.py
View file @
f450accb
...
@@ -49,6 +49,7 @@ class AssetListView(AdminUserRequiredMixin, TemplateView):
...
@@ -49,6 +49,7 @@ class AssetListView(AdminUserRequiredMixin, TemplateView):
'app'
:
_
(
'Assets'
),
'app'
:
_
(
'Assets'
),
'action'
:
_
(
'Asset list'
),
'action'
:
_
(
'Asset list'
),
'labels'
:
Label
.
objects
.
all
()
.
order_by
(
'name'
),
'labels'
:
Label
.
objects
.
all
()
.
order_by
(
'name'
),
'nodes'
:
Node
.
objects
.
all
()
.
order_by
(
'-key'
),
}
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
return
super
()
.
get_context_data
(
**
kwargs
)
...
@@ -284,24 +285,26 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
...
@@ -284,24 +285,26 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
if
set
(
row
)
==
{
''
}:
if
set
(
row
)
==
{
''
}:
continue
continue
asset_dict
=
dict
(
zip
(
attr
,
row
))
asset_dict
_raw
=
dict
(
zip
(
attr
,
row
))
id_
=
asset_dict
.
pop
(
'id'
,
0
)
asset_dict
=
dict
(
)
for
k
,
v
in
asset_dict
.
items
():
for
k
,
v
in
asset_dict
_raw
.
items
():
v
=
v
.
strip
()
v
=
v
.
strip
()
if
k
==
'is_active'
:
if
k
==
'is_active'
:
v
=
True
if
v
in
[
'TRUE'
,
1
,
'true'
]
else
Fals
e
v
=
False
if
v
in
[
'False'
,
0
,
'false'
]
else
Tru
e
elif
k
==
'admin_user'
:
elif
k
==
'admin_user'
:
v
=
get_object_or_none
(
AdminUser
,
name
=
v
)
v
=
get_object_or_none
(
AdminUser
,
name
=
v
)
elif
k
in
[
'port'
,
'cpu_count'
,
'cpu_cores'
]:
elif
k
in
[
'port'
,
'cpu_count'
,
'cpu_cores'
]:
try
:
try
:
v
=
int
(
v
)
v
=
int
(
v
)
except
ValueError
:
except
ValueError
:
v
=
0
v
=
''
elif
k
==
'domain'
:
elif
k
==
'domain'
:
v
=
get_object_or_none
(
Domain
,
name
=
v
)
v
=
get_object_or_none
(
Domain
,
name
=
v
)
asset_dict
[
k
]
=
v
asset
=
get_object_or_none
(
Asset
,
id
=
id_
)
if
is_uuid
(
id_
)
else
None
if
v
!=
''
:
asset_dict
[
k
]
=
v
asset
=
get_object_or_none
(
Asset
,
id
=
asset_dict
.
pop
(
'id'
,
0
))
if
not
asset
:
if
not
asset
:
try
:
try
:
if
len
(
Asset
.
objects
.
filter
(
hostname
=
asset_dict
.
get
(
'hostname'
))):
if
len
(
Asset
.
objects
.
filter
(
hostname
=
asset_dict
.
get
(
'hostname'
))):
...
@@ -316,7 +319,7 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
...
@@ -316,7 +319,7 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
failed
.
append
(
'
%
s:
%
s'
%
(
asset_dict
[
'hostname'
],
str
(
e
)))
failed
.
append
(
'
%
s:
%
s'
%
(
asset_dict
[
'hostname'
],
str
(
e
)))
else
:
else
:
for
k
,
v
in
asset_dict
.
items
():
for
k
,
v
in
asset_dict
.
items
():
if
v
:
if
v
!=
''
:
setattr
(
asset
,
k
,
v
)
setattr
(
asset
,
k
,
v
)
try
:
try
:
asset
.
save
()
asset
.
save
()
...
...
apps/common/fields.py
View file @
f450accb
...
@@ -2,11 +2,15 @@
...
@@ -2,11 +2,15 @@
#
#
import
json
import
json
from
django.db
import
models
from
django
import
forms
from
django
import
forms
from
django.utils
import
six
from
django.utils
import
six
from
django.core.exceptions
import
ValidationError
from
django.core.exceptions
import
ValidationError
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
rest_framework
import
serializers
from
rest_framework
import
serializers
from
.utils
import
get_signer
signer
=
get_signer
()
class
DictField
(
forms
.
Field
):
class
DictField
(
forms
.
Field
):
...
@@ -46,4 +50,27 @@ class StringIDField(serializers.Field):
...
@@ -46,4 +50,27 @@ class StringIDField(serializers.Field):
class
StringManyToManyField
(
serializers
.
RelatedField
):
class
StringManyToManyField
(
serializers
.
RelatedField
):
def
to_representation
(
self
,
value
):
def
to_representation
(
self
,
value
):
return
value
.
__str__
()
return
value
.
__str__
()
\ No newline at end of file
class
EncryptMixin
:
def
from_db_value
(
self
,
value
,
expression
,
connection
,
context
):
if
value
is
not
None
:
return
signer
.
unsign
(
value
)
return
super
()
.
from_db_value
(
self
,
value
,
expression
,
connection
,
context
)
def
get_prep_value
(
self
,
value
):
if
value
is
None
:
return
value
return
signer
.
sign
(
value
)
.
decode
(
'utf-8'
)
class
EncryptTextField
(
EncryptMixin
,
models
.
TextField
):
description
=
_
(
"Encrypt field using Secret Key"
)
class
EncryptCharField
(
EncryptMixin
,
models
.
CharField
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
kwargs
[
'max_length'
]
=
2048
super
()
.
__init__
(
*
args
,
**
kwargs
)
apps/i18n/zh/LC_MESSAGES/django.mo
View file @
f450accb
No preview for this file type
apps/i18n/zh/LC_MESSAGES/django.po
View file @
f450accb
This diff is collapsed.
Click to expand it.
apps/jumpserver/urls.py
View file @
f450accb
...
@@ -36,9 +36,10 @@ urlpatterns = [
...
@@ -36,9 +36,10 @@ urlpatterns = [
url
(
r'^captcha/'
,
include
(
'captcha.urls'
)),
url
(
r'^captcha/'
,
include
(
'captcha.urls'
)),
]
]
urlpatterns
+=
static
(
settings
.
MEDIA_URL
,
document_root
=
settings
.
MEDIA_ROOT
)
\
+
static
(
settings
.
STATIC_URL
,
document_root
=
settings
.
STATIC_ROOT
)
if
settings
.
DEBUG
:
if
settings
.
DEBUG
:
urlpatterns
+=
[
urlpatterns
+=
[
url
(
r'^docs/'
,
schema_view
,
name
=
"docs"
),
url
(
r'^docs/'
,
schema_view
,
name
=
"docs"
),
]
+
static
(
settings
.
STATIC_URL
,
document_root
=
settings
.
STATIC_ROOT
)
\
]
+
static
(
settings
.
MEDIA_URL
,
document_root
=
settings
.
MEDIA_ROOT
)
apps/perms/api.py
View file @
f450accb
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
from
django.shortcuts
import
get_object_or_404
from
django.shortcuts
import
get_object_or_404
from
rest_framework.views
import
APIView
,
Response
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
rest_framework
import
viewsets
from
common.utils
import
set_or_append_attr_bulk
from
common.utils
import
set_or_append_attr_bulk
...
@@ -98,6 +98,11 @@ class UserGrantedNodesApi(ListAPIView):
...
@@ -98,6 +98,11 @@ class UserGrantedNodesApi(ListAPIView):
nodes
=
AssetPermissionUtil
.
get_user_nodes_with_assets
(
user
)
nodes
=
AssetPermissionUtil
.
get_user_nodes_with_assets
(
user
)
return
nodes
.
keys
()
return
nodes
.
keys
()
def
get_permissions
(
self
):
if
self
.
kwargs
.
get
(
'pk'
)
is
None
:
self
.
permission_classes
=
(
IsValidUser
,)
return
super
()
.
get_permissions
()
class
UserGrantedNodesWithAssetsApi
(
ListAPIView
):
class
UserGrantedNodesWithAssetsApi
(
ListAPIView
):
permission_classes
=
(
IsSuperUserOrAppUser
,)
permission_classes
=
(
IsSuperUserOrAppUser
,)
...
@@ -246,3 +251,77 @@ class ValidateUserAssetPermissionView(APIView):
...
@@ -246,3 +251,77 @@ class ValidateUserAssetPermissionView(APIView):
return
Response
({
'msg'
:
True
},
status
=
200
)
return
Response
({
'msg'
:
True
},
status
=
200
)
else
:
else
:
return
Response
({
'msg'
:
False
},
status
=
403
)
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 @
f450accb
...
@@ -4,10 +4,23 @@ from __future__ import absolute_import, unicode_literals
...
@@ -4,10 +4,23 @@ from __future__ import absolute_import, unicode_literals
from
django
import
forms
from
django
import
forms
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
.hands
import
User
from
.models
import
AssetPermission
from
.models
import
AssetPermission
class
AssetPermissionForm
(
forms
.
ModelForm
):
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
:
class
Meta
:
model
=
AssetPermission
model
=
AssetPermission
exclude
=
(
exclude
=
(
...
...
apps/perms/models.py
View file @
f450accb
...
@@ -4,7 +4,7 @@ from django.db import models
...
@@ -4,7 +4,7 @@ from django.db import models
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils
import
timezone
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
):
class
ValidManager
(
models
.
Manager
):
...
@@ -45,6 +45,22 @@ class AssetPermission(models.Model):
...
@@ -45,6 +45,22 @@ class AssetPermission(models.Model):
return
True
return
True
return
False
return
False
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_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
class
NodePermission
(
models
.
Model
):
class
NodePermission
(
models
.
Model
):
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
...
...
apps/perms/templates/perms/asset_permission_asset.html
View file @
f450accb
...
@@ -57,12 +57,12 @@
...
@@ -57,12 +57,12 @@
</tr>
</tr>
</thead>
</thead>
<tbody>
<tbody>
{% for asset in
page_obj
%}
{% for asset in
object_list
%}
<tr>
<tr>
<td>
{{ asset.hostname }}
</td>
<td>
{{ asset.hostname }}
</td>
<td>
{{ asset.ip }}
</td>
<td>
{{ asset.ip }}
</td>
<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>
</td>
</tr>
</tr>
{% endfor %}
{% endfor %}
...
@@ -85,9 +85,9 @@
...
@@ -85,9 +85,9 @@
<form>
<form>
<tr
class=
"no-borders-tr"
>
<tr
class=
"no-borders-tr"
>
<td
colspan=
"2"
>
<td
colspan=
"2"
>
<select
data-placeholder=
"{% trans 'Select assets' %}"
class=
"select2
asset
"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
<select
data-placeholder=
"{% trans 'Select assets' %}"
class=
"select2
"
id=
"asset_select2
"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
{% for asset in assets_remain %}
{% for asset in assets_remain %}
<option
value=
"{{ asset.id }}"
>
{{ asset
.hostname
}}
</option>
<option
value=
"{{ asset.id }}"
>
{{ asset }}
</option>
{% endfor %}
{% endfor %}
</select>
</select>
</td>
</td>
...
@@ -105,7 +105,7 @@
...
@@ -105,7 +105,7 @@
<div
class=
"panel panel-info"
>
<div
class=
"panel panel-info"
>
<div
class=
"panel-heading"
>
<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>
<div
class=
"panel-body"
>
<div
class=
"panel-body"
>
<table
class=
"table group_edit"
>
<table
class=
"table group_edit"
>
...
@@ -113,25 +113,25 @@
...
@@ -113,25 +113,25 @@
<form>
<form>
<tr>
<tr>
<td
colspan=
"2"
class=
"no-borders"
>
<td
colspan=
"2"
class=
"no-borders"
>
<select
data-placeholder=
"{% trans 'Select
asset groups' %}"
class=
"select2 group
"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
<select
data-placeholder=
"{% trans 'Select
nodes' %}"
class=
"select2"
id=
"node_select2
"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
{% for
asset_group in asset_group
s_remain %}
{% for
node in node
s_remain %}
<option
value=
"{{
asset_group.id }}"
id=
"opt_{{ asset_group.id }}"
>
{{ asset_group.nam
e }}
</option>
<option
value=
"{{
node.id }}"
id=
"opt_{{ node.id }}"
>
{{ nod
e }}
</option>
{% endfor %}
{% endfor %}
</select>
</select>
</td>
</td>
</tr>
</tr>
<tr>
<tr>
<td
colspan=
"2"
class=
"no-borders"
>
<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>
</td>
</tr>
</tr>
</form>
</form>
{% for
asset_group in asset_groups
%}
{% for
node in asset_permission.nodes.all
%}
<tr>
<tr>
<td
><b
class=
"bdg_
user_group"
data-gid=
{{
asset_group
.
id
}}
>
{{ asset_group.nam
e }}
</b></td>
<td
><b
class=
"bdg_
group"
data-gid=
{{
node
.
id
}}
>
{{ nod
e }}
</b></td>
<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"
data-gid=
"{{ node.id }}
"
style=
"float: right;"
><i
class=
"fa fa-minus"
></i></button>
</td>
</td>
</tr>
</tr>
{% endfor %}
{% endfor %}
...
@@ -179,49 +179,30 @@ function removeAssets(assets) {
...
@@ -179,49 +179,30 @@ function removeAssets(assets) {
});
});
}
}
function
update
Group
(
group
s
)
{
function
update
Nodes
(
nodes
,
succes
s
)
{
var
the_url
=
"{% url 'api-perms:asset-permission-detail' pk=asset_permission.id %}"
;
var
the_url
=
"{% url 'api-perms:asset-permission-detail' pk=asset_permission.id %}"
;
var
body
=
{
var
body
=
{
asset_groups
:
group
s
nodes
:
node
s
};
};
APIUpdateAttr
({
APIUpdateAttr
({
url
:
the_url
,
url
:
the_url
,
body
:
JSON
.
stringify
(
body
)
body
:
JSON
.
stringify
(
body
),
success
:
success
});
});
}
}
jumpserver
.
assets_selected
=
{};
jumpserver
.
nodes_selected
=
{};
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
$
(
'.select2.asset'
).
select2
()
$
(
'.select2'
).
select2
();
.
on
(
'select2:select'
,
function
(
evt
)
{
var
data
=
evt
.
params
.
data
;
jumpserver
.
assets_selected
[
data
.
id
]
=
data
.
text
;
})
.
on
(
'select2:unselect'
,
function
(
evt
)
{
var
data
=
evt
.
params
.
data
;
delete
jumpserver
.
assets_selected
[
data
.
id
]
});
$
(
'.select2.group'
).
select2
()
.
on
(
'select2:select'
,
function
(
evt
)
{
var
data
=
evt
.
params
.
data
;
jumpserver
.
nodes_selected
[
data
.
id
]
=
data
.
text
;
})
.
on
(
'select2:unselect'
,
function
(
evt
)
{
var
data
=
evt
.
params
.
data
;
delete
jumpserver
.
nodes_selected
[
data
.
id
]
})
})
})
.
on
(
'click'
,
'.btn-add-assets'
,
function
()
{
.
on
(
'click'
,
'.btn-add-assets'
,
function
()
{
if
(
Object
.
keys
(
jumpserver
.
assets_selected
).
length
===
0
)
{
var
assets_selected
=
$
(
"#asset_select2 option:selected"
).
map
(
function
()
{
return
$
(
this
).
attr
(
'value'
);
}).
get
();
if
(
assets_selected
.
length
===
0
)
{
return
false
;
return
false
;
}
}
var
assets
=
[];
addAssets
(
assets_selected
);
$
.
map
(
jumpserver
.
assets_selected
,
function
(
value
,
index
)
{
assets
.
push
(
index
);
});
addAssets
(
assets
);
})
})
.
on
(
'click'
,
'.btn-remove-asset'
,
function
()
{
.
on
(
'click'
,
'.btn-remove-asset'
,
function
()
{
var
asset_id
=
$
(
this
).
data
(
"gid"
);
var
asset_id
=
$
(
this
).
data
(
"gid"
);
...
@@ -231,38 +212,44 @@ $(document).ready(function () {
...
@@ -231,38 +212,44 @@ $(document).ready(function () {
var
assets
=
[
asset_id
];
var
assets
=
[
asset_id
];
removeAssets
(
assets
)
removeAssets
(
assets
)
})
})
.
on
(
'click'
,
'#btn-add-group'
,
function
()
{
.
on
(
'click'
,
'#btn-add-node'
,
function
()
{
if
(
Object
.
keys
(
jumpserver
.
nodes_selected
).
length
===
0
)
{
var
nodes_selected
=
{};
$
(
"#node_select2 option:selected"
).
each
(
function
(
i
,
data
)
{
nodes_selected
[
$
(
data
).
attr
(
'value'
)]
=
$
(
data
).
text
();
});
if
(
Object
.
keys
(
nodes_selected
).
length
===
0
)
{
return
false
;
return
false
;
}
}
var
nodes_origin
=
$
(
'.bdg_group'
).
map
(
function
()
{
var
groups
=
$
(
'.bdg_group'
).
map
(
function
()
{
return
$
(
this
).
data
(
'gid'
);
return
$
(
this
).
data
(
'gid'
);
}).
get
();
}).
get
();
$
.
map
(
jumpserver
.
nodes_selected
,
function
(
group_name
,
index
)
{
var
nodes
=
nodes_origin
.
concat
(
Object
.
keys
(
nodes_selected
));
groups
.
push
(
index
);
var
success
=
function
()
{
$
(
'#opt_'
+
index
).
remove
();
$
.
map
(
nodes_selected
,
function
(
name
,
id
)
{
$
(
'.group_edit tbody'
).
append
(
$
(
'#opt_'
+
id
).
remove
();
'<tr>'
+
$
(
'.group_edit tbody'
).
append
(
'<td><b class="bdg_group" data-gid="'
+
index
+
'">'
+
group_name
+
'</b></td>'
+
'<tr>'
+
'<td><button class="btn btn-danger btn-xs pull-right btn-leave-group" type="button"><i class="fa fa-minus"></i></button></td>'
+
'<td><b class="bdg_group" data-gid="'
+
id
+
'">'
+
name
+
'</b></td>'
+
'</tr>'
'<td><button class="btn btn-danger btn-xs pull-right btn-leave-group" type="button"><i class="fa fa-minus"></i></button></td>'
+
)
'</tr>'
});
)
});
updateGroup
(
groups
);
};
updateNodes
(
nodes
,
success
);
})
})
.
on
(
'click'
,
'.btn-remove-
group
'
,
function
()
{
.
on
(
'click'
,
'.btn-remove-
node
'
,
function
()
{
var
$this
=
$
(
this
);
var
$this
=
$
(
this
);
var
$tr
=
$this
.
closest
(
'tr'
);
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'
)){
if
(
$
(
this
).
data
(
'gid'
)
!==
$this
.
data
(
'gid'
)){
return
$
(
this
).
data
(
'gid'
);
return
$
(
this
).
data
(
'gid'
);
}
}
}).
get
();
}).
get
();
updateGroup
(
groups
);
var
success
=
function
()
{
$tr
.
remove
()
$tr
.
remove
()
};
updateNodes
(
nodes
,
success
);
})
})
</script>
</script>
{% endblock %}
{% endblock %}
apps/perms/templates/perms/asset_permission_create_update.html
View file @
f450accb
...
@@ -76,20 +76,37 @@
...
@@ -76,20 +76,37 @@
</div>
</div>
</div>
</div>
</div>
</div>
{% include 'assets/_asset_list_modal.html' %}
{% endblock %}
{% endblock %}
{% block custom_foot_js %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"
></script>
<script
src=
"{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"
></script>
<script>
<script>
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
();
$
(
'.select2'
).
select2
({
$
(
'#datepicker'
).
datepicker
({
closeOnSelect
:
false
format
:
"yyyy-mm-dd"
,
});
todayBtn
:
"linked"
,
$
(
'#datepicker'
).
datepicker
({
keyboardNavigation
:
false
,
format
:
"yyyy-mm-dd"
,
forceParse
:
false
,
todayBtn
:
"linked"
,
calendarWeeks
:
true
,
keyboardNavigation
:
false
,
autoclose
:
true
forceParse
:
false
,
});
calendarWeeks
:
true
,
})
autoclose
:
true
</script>
});
$
(
"#id_assets"
).
parent
().
find
(
".select2-selection"
).
on
(
'click'
,
function
(
e
)
{
e
.
preventDefault
();
$
(
"#asset_list_modal"
).
modal
();
})
})
.
on
(
'click'
,
'#btn_asset_modal_confirm'
,
function
()
{
var
assets
=
asset_table2
.
selected
;
$
(
'.select2 option:selected'
).
each
(
function
(
i
,
data
)
{
assets
.
push
(
$
(
data
).
attr
(
'value'
))
});
$
.
each
(
assets
,
function
(
id
,
data
)
{
$
(
'.select2'
).
val
(
assets
).
trigger
(
'change'
);
});
$
(
"#asset_list_modal"
).
modal
(
'hide'
);
})
</script>
{% endblock %}
{% endblock %}
\ No newline at end of file
apps/perms/templates/perms/asset_permission_detail.html
View file @
f450accb
This diff is collapsed.
Click to expand it.
apps/perms/templates/perms/asset_permission_user.html
View file @
f450accb
...
@@ -57,12 +57,12 @@
...
@@ -57,12 +57,12 @@
</tr>
</tr>
</thead>
</thead>
<tbody>
<tbody>
{% for user in
page_obj
%}
{% for user in
object_list
%}
<tr>
<tr>
<td>
{{ user.name }}
</td>
<td>
{{ user.name }}
</td>
<td>
{{ user.username }}
</td>
<td>
{{ user.username }}
</td>
<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>
</td>
</tr>
</tr>
{% endfor %}
{% endfor %}
...
@@ -87,7 +87,7 @@
...
@@ -87,7 +87,7 @@
<td
colspan=
"2"
>
<td
colspan=
"2"
>
<select
data-placeholder=
"{% trans 'Select user' %}"
class=
"select2 user"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
<select
data-placeholder=
"{% trans 'Select user' %}"
class=
"select2 user"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
{% for user in users_remain %}
{% for user in users_remain %}
<option
value=
"{{ user.id }}"
>
{{ user
.name
}}
</option>
<option
value=
"{{ user.id }}"
>
{{ user }}
</option>
{% endfor %}
{% endfor %}
</select>
</select>
</td>
</td>
...
@@ -115,7 +115,7 @@
...
@@ -115,7 +115,7 @@
<td
colspan=
"2"
class=
"no-borders"
>
<td
colspan=
"2"
class=
"no-borders"
>
<select
data-placeholder=
"{% trans 'Select user groups' %}"
class=
"select2 user-group"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
<select
data-placeholder=
"{% trans 'Select user groups' %}"
class=
"select2 user-group"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
>
{% for user_group in user_groups_remain %}
{% for user_group in user_groups_remain %}
<option
value=
"{{ user_group.id }}"
id=
"opt_{{ user_group.id }}"
>
{{ user_group
.name
}}
</option>
<option
value=
"{{ user_group.id }}"
id=
"opt_{{ user_group.id }}"
>
{{ user_group }}
</option>
{% endfor %}
{% endfor %}
</select>
</select>
</td>
</td>
...
@@ -127,9 +127,9 @@
...
@@ -127,9 +127,9 @@
</tr>
</tr>
</form>
</form>
{% for user_group in
user_groups
%}
{% for user_group in
asset_permission.user_groups.all
%}
<tr>
<tr>
<td
><b
class=
"bdg_group"
data-gid=
{{
user_group
.
id
}}
>
{{ user_group
.name
}}
</b></td>
<td
><b
class=
"bdg_group"
data-gid=
{{
user_group
.
id
}}
>
{{ user_group }}
</b></td>
<td>
<td>
<button
class=
"btn btn-danger btn-xs btn-remove-group"
type=
"button"
data-gid=
"{{ user_group.id }}"
style=
"float: right;"
><i
class=
"fa fa-minus"
></i></button>
<button
class=
"btn btn-danger btn-xs btn-remove-group"
type=
"button"
data-gid=
"{{ user_group.id }}"
style=
"float: right;"
><i
class=
"fa fa-minus"
></i></button>
</td>
</td>
...
...
apps/perms/urls/api_urls.py
View file @
f450accb
...
@@ -11,20 +11,50 @@ router.register('v1/asset-permissions', api.AssetPermissionViewSet, 'asset-permi
...
@@ -11,20 +11,50 @@ router.register('v1/asset-permissions', api.AssetPermissionViewSet, 'asset-permi
urlpatterns
=
[
urlpatterns
=
[
# 查询某个用户授权的资产和资产组
# 查询某个用户授权的资产和资产组
url
(
r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
UserGrantedAssetsApi
.
as_view
(),
name
=
'user-assets'
),
url
(
r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$'
,
url
(
r'^v1/user/assets/$'
,
api
.
UserGrantedAssetsApi
.
as_view
(),
name
=
'my-assets'
),
api
.
UserGrantedAssetsApi
.
as_view
(),
name
=
'user-assets'
),
url
(
r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$'
,
api
.
UserGrantedNodesApi
.
as_view
(),
name
=
'user-nodes'
),
url
(
r'^v1/user/assets/$'
,
api
.
UserGrantedAssetsApi
.
as_view
(),
url
(
r'^v1/user/nodes/$'
,
api
.
UserGrantedNodesApi
.
as_view
(),
name
=
'my-nodes'
),
name
=
'my-assets'
),
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/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$'
,
url
(
r'^v1/user/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$'
,
api
.
UserGrantedNodeAssetsApi
.
as_view
(),
name
=
'my-node-assets'
),
api
.
UserGrantedNodesApi
.
as_view
(),
name
=
'user-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/$'
,
api
.
UserGrantedNodesApi
.
as_view
(),
url
(
r'^v1/user/nodes-assets/$'
,
api
.
UserGrantedNodesWithAssetsApi
.
as_view
(),
name
=
'my-nodes-assets'
),
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})/assets/$'
,
url
(
r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$'
,
api
.
UserGroupGrantedNodesApi
.
as_view
(),
name
=
'user-group-nodes'
),
api
.
UserGroupGrantedAssetsApi
.
as_view
(),
name
=
'user-group-assets'
),
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/$'
,
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'
),
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'
),
url
(
r'v1/asset-permission/user/validate/$'
,
api
.
ValidateUserAssetPermissionView
.
as_view
(),
name
=
'validate-user-asset-permission'
),
...
...
apps/perms/urls/views_urls.py
View file @
f450accb
...
@@ -11,8 +11,8 @@ urlpatterns = [
...
@@ -11,8 +11,8 @@ urlpatterns = [
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})/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})/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})/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})/asset$'
,
views
.
AssetPermissionAssetView
.
as_view
(),
name
=
'asset-permission-asset-list'
),
]
]
apps/perms/views.py
View file @
f450accb
...
@@ -4,12 +4,12 @@ from __future__ import unicode_literals, absolute_import
...
@@ -4,12 +4,12 @@ from __future__ import unicode_literals, absolute_import
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django.views.generic
import
ListView
,
CreateView
,
UpdateView
,
DetailView
from
django.views.generic
import
ListView
,
CreateView
,
UpdateView
,
DetailView
from
django.views.generic.edit
import
DeleteView
from
django.views.generic.edit
import
DeleteView
,
SingleObjectMixin
from
django.urls
import
reverse_lazy
from
django.urls
import
reverse_lazy
from
django.conf
import
settings
from
django.conf
import
settings
from
common.
utils
import
is_uuid
from
common.
mixins
import
AdminUserRequiredMixin
from
.hands
import
AdminUserRequiredMixin
,
Node
,
Asset
from
.hands
import
Node
,
Asset
,
SystemUser
,
User
,
UserGroup
from
.models
import
AssetPermission
from
.models
import
AssetPermission
from
.forms
import
AssetPermissionForm
from
.forms
import
AssetPermissionForm
...
@@ -83,7 +83,11 @@ class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
...
@@ -83,7 +83,11 @@ class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
context
=
{
'app'
:
_
(
'Perms'
),
'app'
:
_
(
'Perms'
),
'action'
:
_
(
'Update asset permission'
)
'action'
:
_
(
'Update asset permission'
),
'system_users_remain'
:
SystemUser
.
objects
.
exclude
(
granted_by_permissions
=
self
.
object
),
}
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
return
super
()
.
get_context_data
(
**
kwargs
)
...
@@ -95,3 +99,59 @@ class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView):
...
@@ -95,3 +99,59 @@ class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView):
success_url
=
reverse_lazy
(
'perms:asset-permission-list'
)
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/js/jumpserver.js
View file @
f450accb
...
@@ -307,7 +307,7 @@ jumpserver.initDataTable = function (options) {
...
@@ -307,7 +307,7 @@ jumpserver.initDataTable = function (options) {
last
:
"»"
last
:
"»"
}
}
},
},
lengthMenu
:
[[
1
5
,
25
,
50
,
-
1
],
[
15
,
25
,
50
,
"All"
]]
lengthMenu
:
[[
1
0
,
15
,
25
,
50
,
-
1
],
[
10
,
15
,
25
,
50
,
"All"
]]
});
});
table
.
on
(
'select'
,
function
(
e
,
dt
,
type
,
indexes
)
{
table
.
on
(
'select'
,
function
(
e
,
dt
,
type
,
indexes
)
{
var
$node
=
table
[
type
](
indexes
).
nodes
().
to$
();
var
$node
=
table
[
type
](
indexes
).
nodes
().
to$
();
...
@@ -446,22 +446,56 @@ jumpserver.initServerSideDataTable = function (options) {
...
@@ -446,22 +446,56 @@ jumpserver.initServerSideDataTable = function (options) {
last
:
"»"
last
:
"»"
}
}
},
},
lengthMenu
:
[[
1
5
,
25
,
50
],
[
15
,
25
,
50
]]
lengthMenu
:
[[
1
0
,
15
,
25
,
50
],
[
10
,
15
,
25
,
50
]]
});
});
table
.
selected
=
[];
table
.
on
(
'select'
,
function
(
e
,
dt
,
type
,
indexes
)
{
table
.
on
(
'select'
,
function
(
e
,
dt
,
type
,
indexes
)
{
var
$node
=
table
[
type
](
indexes
).
nodes
().
to$
();
var
$node
=
table
[
type
](
indexes
).
nodes
().
to$
();
$node
.
find
(
'input.ipt_check'
).
prop
(
'checked'
,
true
);
$node
.
find
(
'input.ipt_check'
).
prop
(
'checked'
,
true
);
jumpserver
.
selected
[
$node
.
find
(
'input.ipt_check'
).
prop
(
'id'
)]
=
true
jumpserver
.
selected
[
$node
.
find
(
'input.ipt_check'
).
prop
(
'id'
)]
=
true
;
if
(
type
===
'row'
)
{
var
rows
=
table
.
rows
(
indexes
).
data
();
$
.
each
(
rows
,
function
(
id
,
row
)
{
if
(
row
.
id
){
table
.
selected
.
push
(
row
.
id
)
}
})
}
}).
on
(
'deselect'
,
function
(
e
,
dt
,
type
,
indexes
)
{
}).
on
(
'deselect'
,
function
(
e
,
dt
,
type
,
indexes
)
{
var
$node
=
table
[
type
](
indexes
).
nodes
().
to$
();
var
$node
=
table
[
type
](
indexes
).
nodes
().
to$
();
$node
.
find
(
'input.ipt_check'
).
prop
(
'checked'
,
false
);
$node
.
find
(
'input.ipt_check'
).
prop
(
'checked'
,
false
);
jumpserver
.
selected
[
$node
.
find
(
'input.ipt_check'
).
prop
(
'id'
)]
=
false
jumpserver
.
selected
[
$node
.
find
(
'input.ipt_check'
).
prop
(
'id'
)]
=
false
;
if
(
type
===
'row'
)
{
var
rows
=
table
.
rows
(
indexes
).
data
();
$
.
each
(
rows
,
function
(
id
,
row
)
{
if
(
row
.
id
){
var
index
=
table
.
selected
.
indexOf
(
row
.
id
);
if
(
index
>
-
1
){
table
.
selected
.
splice
(
index
,
1
)
}
}
})
}
}).
}).
on
(
'draw'
,
function
(){
on
(
'draw'
,
function
(){
$
(
'#op'
).
html
(
options
.
op_html
||
''
);
$
(
'#op'
).
html
(
options
.
op_html
||
''
);
$
(
'#uc'
).
html
(
options
.
uc_html
||
''
);
$
(
'#uc'
).
html
(
options
.
uc_html
||
''
);
var
table_data
=
[];
$
.
each
(
table
.
rows
().
data
(),
function
(
id
,
row
)
{
if
(
row
.
id
)
{
table_data
.
push
(
row
.
id
)
}
});
$
.
each
(
table
.
selected
,
function
(
id
,
data
)
{
var
index
=
table_data
.
indexOf
(
data
);
if
(
index
>
-
1
){
table
.
rows
(
index
).
select
()
}
});
});
});
$
(
'.ipt_check_all'
).
on
(
'click'
,
function
()
{
var
table_id
=
table
.
settings
()[
0
].
sTableId
;
$
(
'#'
+
table_id
+
' .ipt_check_all'
).
on
(
'click'
,
function
()
{
if
(
$
(
this
).
prop
(
"checked"
))
{
if
(
$
(
this
).
prop
(
"checked"
))
{
$
(
this
).
closest
(
'table'
).
find
(
'.ipt_check'
).
prop
(
'checked'
,
true
);
$
(
this
).
closest
(
'table'
).
find
(
'.ipt_check'
).
prop
(
'checked'
,
true
);
table
.
rows
({
search
:
'applied'
,
page
:
'current'
}).
select
();
table
.
rows
({
search
:
'applied'
,
page
:
'current'
}).
select
();
...
...
apps/templates/_footer.html
View file @
f450accb
<div
class=
"footer fixed"
>
<div
class=
"footer fixed"
>
<div
class=
"pull-right"
>
<div
class=
"pull-right"
>
Version
<strong>
1.
0
.0-{% include '_build.html' %}
</strong>
GPLv2.
Version
<strong>
1.
2
.0-{% include '_build.html' %}
</strong>
GPLv2.
<img
style=
"display: none"
src=
"http://www.jumpserver.org/img/evaluate_avatar1.jpg"
>
<img
style=
"display: none"
src=
"http://www.jumpserver.org/img/evaluate_avatar1.jpg"
>
</div>
</div>
<div>
<div>
...
...
apps/templates/_modal.html
View file @
f450accb
{% load i18n %}
{% load i18n %}
<style>
.modal-body
{
padding
:
0px
20px
0px
20px
;
}
</style>
<div
aria-hidden=
"true"
role=
"dialog"
id=
"{% block modal_id %}{% endblock %}"
class=
"modal inmodal"
>
<div
aria-hidden=
"true"
role=
"dialog"
id=
"{% block modal_id %}{% endblock %}"
class=
"modal inmodal"
>
<div
class=
"modal-dialog {% block modal_class %}{% endblock %}"
>
<div
class=
"modal-dialog {% block modal_class %}{% endblock %}"
>
<div
class=
"modal-content animated fadeIn"
>
<div
class=
"modal-content animated fadeIn"
>
...
@@ -12,8 +17,10 @@
...
@@ -12,8 +17,10 @@
{% endblock %}
{% endblock %}
</div>
</div>
<div
class=
"modal-footer"
>
<div
class=
"modal-footer"
>
{% block modal_button %}
<button
data-dismiss=
"modal"
class=
"btn btn-white"
type=
"button"
>
{% trans "Close" %}
</button>
<button
data-dismiss=
"modal"
class=
"btn btn-white"
type=
"button"
>
{% trans "Close" %}
</button>
<button
class=
"btn btn-primary"
type=
"button"
id=
"{% block modal_confirm_id %}{% endblock %}"
>
{% trans 'Confirm' %}
</button>
<button
class=
"btn btn-primary"
type=
"button"
id=
"{% block modal_confirm_id %}{% endblock %}"
>
{% trans 'Confirm' %}
</button>
{% endblock %}
</div>
</div>
</div>
</div>
</div>
</div>
...
...
apps/templates/_nav.html
View file @
f450accb
...
@@ -61,7 +61,7 @@
...
@@ -61,7 +61,7 @@
</li>
</li>
<li
id=
"audits"
>
<li
id=
"audits"
>
<a>
<a>
<i
class=
"fa fa-
coffee
"
style=
"width: 14px"
></i>
<span
class=
"nav-label"
>
{% trans 'Audits' %}
</span><span
class=
"fa arrow"
></span>
<i
class=
"fa fa-
history
"
style=
"width: 14px"
></i>
<span
class=
"nav-label"
>
{% trans 'Audits' %}
</span><span
class=
"fa arrow"
></span>
</a>
</a>
<ul
class=
"nav nav-second-level"
>
<ul
class=
"nav nav-second-level"
>
<li
id=
"ftp-log"
><a
href=
"{% url 'audits:ftp-log-list' %}"
>
{% trans 'FTP log' %}
</a></li>
<li
id=
"ftp-log"
><a
href=
"{% url 'audits:ftp-log-list' %}"
>
{% trans 'FTP log' %}
</a></li>
...
...
apps/terminal/api.py
View file @
f450accb
...
@@ -248,7 +248,7 @@ class CommandViewSet(viewsets.ViewSet):
...
@@ -248,7 +248,7 @@ class CommandViewSet(viewsets.ViewSet):
class
SessionReplayViewSet
(
viewsets
.
ViewSet
):
class
SessionReplayViewSet
(
viewsets
.
ViewSet
):
serializer_class
=
ReplaySerializer
serializer_class
=
ReplaySerializer
permission_classes
=
()
permission_classes
=
(
IsSuperUserOrAppUser
,
)
session
=
None
session
=
None
def
gen_session_path
(
self
):
def
gen_session_path
(
self
):
...
...
apps/users/models/user.py
View file @
f450accb
...
@@ -45,7 +45,7 @@ class User(AbstractUser):
...
@@ -45,7 +45,7 @@ class User(AbstractUser):
wechat
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
verbose_name
=
_
(
'Wechat'
))
wechat
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
verbose_name
=
_
(
'Wechat'
))
phone
=
models
.
CharField
(
max_length
=
20
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Phone'
))
phone
=
models
.
CharField
(
max_length
=
20
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Phone'
))
otp_level
=
models
.
SmallIntegerField
(
default
=
0
,
choices
=
OTP_LEVEL_CHOICES
,
verbose_name
=
_
(
'Enable OTP'
))
otp_level
=
models
.
SmallIntegerField
(
default
=
0
,
choices
=
OTP_LEVEL_CHOICES
,
verbose_name
=
_
(
'Enable OTP'
))
otp_secret_key
=
models
.
CharField
(
max_length
=
16
,
blank
=
True
,
null
=
True
)
_otp_secret_key
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
)
# Todo: Auto generate key, let user download
# Todo: Auto generate key, let user download
_private_key
=
models
.
CharField
(
max_length
=
5000
,
blank
=
True
,
verbose_name
=
_
(
'Private key'
))
_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'
))
_public_key
=
models
.
CharField
(
max_length
=
5000
,
blank
=
True
,
verbose_name
=
_
(
'Public key'
))
...
@@ -55,7 +55,7 @@ class User(AbstractUser):
...
@@ -55,7 +55,7 @@ class User(AbstractUser):
created_by
=
models
.
CharField
(
max_length
=
30
,
default
=
''
,
verbose_name
=
_
(
'Created by'
))
created_by
=
models
.
CharField
(
max_length
=
30
,
default
=
''
,
verbose_name
=
_
(
'Created by'
))
def
__str__
(
self
):
def
__str__
(
self
):
return
self
.
username
return
'{0.name}({0.username})'
.
format
(
self
)
@property
@property
def
password_raw
(
self
):
def
password_raw
(
self
):
...
@@ -70,6 +70,14 @@ class User(AbstractUser):
...
@@ -70,6 +70,14 @@ class User(AbstractUser):
def
password_raw
(
self
,
password_raw_
):
def
password_raw
(
self
,
password_raw_
):
self
.
set_password
(
password_raw_
)
self
.
set_password
(
password_raw_
)
@property
def
otp_secret_key
(
self
):
return
signer
.
unsign
(
self
.
_otp_secret_key
)
@otp_secret_key.setter
def
otp_secret_key
(
self
,
item
):
self
.
_otp_secret_key
=
signer
.
sign
(
item
)
.
decode
(
'utf-8'
)
def
get_absolute_url
(
self
):
def
get_absolute_url
(
self
):
return
reverse
(
'users:user-detail'
,
args
=
(
self
.
id
,))
return
reverse
(
'users:user-detail'
,
args
=
(
self
.
id
,))
...
...
docs/quickstart.rst
View file @
f450accb
...
@@ -13,7 +13,7 @@ Docker 安装见: `Docker官方安装文档 <https://docs.docker.com/install/>`_
...
@@ -13,7 +13,7 @@ Docker 安装见: `Docker官方安装文档 <https://docs.docker.com/install/>`_
```````````````
```````````````
使用 root 命令行输入::
使用 root 命令行输入::
$ docker run -d -p 8080:80 -p 2222:2222 registry.jumpserver.org/public/jumpserver:
latest
$ docker run -d -p 8080:80 -p 2222:2222 registry.jumpserver.org/public/jumpserver:
1.0.0
访问
访问
```````````````
```````````````
...
@@ -42,10 +42,13 @@ XShell等工具请添加connection连接
...
@@ -42,10 +42,13 @@ XShell等工具请添加connection连接
::
::
docker run -d -p 8080:80 -p 2222:2222 -e DB_ENGINE=mysql -e DB_HOST=192.168.1.1 -e DB_PORT=3306 -e DB_USER=root -e DB_PASSWORD=xxx -e DB_NAME=jumpserver registry.jumpserver.org/public/jumpserver:
latest
docker run -d -p 8080:80 -p 2222:2222 -e DB_ENGINE=mysql -e DB_HOST=192.168.1.1 -e DB_PORT=3306 -e DB_USER=root -e DB_PASSWORD=xxx -e DB_NAME=jumpserver registry.jumpserver.org/public/jumpserver:
1.0.0
仓库地址
仓库地址
```````````````
```````````````
https://github.com/jumpserver/Dockerfile
https://github.com/jumpserver/Dockerfile
docs/step_by_step.rst
View file @
f450accb
...
@@ -49,7 +49,7 @@
...
@@ -49,7 +49,7 @@
# 看到下面的提示符代表成功,以后运行 Jumpserver 都要先运行以上 source 命令,以下所有命令均在该虚拟环境中运行
# 看到下面的提示符代表成功,以后运行 Jumpserver 都要先运行以上 source 命令,以下所有命令均在该虚拟环境中运行
(py3) [root@localhost py3]
(py3) [root@localhost py3]
二. 安装 Jumpserver
0.5
.0
二. 安装 Jumpserver
1.0
.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**2.1 下载或 Clone 项目**
**2.1 下载或 Clone 项目**
...
@@ -201,7 +201,7 @@
...
@@ -201,7 +201,7 @@
Luna 已改为纯前端,需要 Nginx 来运行访问
Luna 已改为纯前端,需要 Nginx 来运行访问
访问(https://github.com/jumpserver/luna/releases)下载对应 release 包,直接解压,不需要编译
访问(https://github.com/jumpserver/luna/releases)下载对应
版本的
release 包,直接解压,不需要编译
4.1 解压 Luna
4.1 解压 Luna
...
@@ -228,7 +228,7 @@ Luna 已改为纯前端,需要 Nginx 来运行访问
...
@@ -228,7 +228,7 @@ Luna 已改为纯前端,需要 Nginx 来运行访问
-p 8081:8080 -v /opt/guacamole/key:/config/guacamole/key \
-p 8081:8080 -v /opt/guacamole/key:/config/guacamole/key \
-e JUMPSERVER_KEY_DIR=/config/guacamole/key \
-e JUMPSERVER_KEY_DIR=/config/guacamole/key \
-e JUMPSERVER_SERVER=http://<填写本机的IP地址>:8080 \
-e JUMPSERVER_SERVER=http://<填写本机的IP地址>:8080 \
registry.jumpserver.org/public/guacamole:
latest
registry.jumpserver.org/public/guacamole:
1.0.0
这里所需要注意的是 guacamole 暴露出来的端口是 8081,若与主机上其他端口冲突请自定义一下。
这里所需要注意的是 guacamole 暴露出来的端口是 8081,若与主机上其他端口冲突请自定义一下。
...
...
utils/2018_04_11_migrate_permissions.sh
View file @
f450accb
...
@@ -3,9 +3,10 @@
...
@@ -3,9 +3,10 @@
python ../apps/manage.py shell
<<
EOF
python ../apps/manage.py shell
<<
EOF
from perms.models import *
from perms.models import *
from assets.models import SystemUser
for old in NodePermission.objects.all():
for old in NodePermission.objects.all():
perm =
asset_perm_model.objects.using(db_alias)
.create(
perm =
AssetPermission.objects
.create(
name="{}-{}-{}".format(
name="{}-{}-{}".format(
old.node.value,
old.node.value,
old.user_group.name,
old.user_group.name,
...
@@ -20,5 +21,10 @@ for old in NodePermission.objects.all():
...
@@ -20,5 +21,10 @@ for old in NodePermission.objects.all():
perm.user_groups.add(old.user_group)
perm.user_groups.add(old.user_group)
perm.nodes.add(old.node)
perm.nodes.add(old.node)
perm.system_users.add(old.system_user)
perm.system_users.add(old.system_user)
for s in SystemUser.objects.all():
nodes = list(s.nodes.all())
s.nodes.set([])
s.nodes.set(nodes)
EOF
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