Unverified Commit d1a2fe14 authored by liuzheng712's avatar liuzheng712

Merge branch 'dev' of github.com:jumpserver/jumpserver into dev

parents 83f83d9b c4afd04c
...@@ -30,3 +30,4 @@ celerybeat.pid ...@@ -30,3 +30,4 @@ celerybeat.pid
django.db django.db
celerybeat-schedule.db celerybeat-schedule.db
data/static data/static
_build/
...@@ -12,7 +12,7 @@ __all__ = ['Node'] ...@@ -12,7 +12,7 @@ __all__ = ['Node']
class Node(models.Model): class Node(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
key = models.CharField(unique=True, max_length=64, verbose_name=_("Key")) # '1:1:1:1' key = models.CharField(unique=True, max_length=64, verbose_name=_("Key")) # '1:1:1:1'
value = models.CharField(max_length=128, unique=True, verbose_name=_("Value")) value = models.CharField(max_length=128, verbose_name=_("Value"))
child_mark = models.IntegerField(default=0) child_mark = models.IntegerField(default=0)
date_create = models.DateTimeField(auto_now_add=True) date_create = models.DateTimeField(auto_now_add=True)
......
...@@ -26,14 +26,14 @@ signer = get_signer() ...@@ -26,14 +26,14 @@ signer = get_signer()
class AssetUser(models.Model): class AssetUser(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
username = models.CharField(max_length=16, verbose_name=_('Username')) username = models.CharField(max_length=128, verbose_name=_('Username'))
_password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password')) _password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
_private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ]) _private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
_public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key')) _public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
comment = models.TextField(blank=True, verbose_name=_('Comment')) comment = models.TextField(blank=True, verbose_name=_('Comment'))
date_created = models.DateTimeField(auto_now_add=True) date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True) date_updated = models.DateTimeField(auto_now=True)
created_by = models.CharField(max_length=32, null=True, verbose_name=_('Created by')) created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by'))
@property @property
def password(self): def password(self):
......
...@@ -91,7 +91,7 @@ def update_assets_hardware_info_util(assets, task_name=None): ...@@ -91,7 +91,7 @@ def update_assets_hardware_info_util(assets, task_name=None):
if task_name is None: if task_name is None:
task_name = _("Update some assets hardware info") task_name = _("Update some assets hardware info")
tasks = const.UPDATE_ASSETS_HARDWARE_TASKS tasks = const.UPDATE_ASSETS_HARDWARE_TASKS
hostname_list = [asset.hostname for asset in assets] hostname_list = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()]
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',
...@@ -120,7 +120,10 @@ def update_assets_hardware_info_period(): ...@@ -120,7 +120,10 @@ def update_assets_hardware_info_period():
""" """
from ops.utils import update_or_create_ansible_task from ops.utils import update_or_create_ansible_task
task_name = _("Update assets hardware info period") task_name = _("Update assets hardware info period")
hostname_list = [asset.hostname for asset in Asset.objects.all()] hostname_list = [
asset.hostname for asset in Asset.objects.all()
if asset.is_active and asset.is_unixlike()
]
tasks = const.UPDATE_ASSETS_HARDWARE_TASKS tasks = const.UPDATE_ASSETS_HARDWARE_TASKS
# Only create, schedule by celery beat # Only create, schedule by celery beat
...@@ -165,7 +168,8 @@ def test_admin_user_connectability_util(admin_user, task_name): ...@@ -165,7 +168,8 @@ def test_admin_user_connectability_util(admin_user, task_name):
from ops.utils import update_or_create_ansible_task from ops.utils import update_or_create_ansible_task
assets = admin_user.get_related_assets() assets = admin_user.get_related_assets()
hosts = [asset.hostname for asset in assets] hosts = [asset.hostname for asset in assets
if asset.is_active and asset.is_unixlike()]
if not hosts: if not hosts:
return return
tasks = const.TEST_ADMIN_USER_CONN_TASKS tasks = const.TEST_ADMIN_USER_CONN_TASKS
...@@ -257,7 +261,7 @@ def test_system_user_connectability_util(system_user, task_name): ...@@ -257,7 +261,7 @@ def test_system_user_connectability_util(system_user, task_name):
""" """
from ops.utils import update_or_create_ansible_task from ops.utils import update_or_create_ansible_task
assets = system_user.assets assets = system_user.assets
hosts = [asset.hostname for asset in assets] hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()]
tasks = const.TEST_SYSTEM_USER_CONN_TASKS tasks = const.TEST_SYSTEM_USER_CONN_TASKS
if not hosts: if not hosts:
logger.info("No hosts, passed") logger.info("No hosts, passed")
...@@ -346,7 +350,7 @@ def push_system_user_util(system_users, assets, task_name): ...@@ -346,7 +350,7 @@ def push_system_user_util(system_users, assets, task_name):
logger.info("Not tasks, passed") logger.info("Not tasks, passed")
return {} return {}
hosts = [asset.hostname for asset in assets] hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()]
if not hosts: if not hosts:
logger.info("Not hosts, passed") logger.info("Not hosts, passed")
return {} return {}
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<div class="col-sm-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>{% trans 'Create system user' %}</h5> <h5>{{ action }}</h5>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
...@@ -81,6 +81,14 @@ ...@@ -81,6 +81,14 @@
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
var auto_generate_key = '#'+'{{ form.auto_generate_key.id_for_label }}'; var auto_generate_key = '#'+'{{ form.auto_generate_key.id_for_label }}';
var protocol_id = '#' + '{{ form.protocol.id_for_label }}';
var password_id = '#' + '{{ form.password.id_for_label }}';
var private_key_id = '#' + '{{ form.private_key_file.id_for_label }}';
var sudo_id = '#' + '{{ form.sudo.id_for_label }}';
var shell_id = '#' + '{{ form.shell.id_for_label }}';
var need_change_field = [auto_generate_key, private_key_id, sudo_id, shell_id] ;
function authFieldsDisplay() { function authFieldsDisplay() {
if ($(auto_generate_key).prop('checked')) { if ($(auto_generate_key).prop('checked')) {
$('.auth-fields').addClass('hidden'); $('.auth-fields').addClass('hidden');
...@@ -88,9 +96,23 @@ ...@@ -88,9 +96,23 @@
$('.auth-fields').removeClass('hidden'); $('.auth-fields').removeClass('hidden');
} }
} }
function protocolChange() {
if ($(protocol_id).attr('value') === 'rdp') {
$.each(need_change_field, function (index, value) {
$(value).addClass('hidden')
});
$(password_id).removeClass('hidden')
} else {
$.each(need_change_field, function (index, value) {
$(value).removeClass('hidden')
});
}
}
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2(); $('.select2').select2();
authFieldsDisplay(); authFieldsDisplay();
protocolChange();
$(auto_generate_key).change(function () { $(auto_generate_key).change(function () {
authFieldsDisplay(); authFieldsDisplay();
}); });
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<div class="col-sm-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>{% trans 'Create admin user' %}</h5> <h5>{{ action }}</h5>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
......
...@@ -2,6 +2,12 @@ ...@@ -2,6 +2,12 @@
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
{% block help_message %}
<div class="alert alert-info help-message">
左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的,右侧是属于该节点下的资产
</div>
{% endblock %}
{% block custom_head_css_js %} {% block custom_head_css_js %}
<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.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> <script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script>
...@@ -224,7 +230,9 @@ function editTreeNode() { ...@@ -224,7 +230,9 @@ function editTreeNode() {
if (!current_node){ if (!current_node){
return return
} }
current_node.name = current_node.value; if (current_node.value) {
current_node.name = current_node.value;
}
zTree.editName(current_node); zTree.editName(current_node);
} }
...@@ -313,38 +321,36 @@ function beforeDrag() { ...@@ -313,38 +321,36 @@ function beforeDrag() {
return true return true
} }
function beforeDrop() { function beforeDrop(treeId, treeNodes, targetNode, moveType) {
return true var treeNodesNames = [];
$.each(treeNodes, function (index, value) {
treeNodesNames.push(value.value);
});
var msg = "你想移动节点: `" + treeNodesNames.join(",") + "` 到 `" + targetNode.value + "` 下吗?";
if (confirm(msg)){
return true
} else {
return false
}
} }
function onDrag(event, treeId, treeNodes) { function onDrag(event, treeId, treeNodes) {
} }
function onDrop(event, treeId, treeNodes, targetNode, moveType) { function onDrop(event, treeId, treeNodes, targetNode, moveType) {
console.log("DROP");
console.log(event);
console.log(treeNodes);
console.log(targetNode);
console.log(moveType);
var treeNodesNames = [];
var treeNodesIds = []; var treeNodesIds = [];
$.each(treeNodes, function (index, value) { $.each(treeNodes, function (index, value) {
treeNodesNames.push(value.value);
treeNodesIds.push(value.id); treeNodesIds.push(value.id);
}); });
var msg = "你想移动节点: `" + treeNodesNames.join(",") + "` 到 `" + targetNode.value + "` 下吗?";
var the_url = "{% url 'api-assets:node-add-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", targetNode.id); var the_url = "{% url 'api-assets:node-add-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", targetNode.id);
var body = {nodes: treeNodesIds}; var body = {nodes: treeNodesIds};
if (confirm(msg)){ APIUpdateAttr({
APIUpdateAttr({ url: the_url,
url: the_url, method: "PUT",
method: "PUT", body: JSON.stringify(body)
body: JSON.stringify(body) })
})
}
} }
function initTree() { function initTree() {
......
...@@ -178,7 +178,7 @@ ...@@ -178,7 +178,7 @@
</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-to-cluster">{% trans 'Confirm' %}</button> <button type="button" class="btn btn-info btn-sm" id="btn-add-to-node">{% trans 'Confirm' %}</button>
</td> </td>
</tr> </tr>
</form> </form>
...@@ -187,7 +187,7 @@ ...@@ -187,7 +187,7 @@
<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.name }}</b></td>
<td> <td>
<button class="btn btn-danger pull-right btn-xs btn-remove-from-cluster" 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>
</tr> </tr>
{% endfor %} {% endfor %}
...@@ -204,27 +204,27 @@ ...@@ -204,27 +204,27 @@
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
function updateSystemUserCluster(clusters) { function updateSystemUserCluster(nodes) {
var the_url = "{% url 'api-assets:system-user-detail' pk=system_user.id %}"; var the_url = "{% url 'api-assets:system-user-detail' pk=system_user.id %}";
var body = { var body = {
cluster: Object.assign([], clusters) nodes: Object.assign([], nodes)
}; };
var success = function(data) { var success = function(data) {
// remove all the selected groups from select > option and rendered ul element; // remove all the selected groups from select > option and rendered ul element;
$('.select2-selection__rendered').empty(); $('.select2-selection__rendered').empty();
$('#cluster_selected').val(''); $('#cluster_selected').val('');
$.map(jumpserver.cluster_selected, function(cluster_name, index) { $.map(jumpserver.nodes_selected, function(cluster_name, index) {
$('#opt_' + index).remove(); $('#opt_' + index).remove();
// change tr html of user groups. // change tr html of user groups.
$('.cluster_edit tbody').append( $('.cluster_edit tbody').append(
'<tr>' + '<tr>' +
'<td><b class="bdg_node" data-gid="' + index + '">' + cluster_name + '</b></td>' + '<td><b class="bdg_node" data-gid="' + index + '">' + cluster_name + '</b></td>' +
'<td><button class="btn btn-danger btn-xs pull-right btn-remove-from-cluster" type="button"><i class="fa fa-minus"></i></button></td>' + '<td><button class="btn btn-danger btn-xs pull-right btn-remove-from-node" type="button"><i class="fa fa-minus"></i></button></td>' +
'</tr>' '</tr>'
) )
}); });
// clear jumpserver.groups_selected // clear jumpserver.groups_selected
jumpserver.cluster_selected = {}; jumpserver.nodes_selected = {};
}; };
APIUpdateAttr({ APIUpdateAttr({
url: the_url, url: the_url,
...@@ -232,16 +232,16 @@ function updateSystemUserCluster(clusters) { ...@@ -232,16 +232,16 @@ function updateSystemUserCluster(clusters) {
success: success success: success
}); });
} }
jumpserver.cluster_selected = {}; jumpserver.nodes_selected = {};
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2() $('.select2').select2()
.on('select2:select', function(evt) { .on('select2:select', function(evt) {
var data = evt.params.data; var data = evt.params.data;
jumpserver.cluster_selected[data.id] = data.text; jumpserver.nodes_selected[data.id] = data.text;
}) })
.on('select2:unselect', function(evt) { .on('select2:unselect', function(evt) {
var data = evt.params.data; var data = evt.params.data;
delete jumpserver.cluster_selected[data.id]; delete jumpserver.nodes_selected[data.id];
}); });
}) })
.on('click', '#btn-auto-push', function () { .on('click', '#btn-auto-push', function () {
...@@ -255,26 +255,26 @@ $(document).ready(function () { ...@@ -255,26 +255,26 @@ $(document).ready(function () {
body: JSON.stringify(body) body: JSON.stringify(body)
}); });
}) })
.on('click', '#btn-add-to-cluster', function() { .on('click', '#btn-add-to-node', function() {
if (Object.keys(jumpserver.cluster_selected).length === 0) { if (Object.keys(jumpserver.nodes_selected).length === 0) {
return false; return false;
} }
var clusters = $('.bdg_node').map(function() { var nodes = $('.bdg_node').map(function() {
return $(this).data('gid'); return $(this).data('gid');
}).get(); }).get();
$.map(jumpserver.cluster_selected, function(value, index) { $.map(jumpserver.nodes_selected, function(value, index) {
clusters.push(index); nodes.push(index);
}); });
updateSystemUserCluster(clusters); updateSystemUserCluster(nodes);
}) })
.on('click', '.btn-remove-from-cluster', function() { .on('click', '.btn-remove-from-node', function() {
var $this = $(this); var $this = $(this);
var $tr = $this.closest('tr'); var $tr = $this.closest('tr');
var $badge = $tr.find('.bdg_node'); var $badge = $tr.find('.bdg_node');
var gid = $badge.data('gid'); var gid = $badge.data('gid');
var cluster_name = $badge.html() || $badge.text(); var node_name = $badge.html() || $badge.text();
$('#groups_selected').append( $('#groups_selected').append(
'<option value="' + gid + '" id="opt_' + gid + '">' + cluster_name + '</option>' '<option value="' + gid + '" id="opt_' + gid + '">' + node_name + '</option>'
); );
$tr.remove(); $tr.remove();
var clusters = $('.bdg_node').map(function () { var clusters = $('.bdg_node').map(function () {
......
...@@ -58,8 +58,7 @@ class UserAssetListView(LoginRequiredMixin, TemplateView): ...@@ -58,8 +58,7 @@ class UserAssetListView(LoginRequiredMixin, TemplateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
'app': _('Assets'), 'action': _('My assets'),
'action': _('Asset list'),
'system_users': SystemUser.objects.all(), 'system_users': SystemUser.objects.all(),
} }
kwargs.update(context) kwargs.update(context)
......
...@@ -97,6 +97,9 @@ class LDAPTestingAPI(APIView): ...@@ -97,6 +97,9 @@ class LDAPTestingAPI(APIView):
class DjangoSettingsAPI(APIView): class DjangoSettingsAPI(APIView):
def get(self, request): def get(self, request):
if not settings.DEBUG:
return Response('Only debug mode support')
configs = {} configs = {}
for i in dir(settings): for i in dir(settings):
if i.isupper(): if i.isupper():
......
...@@ -99,9 +99,8 @@ class DatetimeSearchMixin: ...@@ -99,9 +99,8 @@ class DatetimeSearchMixin:
if date_from_s: if date_from_s:
date_from = timezone.datetime.strptime(date_from_s, self.date_format) date_from = timezone.datetime.strptime(date_from_s, self.date_format)
self.date_from = date_from.replace( tz = timezone.get_current_timezone()
tzinfo=timezone.get_current_timezone() self.date_from = tz.localize(date_from)
)
else: else:
self.date_from = timezone.now() - timezone.timedelta(7) self.date_from = timezone.now() - timezone.timedelta(7)
......
...@@ -73,17 +73,20 @@ def to_html(s): ...@@ -73,17 +73,20 @@ def to_html(s):
@register.filter @register.filter
def time_util_with_seconds(date_from, date_to): def time_util_with_seconds(date_from, date_to):
if date_from and date_to: if not date_from:
delta = date_to - date_from return ''
seconds = delta.seconds if not date_to:
if seconds < 60:
return '{} s'.format(seconds)
elif seconds < 60*60:
return '{} m'.format(seconds//60)
else:
return '{} h'.format(seconds//3600)
else:
return '' return ''
date_to = timezone.now()
delta = date_to - date_from
seconds = delta.seconds
if seconds < 60:
return '{} s'.format(seconds)
elif seconds < 60*60:
return '{} m'.format(seconds//60)
else:
return '{} h'.format(seconds//3600)
@register.filter @register.filter
......
...@@ -8,7 +8,7 @@ msgid "" ...@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n" "Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-02-26 16:54+0800\n" "POT-Creation-Date: 2018-03-07 11:54+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n" "Language-Team: Jumpserver team<ibuler@qq.com>\n"
...@@ -17,12 +17,12 @@ msgstr "" ...@@ -17,12 +17,12 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: assets/api/node.py:54 #: assets/api/node.py:55
msgid "New node {}" msgid "New node {}"
msgstr "新节点 {}" msgstr "新节点 {}"
#: assets/forms/asset.py:23 assets/forms/asset.py:52 assets/forms/user.py:125 #: assets/forms/asset.py:23 assets/forms/asset.py:52 assets/forms/user.py:125
#: assets/models/asset.py:45 assets/models/user.py:221 #: assets/models/asset.py:53 assets/models/user.py:218
#: assets/templates/assets/asset_detail.html:181 #: assets/templates/assets/asset_detail.html:181
#: assets/templates/assets/asset_detail.html:189 #: assets/templates/assets/asset_detail.html:189
#: assets/templates/assets/system_user_detail.html:164 #: assets/templates/assets/system_user_detail.html:164
...@@ -30,16 +30,16 @@ msgid "Nodes" ...@@ -30,16 +30,16 @@ msgid "Nodes"
msgstr "节点管理" msgstr "节点管理"
#: assets/forms/asset.py:26 assets/forms/asset.py:55 assets/forms/asset.py:90 #: assets/forms/asset.py:26 assets/forms/asset.py:55 assets/forms/asset.py:90
#: assets/forms/asset.py:94 assets/models/asset.py:49 #: assets/forms/asset.py:94 assets/models/asset.py:57
#: assets/models/cluster.py:19 assets/models/user.py:190 #: assets/models/cluster.py:19 assets/models/user.py:187
#: assets/templates/assets/asset_detail.html:73 templates/_nav.html:23 #: assets/templates/assets/asset_detail.html:73 templates/_nav.html:24
msgid "Admin user" msgid "Admin user"
msgstr "管理用户" msgstr "管理用户"
#: assets/forms/asset.py:29 assets/forms/asset.py:58 assets/models/asset.py:73 #: assets/forms/asset.py:29 assets/forms/asset.py:58 assets/models/asset.py:81
#: assets/templates/assets/asset_create.html:31 #: assets/templates/assets/asset_create.html:32
#: assets/templates/assets/asset_detail.html:218 #: assets/templates/assets/asset_detail.html:218
#: assets/templates/assets/asset_update.html:36 templates/_nav.html:25 #: assets/templates/assets/asset_update.html:37 templates/_nav.html:26
msgid "Labels" msgid "Labels"
msgstr "标签管理" msgstr "标签管理"
...@@ -54,7 +54,7 @@ msgstr "管理用户是资产上已经存在的特权用户,如 root或者其 ...@@ -54,7 +54,7 @@ msgstr "管理用户是资产上已经存在的特权用户,如 root或者其
msgid "Select assets" msgid "Select assets"
msgstr "选择资产" msgstr "选择资产"
#: assets/forms/asset.py:86 assets/models/asset.py:44 #: assets/forms/asset.py:86 assets/models/asset.py:52
#: assets/templates/assets/admin_user_assets.html:53 #: assets/templates/assets/admin_user_assets.html:53
#: assets/templates/assets/asset_detail.html:69 #: assets/templates/assets/asset_detail.html:69
#: assets/templates/assets/system_user_asset.html:51 #: assets/templates/assets/system_user_asset.html:51
...@@ -62,7 +62,7 @@ msgstr "选择资产" ...@@ -62,7 +62,7 @@ msgstr "选择资产"
msgid "Port" msgid "Port"
msgstr "端口" msgstr "端口"
#: assets/forms/asset.py:106 assets/templates/assets/asset_create.html:35 #: assets/forms/asset.py:106 assets/templates/assets/asset_create.html:36
msgid "Select labels" msgid "Select labels"
msgstr "选择标签" msgstr "选择标签"
...@@ -70,11 +70,11 @@ msgstr "选择标签" ...@@ -70,11 +70,11 @@ msgstr "选择标签"
msgid "Select nodes" msgid "Select nodes"
msgstr "选择节点" msgstr "选择节点"
#: assets/forms/label.py:13 assets/models/asset.py:137 #: assets/forms/label.py:13 assets/models/asset.py:153
#: assets/templates/assets/admin_user_list.html:24 #: assets/templates/assets/admin_user_list.html:24
#: assets/templates/assets/label_list.html:16 #: assets/templates/assets/label_list.html:16
#: assets/templates/assets/system_user_list.html:26 perms/models.py:17 #: assets/templates/assets/system_user_list.html:26 perms/models.py:17
#: terminal/backends/command/models.py:11 terminal/models.py:116 #: terminal/backends/command/models.py:11 terminal/models.py:123
#: terminal/templates/terminal/command_list.html:40 #: terminal/templates/terminal/command_list.html:40
#: terminal/templates/terminal/command_list.html:73 #: terminal/templates/terminal/command_list.html:73
#: terminal/templates/terminal/session_list.html:41 #: terminal/templates/terminal/session_list.html:41
...@@ -84,10 +84,10 @@ msgstr "资产" ...@@ -84,10 +84,10 @@ msgstr "资产"
#: assets/forms/user.py:24 #: assets/forms/user.py:24
msgid "Password or private key passphrase" msgid "Password or private key passphrase"
msgstr "密码或钥密码" msgstr "密码或钥密码"
#: assets/forms/user.py:25 assets/models/user.py:30 common/forms.py:113 #: assets/forms/user.py:25 assets/models/user.py:30 common/forms.py:113
#: users/forms.py:16 users/forms.py:24 users/templates/users/login.html:56 #: users/forms.py:16 users/forms.py:24 users/templates/users/login.html:59
#: users/templates/users/reset_password.html:52 #: users/templates/users/reset_password.html:52
#: users/templates/users/user_create.html:11 #: users/templates/users/user_create.html:11
#: users/templates/users/user_password_update.html:40 #: users/templates/users/user_password_update.html:40
...@@ -116,11 +116,11 @@ msgstr "密码和私钥, 必须输入一个" ...@@ -116,11 +116,11 @@ msgstr "密码和私钥, 必须输入一个"
#: assets/templates/assets/system_user_detail.html:58 #: assets/templates/assets/system_user_detail.html:58
#: assets/templates/assets/system_user_list.html:24 common/models.py:26 #: assets/templates/assets/system_user_list.html:24 common/models.py:26
#: common/templates/common/terminal_setting.html:67 #: common/templates/common/terminal_setting.html:67
#: common/templates/common/terminal_setting.html:88 ops/models.py:31 #: common/templates/common/terminal_setting.html:85 ops/models.py:31
#: ops/templates/ops/task_detail.html:56 ops/templates/ops/task_list.html:34 #: ops/templates/ops/task_detail.html:56 ops/templates/ops/task_list.html:34
#: perms/models.py:14 perms/templates/perms/asset_permission_detail.html:62 #: perms/models.py:14 perms/templates/perms/asset_permission_detail.html:62
#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:15 #: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:16
#: terminal/models.py:141 terminal/templates/terminal/terminal_detail.html:43 #: terminal/models.py:149 terminal/templates/terminal/terminal_detail.html:43
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 #: 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:35 users/templates/users/_select_user_modal.html:13
#: users/templates/users/user_detail.html:63 #: users/templates/users/user_detail.html:63
...@@ -138,9 +138,9 @@ msgstr "名称" ...@@ -138,9 +138,9 @@ msgstr "名称"
#: assets/templates/assets/system_user_detail.html:62 #: assets/templates/assets/system_user_detail.html:62
#: assets/templates/assets/system_user_list.html:25 #: assets/templates/assets/system_user_list.html:25
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:14 #: perms/templates/perms/asset_permission_user.html:55 users/forms.py:14
#: users/models/authentication.py:44 users/models/user.py:34 #: users/models/authentication.py:45 users/models/user.py:34
#: users/templates/users/_select_user_modal.html:14 #: users/templates/users/_select_user_modal.html:14
#: users/templates/users/login.html:53 #: users/templates/users/login.html:56
#: users/templates/users/login_log_list.html:49 #: users/templates/users/login_log_list.html:49
#: users/templates/users/user_detail.html:67 #: users/templates/users/user_detail.html:67
#: users/templates/users/user_list.html:24 #: users/templates/users/user_list.html:24
...@@ -162,10 +162,10 @@ msgid "" ...@@ -162,10 +162,10 @@ msgid ""
"than 2 system user" "than 2 system user"
msgstr "高优先级的系统用户将会作为默认登录用户" msgstr "高优先级的系统用户将会作为默认登录用户"
#: assets/models/asset.py:42 assets/templates/assets/_asset_list_modal.html:21 #: assets/models/asset.py:50 assets/templates/assets/_asset_list_modal.html:21
#: assets/templates/assets/admin_user_assets.html:52 #: assets/templates/assets/admin_user_assets.html:52
#: assets/templates/assets/asset_detail.html:61 #: assets/templates/assets/asset_detail.html:61
#: assets/templates/assets/asset_list.html:81 #: assets/templates/assets/asset_list.html:87
#: assets/templates/assets/system_user_asset.html:50 #: 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:20 common/forms.py:144
#: perms/templates/perms/asset_permission_asset.html:55 #: perms/templates/perms/asset_permission_asset.html:55
...@@ -175,10 +175,10 @@ msgstr "高优先级的系统用户将会作为默认登录用户" ...@@ -175,10 +175,10 @@ msgstr "高优先级的系统用户将会作为默认登录用户"
msgid "IP" msgid "IP"
msgstr "IP" msgstr "IP"
#: assets/models/asset.py:43 assets/templates/assets/_asset_list_modal.html:20 #: assets/models/asset.py:51 assets/templates/assets/_asset_list_modal.html:20
#: assets/templates/assets/admin_user_assets.html:51 #: assets/templates/assets/admin_user_assets.html:51
#: assets/templates/assets/asset_detail.html:57 #: assets/templates/assets/asset_detail.html:57
#: assets/templates/assets/asset_list.html:80 #: assets/templates/assets/asset_list.html:86
#: assets/templates/assets/system_user_asset.html:49 #: 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:19 common/forms.py:143
#: perms/templates/perms/asset_permission_asset.html:54 #: perms/templates/perms/asset_permission_asset.html:54
...@@ -187,77 +187,77 @@ msgstr "IP" ...@@ -187,77 +187,77 @@ msgstr "IP"
msgid "Hostname" msgid "Hostname"
msgstr "主机名" msgstr "主机名"
#: assets/models/asset.py:46 assets/models/label.py:20 #: assets/models/asset.py:54 assets/models/label.py:20
#: assets/templates/assets/asset_detail.html:105 #: assets/templates/assets/asset_detail.html:105
#: perms/templates/perms/asset_permission_list.html:70 #: perms/templates/perms/asset_permission_list.html:70
msgid "Is active" msgid "Is active"
msgstr "激活" msgstr "激活"
#: assets/models/asset.py:52 assets/templates/assets/asset_detail.html:65 #: assets/models/asset.py:60 assets/templates/assets/asset_detail.html:65
msgid "Public IP" msgid "Public IP"
msgstr "公网IP" msgstr "公网IP"
#: assets/models/asset.py:53 assets/templates/assets/asset_detail.html:113 #: assets/models/asset.py:61 assets/templates/assets/asset_detail.html:113
msgid "Asset number" msgid "Asset number"
msgstr "资产编号" msgstr "资产编号"
#: assets/models/asset.py:56 assets/templates/assets/asset_detail.html:77 #: assets/models/asset.py:64 assets/templates/assets/asset_detail.html:77
msgid "Vendor" msgid "Vendor"
msgstr "制造商" msgstr "制造商"
#: assets/models/asset.py:57 assets/templates/assets/asset_detail.html:81 #: assets/models/asset.py:65 assets/templates/assets/asset_detail.html:81
msgid "Model" msgid "Model"
msgstr "型号" msgstr "型号"
#: assets/models/asset.py:58 assets/templates/assets/asset_detail.html:109 #: assets/models/asset.py:66 assets/templates/assets/asset_detail.html:109
msgid "Serial number" msgid "Serial number"
msgstr "序列号" msgstr "序列号"
#: assets/models/asset.py:60 #: assets/models/asset.py:68
msgid "CPU model" msgid "CPU model"
msgstr "CPU型号" msgstr "CPU型号"
#: assets/models/asset.py:61 #: assets/models/asset.py:69
msgid "CPU count" msgid "CPU count"
msgstr "CPU数量" msgstr "CPU数量"
#: assets/models/asset.py:62 #: assets/models/asset.py:70
msgid "CPU cores" msgid "CPU cores"
msgstr "CPU核数" msgstr "CPU核数"
#: assets/models/asset.py:63 assets/templates/assets/asset_detail.html:89 #: assets/models/asset.py:71 assets/templates/assets/asset_detail.html:89
msgid "Memory" msgid "Memory"
msgstr "内存" msgstr "内存"
#: assets/models/asset.py:64 #: assets/models/asset.py:72
msgid "Disk total" msgid "Disk total"
msgstr "硬盘大小" msgstr "硬盘大小"
#: assets/models/asset.py:65 #: assets/models/asset.py:73
msgid "Disk info" msgid "Disk info"
msgstr "硬盘信息" msgstr "硬盘信息"
#: assets/models/asset.py:67 assets/templates/assets/asset_detail.html:97 #: assets/models/asset.py:75 assets/templates/assets/asset_detail.html:97
msgid "Platform" msgid "Platform"
msgstr "系统平台" msgstr "系统平台"
#: assets/models/asset.py:68 assets/templates/assets/asset_detail.html:101 #: assets/models/asset.py:76 assets/templates/assets/asset_detail.html:101
msgid "OS" msgid "OS"
msgstr "操作系统" msgstr "操作系统"
#: assets/models/asset.py:69 #: assets/models/asset.py:77
msgid "OS version" msgid "OS version"
msgstr "系统版本" msgstr "系统版本"
#: assets/models/asset.py:70 #: assets/models/asset.py:78
msgid "OS arch" msgid "OS arch"
msgstr "系统架构" msgstr "系统架构"
#: assets/models/asset.py:71 #: assets/models/asset.py:79
msgid "Hostname raw" msgid "Hostname raw"
msgstr "主机名原始" msgstr "主机名原始"
#: assets/models/asset.py:74 assets/models/cluster.py:28 #: assets/models/asset.py:82 assets/models/cluster.py:28
#: assets/models/group.py:21 assets/models/user.py:36 #: assets/models/group.py:21 assets/models/user.py:36
#: assets/templates/assets/admin_user_detail.html:68 #: assets/templates/assets/admin_user_detail.html:68
#: assets/templates/assets/asset_detail.html:117 #: assets/templates/assets/asset_detail.html:117
...@@ -268,7 +268,7 @@ msgstr "主机名原始" ...@@ -268,7 +268,7 @@ msgstr "主机名原始"
msgid "Created by" msgid "Created by"
msgstr "创建者" msgstr "创建者"
#: assets/models/asset.py:75 assets/models/cluster.py:26 #: assets/models/asset.py:83 assets/models/cluster.py:26
#: assets/models/group.py:22 assets/models/label.py:23 #: assets/models/group.py:22 assets/models/label.py:23
#: assets/templates/assets/admin_user_detail.html:64 #: assets/templates/assets/admin_user_detail.html:64
#: assets/templates/assets/system_user_detail.html:92 #: assets/templates/assets/system_user_detail.html:92
...@@ -280,7 +280,7 @@ msgstr "创建者" ...@@ -280,7 +280,7 @@ msgstr "创建者"
msgid "Date created" msgid "Date created"
msgstr "创建日期" msgstr "创建日期"
#: assets/models/asset.py:76 assets/models/cluster.py:29 #: assets/models/asset.py:84 assets/models/cluster.py:29
#: assets/models/group.py:23 assets/models/label.py:21 assets/models/user.py:33 #: assets/models/group.py:23 assets/models/label.py:21 assets/models/user.py:33
#: assets/templates/assets/admin_user_detail.html:72 #: assets/templates/assets/admin_user_detail.html:72
#: assets/templates/assets/admin_user_list.html:28 #: assets/templates/assets/admin_user_list.html:28
...@@ -288,7 +288,7 @@ msgstr "创建日期" ...@@ -288,7 +288,7 @@ msgstr "创建日期"
#: assets/templates/assets/system_user_detail.html:100 #: assets/templates/assets/system_user_detail.html:100
#: assets/templates/assets/system_user_list.html:30 common/models.py:30 #: assets/templates/assets/system_user_list.html:30 common/models.py:30
#: ops/models.py:37 perms/models.py:24 perms/models.py:81 #: ops/models.py:37 perms/models.py:24 perms/models.py:81
#: perms/templates/perms/asset_permission_detail.html:98 terminal/models.py:25 #: perms/templates/perms/asset_permission_detail.html:98 terminal/models.py:26
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15 #: 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:47 users/templates/users/user_detail.html:111
#: users/templates/users/user_group_detail.html:67 #: users/templates/users/user_group_detail.html:67
...@@ -331,7 +331,7 @@ msgid "Default" ...@@ -331,7 +331,7 @@ msgid "Default"
msgstr "默认" msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:13 #: assets/models/cluster.py:36 assets/models/label.py:13
#: users/models/user.py:261 #: users/models/user.py:266
msgid "System" msgid "System"
msgstr "系统" msgstr "系统"
...@@ -352,13 +352,14 @@ msgid "Default asset group" ...@@ -352,13 +352,14 @@ msgid "Default asset group"
msgstr "默认资产组" msgstr "默认资产组"
#: assets/models/label.py:14 perms/models.py:15 #: assets/models/label.py:14 perms/models.py:15
#: terminal/backends/command/models.py:10 terminal/models.py:115 #: terminal/backends/command/models.py:10 terminal/models.py:122
#: terminal/templates/terminal/command_list.html:32 #: terminal/templates/terminal/command_list.html:32
#: terminal/templates/terminal/command_list.html:72 #: terminal/templates/terminal/command_list.html:72
#: terminal/templates/terminal/session_list.html:33 #: terminal/templates/terminal/session_list.html:33
#: terminal/templates/terminal/session_list.html:71 users/forms.py:190 #: terminal/templates/terminal/session_list.html:71 users/forms.py:190
#: users/models/user.py:30 users/templates/users/user_group_detail.html:78 #: users/models/user.py:30 users/models/user.py:254
#: users/templates/users/user_group_list.html:13 users/views/user.py:330 #: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:13 users/views/user.py:333
msgid "User" msgid "User"
msgstr "用户" msgstr "用户"
...@@ -383,32 +384,32 @@ msgstr "ssh密钥" ...@@ -383,32 +384,32 @@ msgstr "ssh密钥"
msgid "SSH public key" msgid "SSH public key"
msgstr "ssh公钥" msgstr "ssh公钥"
#: assets/models/user.py:222 #: assets/models/user.py:219
msgid "Priority" msgid "Priority"
msgstr "优先级" msgstr "优先级"
#: assets/models/user.py:223 assets/templates/assets/system_user_detail.html:66 #: assets/models/user.py:220 assets/templates/assets/system_user_detail.html:66
msgid "Protocol" msgid "Protocol"
msgstr "协议" msgstr "协议"
#: assets/models/user.py:224 assets/templates/assets/_system_user.html:58 #: assets/models/user.py:221 assets/templates/assets/_system_user.html:58
#: assets/templates/assets/system_user_detail.html:118 #: assets/templates/assets/system_user_detail.html:118
#: assets/templates/assets/system_user_update.html:11 #: assets/templates/assets/system_user_update.html:11
msgid "Auto push" msgid "Auto push"
msgstr "自动推送" msgstr "自动推送"
#: assets/models/user.py:225 assets/templates/assets/system_user_detail.html:70 #: assets/models/user.py:222 assets/templates/assets/system_user_detail.html:70
msgid "Sudo" msgid "Sudo"
msgstr "Sudo" msgstr "Sudo"
#: assets/models/user.py:226 assets/templates/assets/system_user_detail.html:75 #: assets/models/user.py:223 assets/templates/assets/system_user_detail.html:75
msgid "Shell" msgid "Shell"
msgstr "Shell" msgstr "Shell"
#: assets/models/user.py:269 perms/forms.py:25 perms/models.py:19 #: assets/models/user.py:266 perms/forms.py:25 perms/models.py:19
#: perms/models.py:76 perms/templates/perms/asset_permission_detail.html:136 #: perms/models.py:76 perms/templates/perms/asset_permission_detail.html:136
#: perms/templates/perms/asset_permission_list.html:69 templates/_nav.html:24 #: perms/templates/perms/asset_permission_list.html:69 templates/_nav.html:25
#: terminal/backends/command/models.py:12 terminal/models.py:117 #: terminal/backends/command/models.py:12 terminal/models.py:124
#: terminal/templates/terminal/command_list.html:48 #: terminal/templates/terminal/command_list.html:48
#: terminal/templates/terminal/command_list.html:74 #: terminal/templates/terminal/command_list.html:74
#: terminal/templates/terminal/session_list.html:49 #: terminal/templates/terminal/session_list.html:49
...@@ -433,37 +434,37 @@ msgstr "更新资产硬件信息" ...@@ -433,37 +434,37 @@ msgstr "更新资产硬件信息"
msgid "Update assets hardware info period" msgid "Update assets hardware info period"
msgstr "定期更新资产硬件信息" msgstr "定期更新资产硬件信息"
#: assets/tasks.py:191 #: assets/tasks.py:195
msgid "Test admin user connectability period: {}" msgid "Test admin user connectability period: {}"
msgstr "定期测试管理用户可连接性: {}" msgstr "定期测试管理用户可连接性: {}"
#: assets/tasks.py:197 #: assets/tasks.py:201
msgid "Test admin user connectability: {}" msgid "Test admin user connectability: {}"
msgstr "测试管理用户可连接性: {}" msgstr "测试管理用户可连接性: {}"
#: assets/tasks.py:206 #: assets/tasks.py:210
msgid "Test asset connectability" msgid "Test asset connectability"
msgstr "测试资产可连接性" msgstr "测试资产可连接性"
#: assets/tasks.py:277 #: assets/tasks.py:281
msgid "Test system user connectability: {}" msgid "Test system user connectability: {}"
msgstr "测试系统用户可连接性: {}" msgstr "测试系统用户可连接性: {}"
#: assets/tasks.py:288 #: assets/tasks.py:292
msgid "test system user connectability period: {}" msgid "test system user connectability period: {}"
msgstr "测试系统用户可连接性: {}" msgstr "测试系统用户可连接性: {}"
#: assets/tasks.py:361 #: assets/tasks.py:365
msgid "Push system user to node: {} => {}" msgid "Push system user to node: {} => {}"
msgstr "推送系统用户到节点: {}->{}" msgstr "推送系统用户到节点: {}->{}"
#: assets/tasks.py:393 #: assets/tasks.py:397
msgid "Push system users to node: {}" msgid "Push system users to node: {}"
msgstr "推送系统用户到节点: {}" msgstr "推送系统用户到节点: {}"
#: assets/templates/assets/_asset_group_bulk_update_modal.html:5 #: assets/templates/assets/_asset_group_bulk_update_modal.html:5
msgid "Update asset group" msgid "Update asset group"
msgstr "编辑用户组" msgstr "更新用户组"
#: assets/templates/assets/_asset_group_bulk_update_modal.html:8 #: assets/templates/assets/_asset_group_bulk_update_modal.html:8
msgid "Hint: only change the field you want to update." msgid "Hint: only change the field you want to update."
...@@ -474,12 +475,11 @@ msgstr "仅修改你需要更新的字段" ...@@ -474,12 +475,11 @@ msgstr "仅修改你需要更新的字段"
#: assets/views/admin_user.py:29 assets/views/admin_user.py:47 #: 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:63 assets/views/admin_user.py:78
#: assets/views/admin_user.py:102 assets/views/asset.py:48 #: assets/views/admin_user.py:102 assets/views/asset.py:48
#: assets/views/asset.py:61 assets/views/asset.py:95 assets/views/asset.py:155 #: assets/views/asset.py:94 assets/views/asset.py:154 assets/views/asset.py:171
#: assets/views/asset.py:172 assets/views/asset.py:196 assets/views/label.py:26 #: assets/views/asset.py:195 assets/views/label.py:26 assets/views/label.py:42
#: assets/views/label.py:42 assets/views/label.py:58 #: assets/views/label.py:58 assets/views/system_user.py:28
#: assets/views/system_user.py:28 assets/views/system_user.py:44 #: assets/views/system_user.py:44 assets/views/system_user.py:60
#: assets/views/system_user.py:60 assets/views/system_user.py:74 #: assets/views/system_user.py:74 templates/_nav.html:20
#: templates/_nav.html:19
msgid "Assets" msgid "Assets"
msgstr "资产管理" msgstr "资产管理"
...@@ -522,14 +522,14 @@ msgid "If set id, will use this id update asset existed" ...@@ -522,14 +522,14 @@ msgid "If set id, will use this id update asset existed"
msgstr "如果设置了id,则会使用该行信息更新该id的资产" msgstr "如果设置了id,则会使用该行信息更新该id的资产"
#: assets/templates/assets/_asset_list_modal.html:22 #: assets/templates/assets/_asset_list_modal.html:22
#: assets/templates/assets/asset_list.html:82 #: assets/templates/assets/asset_list.html:88
#: assets/templates/assets/user_asset_list.html:22 #: assets/templates/assets/user_asset_list.html:22
msgid "Hardware" msgid "Hardware"
msgstr "硬件" msgstr "硬件"
#: assets/templates/assets/_asset_list_modal.html:23 #: assets/templates/assets/_asset_list_modal.html:23
#: assets/templates/assets/asset_detail.html:143 #: assets/templates/assets/asset_detail.html:143
#: assets/templates/assets/asset_list.html:83 #: assets/templates/assets/asset_list.html:89
#: assets/templates/assets/user_asset_list.html:23 perms/models.py:20 #: assets/templates/assets/user_asset_list.html:23 perms/models.py:20
#: perms/models.py:77 #: perms/models.py:77
#: perms/templates/perms/asset_permission_create_update.html:51 #: perms/templates/perms/asset_permission_create_update.html:51
...@@ -548,7 +548,7 @@ msgstr "激活中" ...@@ -548,7 +548,7 @@ msgstr "激活中"
#: assets/templates/assets/admin_user_assets.html:54 #: assets/templates/assets/admin_user_assets.html:54
#: assets/templates/assets/admin_user_list.html:25 #: assets/templates/assets/admin_user_list.html:25
#: assets/templates/assets/asset_detail.html:357 #: assets/templates/assets/asset_detail.html:357
#: assets/templates/assets/asset_list.html:84 #: assets/templates/assets/asset_list.html:90
#: assets/templates/assets/system_user_asset.html:52 #: assets/templates/assets/system_user_asset.html:52
#: assets/templates/assets/system_user_list.html:27 #: assets/templates/assets/system_user_list.html:27
#: users/templates/users/user_granted_asset.html:47 #: users/templates/users/user_granted_asset.html:47
...@@ -558,13 +558,13 @@ msgstr "可连接" ...@@ -558,13 +558,13 @@ msgstr "可连接"
#: assets/templates/assets/_asset_list_modal.html:25 #: assets/templates/assets/_asset_list_modal.html:25
#: assets/templates/assets/admin_user_list.html:29 #: assets/templates/assets/admin_user_list.html:29
#: assets/templates/assets/asset_list.html:85 #: assets/templates/assets/asset_list.html:91
#: assets/templates/assets/label_list.html:17 #: assets/templates/assets/label_list.html:17
#: assets/templates/assets/system_user_list.html:31 #: assets/templates/assets/system_user_list.html:31
#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:61 #: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:61
#: ops/templates/ops/task_history.html:62 ops/templates/ops/task_list.html:41 #: ops/templates/ops/task_history.html:62 ops/templates/ops/task_list.html:41
#: perms/templates/perms/asset_permission_list.html:72 #: perms/templates/perms/asset_permission_list.html:72
#: terminal/templates/terminal/session_list.html:79 #: terminal/templates/terminal/session_list.html:80
#: terminal/templates/terminal/terminal_list.html:36 #: terminal/templates/terminal/terminal_list.html:36
#: users/templates/users/user_group_list.html:15 #: users/templates/users/user_group_list.html:15
#: users/templates/users/user_list.html:28 #: users/templates/users/user_list.html:28
...@@ -572,25 +572,25 @@ msgid "Action" ...@@ -572,25 +572,25 @@ msgid "Action"
msgstr "动作" msgstr "动作"
#: assets/templates/assets/_asset_list_modal.html:34 #: assets/templates/assets/_asset_list_modal.html:34
#: assets/templates/assets/asset_list.html:94 #: assets/templates/assets/asset_list.html:100
#: users/templates/users/user_list.html:37 #: users/templates/users/user_list.html:37
msgid "Delete selected" msgid "Delete selected"
msgstr "批量删除" msgstr "批量删除"
#: assets/templates/assets/_asset_list_modal.html:35 #: assets/templates/assets/_asset_list_modal.html:35
#: assets/templates/assets/asset_list.html:95 #: assets/templates/assets/asset_list.html:101
#: users/templates/users/user_list.html:38 #: users/templates/users/user_list.html:38
msgid "Update selected" msgid "Update selected"
msgstr "批量更新" msgstr "批量更新"
#: assets/templates/assets/_asset_list_modal.html:36 #: assets/templates/assets/_asset_list_modal.html:36
#: assets/templates/assets/asset_list.html:97 #: assets/templates/assets/asset_list.html:103
#: users/templates/users/user_list.html:39 #: users/templates/users/user_list.html:39
msgid "Deactive selected" msgid "Deactive selected"
msgstr "禁用所选" msgstr "禁用所选"
#: assets/templates/assets/_asset_list_modal.html:37 #: assets/templates/assets/_asset_list_modal.html:37
#: assets/templates/assets/asset_list.html:98 #: assets/templates/assets/asset_list.html:104
#: users/templates/users/user_list.html:40 #: users/templates/users/user_list.html:40
msgid "Active selected" msgid "Active selected"
msgstr "激活所选" msgstr "激活所选"
...@@ -599,16 +599,17 @@ msgstr "激活所选" ...@@ -599,16 +599,17 @@ msgstr "激活所选"
#: assets/templates/assets/_system_user.html:71 #: assets/templates/assets/_system_user.html:71
#: assets/templates/assets/admin_user_create_update.html:46 #: assets/templates/assets/admin_user_create_update.html:46
#: assets/templates/assets/asset_bulk_update.html:24 #: assets/templates/assets/asset_bulk_update.html:24
#: assets/templates/assets/asset_create.html:65 #: assets/templates/assets/asset_create.html:66
#: assets/templates/assets/asset_list.html:102 #: assets/templates/assets/asset_list.html:108
#: assets/templates/assets/asset_update.html:69 #: assets/templates/assets/asset_update.html:70
#: assets/templates/assets/label_create_update.html:17 #: assets/templates/assets/label_create_update.html:17
#: common/templates/common/basic_setting.html:59 #: common/templates/common/basic_setting.html:59
#: common/templates/common/email_setting.html:60 #: common/templates/common/email_setting.html:60
#: common/templates/common/ldap_setting.html:60 #: common/templates/common/ldap_setting.html:60
#: common/templates/common/terminal_setting.html:108 #: common/templates/common/terminal_setting.html:103
#: perms/templates/perms/asset_permission_create_update.html:72 #: perms/templates/perms/asset_permission_create_update.html:72
#: terminal/templates/terminal/terminal_update.html:47 #: terminal/templates/terminal/session_list.html:120
#: terminal/templates/terminal/terminal_update.html:48
#: users/templates/users/_user.html:44 #: users/templates/users/_user.html:44
#: users/templates/users/first_login.html:62 #: users/templates/users/first_login.html:62
#: users/templates/users/forgot_password.html:44 #: users/templates/users/forgot_password.html:44
...@@ -624,7 +625,7 @@ msgstr "提交" ...@@ -624,7 +625,7 @@ msgstr "提交"
#: assets/templates/assets/admin_user_detail.html:24 #: assets/templates/assets/admin_user_detail.html:24
#: assets/templates/assets/admin_user_list.html:84 #: assets/templates/assets/admin_user_list.html:84
#: assets/templates/assets/asset_detail.html:24 #: assets/templates/assets/asset_detail.html:24
#: assets/templates/assets/asset_list.html:160 #: assets/templates/assets/asset_list.html:166
#: assets/templates/assets/label_list.html:38 #: assets/templates/assets/label_list.html:38
#: assets/templates/assets/system_user_detail.html:26 #: assets/templates/assets/system_user_detail.html:26
#: assets/templates/assets/system_user_list.html:85 #: assets/templates/assets/system_user_list.html:85
...@@ -643,7 +644,7 @@ msgstr "更新" ...@@ -643,7 +644,7 @@ msgstr "更新"
#: assets/templates/assets/admin_user_detail.html:28 #: assets/templates/assets/admin_user_detail.html:28
#: assets/templates/assets/admin_user_list.html:85 #: assets/templates/assets/admin_user_list.html:85
#: assets/templates/assets/asset_detail.html:28 #: assets/templates/assets/asset_detail.html:28
#: assets/templates/assets/asset_list.html:161 #: assets/templates/assets/asset_list.html:167
#: assets/templates/assets/label_list.html:39 #: assets/templates/assets/label_list.html:39
#: assets/templates/assets/system_user_detail.html:30 #: assets/templates/assets/system_user_detail.html:30
#: assets/templates/assets/system_user_list.html:86 #: assets/templates/assets/system_user_list.html:86
...@@ -659,12 +660,6 @@ msgstr "更新" ...@@ -659,12 +660,6 @@ msgstr "更新"
msgid "Delete" msgid "Delete"
msgstr "删除" msgstr "删除"
#: assets/templates/assets/_system_user.html:16
#: assets/templates/assets/system_user_list.html:16
#: assets/views/system_user.py:45
msgid "Create system user"
msgstr "创建系统用户"
#: assets/templates/assets/_system_user.html:37 #: assets/templates/assets/_system_user.html:37
#: assets/templates/assets/asset_create.html:16 #: assets/templates/assets/asset_create.html:16
#: assets/templates/assets/asset_update.html:21 #: assets/templates/assets/asset_update.html:21
...@@ -673,8 +668,8 @@ msgid "Basic" ...@@ -673,8 +668,8 @@ msgid "Basic"
msgstr "基本" msgstr "基本"
#: assets/templates/assets/_system_user.html:44 #: assets/templates/assets/_system_user.html:44
#: assets/templates/assets/asset_create.html:23 #: assets/templates/assets/asset_create.html:24
#: assets/templates/assets/asset_update.html:28 #: assets/templates/assets/asset_update.html:29
#: assets/templates/assets/system_user_update.html:7 #: assets/templates/assets/system_user_update.html:7
#: users/templates/users/user_create.html:9 #: users/templates/users/user_create.html:9
#: users/templates/users/user_update.html:6 #: users/templates/users/user_update.html:6
...@@ -683,28 +678,28 @@ msgstr "认证" ...@@ -683,28 +678,28 @@ msgstr "认证"
#: assets/templates/assets/_system_user.html:47 #: assets/templates/assets/_system_user.html:47
msgid "Auto generate key" msgid "Auto generate key"
msgstr "自动生成钥" msgstr "自动生成钥"
#: assets/templates/assets/_system_user.html:64 #: assets/templates/assets/_system_user.html:64
#: assets/templates/assets/asset_create.html:57 #: assets/templates/assets/asset_create.html:58
#: assets/templates/assets/asset_update.html:61 #: assets/templates/assets/asset_update.html:62
#: perms/templates/perms/asset_permission_create_update.html:49 #: perms/templates/perms/asset_permission_create_update.html:49
#: terminal/templates/terminal/terminal_update.html:41 #: terminal/templates/terminal/terminal_update.html:42
msgid "Other" msgid "Other"
msgstr "其它" msgstr "其它"
#: assets/templates/assets/_system_user.html:70 #: assets/templates/assets/_system_user.html:70
#: assets/templates/assets/admin_user_create_update.html:45 #: assets/templates/assets/admin_user_create_update.html:45
#: assets/templates/assets/asset_bulk_update.html:23 #: assets/templates/assets/asset_bulk_update.html:23
#: assets/templates/assets/asset_create.html:64 #: assets/templates/assets/asset_create.html:65
#: assets/templates/assets/asset_update.html:68 #: assets/templates/assets/asset_update.html:69
#: assets/templates/assets/label_create_update.html:16 #: assets/templates/assets/label_create_update.html:16
#: common/templates/common/basic_setting.html:58 #: common/templates/common/basic_setting.html:58
#: common/templates/common/email_setting.html:59 #: common/templates/common/email_setting.html:59
#: common/templates/common/ldap_setting.html:59 #: common/templates/common/ldap_setting.html:59
#: common/templates/common/terminal_setting.html:106 #: common/templates/common/terminal_setting.html:101
#: perms/templates/perms/asset_permission_create_update.html:71 #: perms/templates/perms/asset_permission_create_update.html:71
#: terminal/templates/terminal/terminal_update.html:46 #: terminal/templates/terminal/terminal_update.html:47
#: users/templates/users/_user.html:43 #: users/templates/users/_user.html:43
#: users/templates/users/user_bulk_update.html:23 #: users/templates/users/user_bulk_update.html:23
#: users/templates/users/user_password_update.html:58 #: users/templates/users/user_password_update.html:58
...@@ -761,19 +756,13 @@ msgstr "测试" ...@@ -761,19 +756,13 @@ msgstr "测试"
msgid "Task has been send, seen left asset status" msgid "Task has been send, seen left asset status"
msgstr "任务已下发,查看左侧资产状态" msgstr "任务已下发,查看左侧资产状态"
#: assets/templates/assets/admin_user_create_update.html:16
#: assets/templates/assets/admin_user_list.html:14
#: assets/views/admin_user.py:48
msgid "Create admin user"
msgstr "创建管理用户"
#: assets/templates/assets/admin_user_detail.html:83 #: assets/templates/assets/admin_user_detail.html:83
msgid "Replace node assets admin user with this" msgid "Replace node assets admin user with this"
msgstr "替换资产的管理员" msgstr "替换资产的管理员"
#: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:198 #: assets/templates/assets/asset_detail.html:198
#: assets/templates/assets/asset_list.html:482 #: assets/templates/assets/asset_list.html:541
#: assets/templates/assets/system_user_detail.html:181 #: assets/templates/assets/system_user_detail.html:181
#: assets/templates/assets/system_user_list.html:135 templates/_modal.html:16 #: assets/templates/assets/system_user_list.html:135 templates/_modal.html:16
#: terminal/templates/terminal/session_detail.html:108 #: terminal/templates/terminal/session_detail.html:108
...@@ -787,6 +776,11 @@ msgstr "替换资产的管理员" ...@@ -787,6 +776,11 @@ msgstr "替换资产的管理员"
msgid "Confirm" msgid "Confirm"
msgstr "确认" msgstr "确认"
#: assets/templates/assets/admin_user_list.html:14
#: assets/views/admin_user.py:48
msgid "Create admin user"
msgstr "创建管理用户"
#: assets/templates/assets/admin_user_list.html:26 #: assets/templates/assets/admin_user_list.html:26
#: assets/templates/assets/system_user_list.html:28 #: assets/templates/assets/system_user_list.html:28
msgid "Unreachable" msgid "Unreachable"
...@@ -799,20 +793,20 @@ msgstr "不可达" ...@@ -799,20 +793,20 @@ msgstr "不可达"
msgid "Ratio" msgid "Ratio"
msgstr "比例" msgstr "比例"
#: assets/templates/assets/asset_create.html:27 #: assets/templates/assets/asset_create.html:28
#: assets/templates/assets/asset_update.html:32 perms/models.py:74 #: assets/templates/assets/asset_update.html:33 perms/models.py:74
#: perms/templates/perms/asset_permission_create_update.html:40 #: perms/templates/perms/asset_permission_create_update.html:40
#: perms/templates/perms/asset_permission_list.html:67 #: perms/templates/perms/asset_permission_list.html:67
msgid "Node" msgid "Node"
msgstr "节点" msgstr "节点"
#: assets/templates/assets/asset_create.html:33 #: assets/templates/assets/asset_create.html:34
#: assets/templates/assets/asset_list.html:69 #: assets/templates/assets/asset_list.html:75
#: assets/templates/assets/asset_update.html:38 #: assets/templates/assets/asset_update.html:39
msgid "Label" msgid "Label"
msgstr "标签" msgstr "标签"
#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:197 #: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:196
msgid "Asset detail" msgid "Asset detail"
msgstr "资产详情" msgstr "资产详情"
...@@ -850,50 +844,50 @@ msgstr "刷新" ...@@ -850,50 +844,50 @@ msgstr "刷新"
msgid "Update successfully!" msgid "Update successfully!"
msgstr "更新成功" msgstr "更新成功"
#: assets/templates/assets/asset_list.html:57 #: assets/templates/assets/asset_list.html:63
#: assets/templates/assets/asset_list.html:114 assets/views/asset.py:96 #: assets/templates/assets/asset_list.html:120 assets/views/asset.py:95
msgid "Create asset" msgid "Create asset"
msgstr "创建资产" msgstr "创建资产"
#: assets/templates/assets/asset_list.html:61 #: assets/templates/assets/asset_list.html:67
#: users/templates/users/user_list.html:7 #: users/templates/users/user_list.html:7
msgid "Import" msgid "Import"
msgstr "导入" msgstr "导入"
#: assets/templates/assets/asset_list.html:64 #: assets/templates/assets/asset_list.html:70
#: users/templates/users/user_list.html:10 #: users/templates/users/user_list.html:10
msgid "Export" msgid "Export"
msgstr "导出" msgstr "导出"
#: assets/templates/assets/asset_list.html:96 #: assets/templates/assets/asset_list.html:102
msgid "Remove from this node" msgid "Remove from this node"
msgstr "从节点移除" msgstr "从节点移除"
#: assets/templates/assets/asset_list.html:115 #: assets/templates/assets/asset_list.html:121
msgid "Add asset" msgid "Add asset"
msgstr "添加资产到节点" msgstr "添加资产到节点"
#: assets/templates/assets/asset_list.html:117 #: assets/templates/assets/asset_list.html:123
msgid "Add node" msgid "Add node"
msgstr "新建节点" msgstr "新建节点"
#: assets/templates/assets/asset_list.html:118 #: assets/templates/assets/asset_list.html:124
msgid "Rename node" msgid "Rename node"
msgstr "重命名节点" msgstr "重命名节点"
#: assets/templates/assets/asset_list.html:120 #: assets/templates/assets/asset_list.html:126
msgid "Delete node" msgid "Delete node"
msgstr "删除节点" msgstr "删除节点"
#: assets/templates/assets/asset_list.html:195 #: assets/templates/assets/asset_list.html:201
msgid "Create node failed" msgid "Create node failed"
msgstr "创建节点失败" msgstr "创建节点失败"
#: assets/templates/assets/asset_list.html:208 #: assets/templates/assets/asset_list.html:214
msgid "Have child node, cancel" msgid "Have child node, cancel"
msgstr "存在子节点,不能删除" msgstr "存在子节点,不能删除"
#: assets/templates/assets/asset_list.html:477 #: assets/templates/assets/asset_list.html:536
#: assets/templates/assets/system_user_list.html:130 #: assets/templates/assets/system_user_list.html:130
#: users/templates/users/user_detail.html:334 #: users/templates/users/user_detail.html:334
#: users/templates/users/user_detail.html:359 #: users/templates/users/user_detail.html:359
...@@ -902,24 +896,24 @@ msgstr "存在子节点,不能删除" ...@@ -902,24 +896,24 @@ msgstr "存在子节点,不能删除"
msgid "Are you sure?" msgid "Are you sure?"
msgstr "你确认吗?" msgstr "你确认吗?"
#: assets/templates/assets/asset_list.html:478 #: assets/templates/assets/asset_list.html:537
msgid "This will delete the selected assets !!!" msgid "This will delete the selected assets !!!"
msgstr "删除选择资产" msgstr "删除选择资产"
#: assets/templates/assets/asset_list.html:486 #: assets/templates/assets/asset_list.html:545
msgid "Asset Deleted." msgid "Asset Deleted."
msgstr "已被删除" msgstr "已被删除"
#: assets/templates/assets/asset_list.html:487 #: assets/templates/assets/asset_list.html:546
#: assets/templates/assets/asset_list.html:492 #: assets/templates/assets/asset_list.html:551
msgid "Asset Delete" msgid "Asset Delete"
msgstr "删除" msgstr "删除"
#: assets/templates/assets/asset_list.html:491 #: assets/templates/assets/asset_list.html:550
msgid "Asset Deleting failed." msgid "Asset Deleting failed."
msgstr "删除失败" msgstr "删除失败"
#: assets/templates/assets/asset_update.html:57 #: assets/templates/assets/asset_update.html:58
msgid "Configuration" msgid "Configuration"
msgstr "配置" msgstr "配置"
...@@ -978,6 +972,11 @@ msgstr "Uid" ...@@ -978,6 +972,11 @@ msgstr "Uid"
msgid "Add to node" msgid "Add to node"
msgstr "添加到节点" msgstr "添加到节点"
#: assets/templates/assets/system_user_list.html:16
#: assets/views/system_user.py:45
msgid "Create system user"
msgstr "创建系统用户"
#: assets/templates/assets/system_user_list.html:131 #: assets/templates/assets/system_user_list.html:131
msgid "This will delete the selected System Users !!!" msgid "This will delete the selected System Users !!!"
msgstr "删除选择系统用户" msgstr "删除选择系统用户"
...@@ -1011,17 +1010,21 @@ msgstr "更新管理用户" ...@@ -1011,17 +1010,21 @@ msgstr "更新管理用户"
msgid "Admin user detail" msgid "Admin user detail"
msgstr "管理用户详情" msgstr "管理用户详情"
#: assets/views/asset.py:49 assets/views/asset.py:62 templates/_nav.html:22 #: assets/views/asset.py:49 templates/_nav.html:23
msgid "Asset list" msgid "Asset list"
msgstr "资产列表" msgstr "资产列表"
#: assets/views/asset.py:156 #: assets/views/asset.py:61 templates/_nav_user.html:4
msgid "My assets"
msgstr "我的资产"
#: assets/views/asset.py:155
msgid "Bulk update asset" msgid "Bulk update asset"
msgstr "批量更新资产" msgstr "批量更新资产"
#: assets/views/asset.py:173 #: assets/views/asset.py:172
msgid "Update asset" msgid "Update asset"
msgstr "编辑资产" msgstr "更新资产"
#: assets/views/asset.py:296 #: assets/views/asset.py:296
msgid "already exists" msgid "already exists"
...@@ -1033,7 +1036,7 @@ msgstr "标签列表" ...@@ -1033,7 +1036,7 @@ msgstr "标签列表"
#: assets/views/label.py:59 #: assets/views/label.py:59
msgid "Update label" msgid "Update label"
msgstr "编辑标签" msgstr "更新标签"
#: assets/views/system_user.py:29 #: assets/views/system_user.py:29
msgid "System user list" msgid "System user list"
...@@ -1192,10 +1195,10 @@ msgstr "密码认证" ...@@ -1192,10 +1195,10 @@ msgstr "密码认证"
#: common/forms.py:156 #: common/forms.py:156
msgid "Public key auth" msgid "Public key auth"
msgstr "钥认证" msgstr "钥认证"
#: common/forms.py:159 common/templates/common/terminal_setting.html:63 #: common/forms.py:159 common/templates/common/terminal_setting.html:63
#: terminal/forms.py:21 terminal/models.py:19 #: terminal/forms.py:30 terminal/models.py:20
msgid "Command storage" msgid "Command storage"
msgstr "命令存储" msgstr "命令存储"
...@@ -1205,8 +1208,8 @@ msgid "" ...@@ -1205,8 +1208,8 @@ msgid ""
"other storage and some terminal using" "other storage and some terminal using"
msgstr "设置终端命令存储,default是默认用的存储方式" msgstr "设置终端命令存储,default是默认用的存储方式"
#: common/forms.py:165 common/templates/common/terminal_setting.html:84 #: common/forms.py:165 common/templates/common/terminal_setting.html:81
#: terminal/models.py:20 #: terminal/forms.py:34 terminal/models.py:21
msgid "Replay storage" msgid "Replay storage"
msgstr "录像存储" msgstr "录像存储"
...@@ -1263,19 +1266,13 @@ msgid "Test connection" ...@@ -1263,19 +1266,13 @@ msgid "Test connection"
msgstr "测试连接" msgstr "测试连接"
#: common/templates/common/terminal_setting.html:68 #: common/templates/common/terminal_setting.html:68
#: common/templates/common/terminal_setting.html:89 #: common/templates/common/terminal_setting.html:86
#: users/templates/users/login_log_list.html:50 #: users/templates/users/login_log_list.html:50
msgid "Type" msgid "Type"
msgstr "类型" msgstr "类型"
#: common/templates/common/terminal_setting.html:90
#: users/templates/users/reset_password.html:57
#: users/templates/users/user_profile.html:20
msgid "Setting"
msgstr "设置"
#: common/views.py:20 common/views.py:46 common/views.py:72 common/views.py:102 #: common/views.py:20 common/views.py:46 common/views.py:72 common/views.py:102
#: templates/_nav.html:66 #: templates/_nav.html:72
msgid "Settings" msgid "Settings"
msgstr "系统设置" msgstr "系统设置"
...@@ -1430,7 +1427,7 @@ msgstr "执行历史" ...@@ -1430,7 +1427,7 @@ msgstr "执行历史"
#: ops/templates/ops/adhoc_history.html:52 #: ops/templates/ops/adhoc_history.html:52
#: ops/templates/ops/adhoc_history_detail.html:58 #: ops/templates/ops/adhoc_history_detail.html:58
#: ops/templates/ops/task_history.html:55 terminal/models.py:124 #: ops/templates/ops/task_history.html:55 terminal/models.py:132
#: terminal/templates/terminal/session_list.html:77 #: terminal/templates/terminal/session_list.html:77
msgid "Date start" msgid "Date start"
msgstr "开始日期" msgstr "开始日期"
...@@ -1542,7 +1539,7 @@ msgstr "任务开始: " ...@@ -1542,7 +1539,7 @@ msgstr "任务开始: "
msgid "Ops" msgid "Ops"
msgstr "作业中心" msgstr "作业中心"
#: ops/views.py:37 templates/_nav.html:52 #: ops/views.py:37 templates/_nav.html:58
msgid "Task list" msgid "Task list"
msgstr "任务列表" msgstr "任务列表"
...@@ -1551,8 +1548,9 @@ msgid "Task run history" ...@@ -1551,8 +1548,9 @@ msgid "Task run history"
msgstr "执行历史" msgstr "执行历史"
#: perms/forms.py:22 perms/models.py:16 perms/models.py:75 #: perms/forms.py:22 perms/models.py:16 perms/models.py:75
#: perms/templates/perms/asset_permission_list.html:68 templates/_nav.html:13 #: perms/templates/perms/asset_permission_list.html:68 templates/_nav.html:14
#: users/models/user.py:37 users/templates/users/_select_user_modal.html:16 #: users/models/group.py:25 users/models/user.py:37
#: users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:179 #: users/templates/users/user_detail.html:179
#: users/templates/users/user_list.html:26 #: users/templates/users/user_list.html:26
msgid "User group" msgid "User group"
...@@ -1566,7 +1564,7 @@ msgstr "用户组" ...@@ -1566,7 +1564,7 @@ msgstr "用户组"
msgid "Date expired" msgid "Date expired"
msgstr "失效日期" msgstr "失效日期"
#: perms/models.py:88 templates/_nav.html:32 #: perms/models.py:88 templates/_nav.html:33
msgid "Asset permission" msgid "Asset permission"
msgstr "资产授权" msgstr "资产授权"
...@@ -1607,10 +1605,6 @@ msgstr "选择资产组" ...@@ -1607,10 +1605,6 @@ msgstr "选择资产组"
msgid "Join" msgid "Join"
msgstr "加入" msgstr "加入"
#: perms/templates/perms/asset_permission_create_update.html:17
msgid "Create asset permission "
msgstr "创建资产权限"
#: perms/templates/perms/asset_permission_detail.html:66 #: perms/templates/perms/asset_permission_detail.html:66
msgid "User count" msgid "User count"
msgstr "用户数量" msgstr "用户数量"
...@@ -1660,7 +1654,7 @@ msgstr "添加用户组" ...@@ -1660,7 +1654,7 @@ msgstr "添加用户组"
msgid "Select user groups" msgid "Select user groups"
msgstr "选择用户组" msgstr "选择用户组"
#: perms/views.py:23 perms/views.py:47 perms/views.py:67 templates/_nav.html:29 #: perms/views.py:23 perms/views.py:47 perms/views.py:67 templates/_nav.html:30
msgid "Perms" msgid "Perms"
msgstr "权限管理" msgstr "权限管理"
...@@ -1677,37 +1671,41 @@ msgid "Update asset permission" ...@@ -1677,37 +1671,41 @@ msgid "Update asset permission"
msgstr "更新资产授权" msgstr "更新资产授权"
#: templates/_header_bar.html:18 #: templates/_header_bar.html:18
msgid "Help" msgid "Supports"
msgstr "帮助" msgstr "商业支持"
#: templates/_header_bar.html:23
msgid "Docs"
msgstr "文档"
#: templates/_header_bar.html:32 templates/_nav_user.html:9 #: templates/_header_bar.html:37 templates/_nav_user.html:9
#: users/templates/users/_user.html:36 #: users/templates/users/_user.html:36
#: users/templates/users/user_password_update.html:37 #: users/templates/users/user_password_update.html:37
#: users/templates/users/user_profile.html:17 #: users/templates/users/user_profile.html:17
#: users/templates/users/user_profile_update.html:37 #: users/templates/users/user_profile_update.html:37
#: users/templates/users/user_profile_update.html:57 #: users/templates/users/user_profile_update.html:57
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:313 #: users/templates/users/user_pubkey_update.html:37 users/views/user.py:316
msgid "Profile" msgid "Profile"
msgstr "个人信息" msgstr "个人信息"
#: templates/_header_bar.html:36 #: templates/_header_bar.html:40
msgid "Admin page" msgid "Admin page"
msgstr "管理页面" msgstr "管理页面"
#: templates/_header_bar.html:38 #: templates/_header_bar.html:42
msgid "User page" msgid "User page"
msgstr "用户页面" msgstr "用户页面"
#: templates/_header_bar.html:41 #: templates/_header_bar.html:45
msgid "Logout" msgid "Logout"
msgstr "注销登录" msgstr "注销登录"
#: templates/_header_bar.html:45 users/templates/users/login.html:42 #: templates/_header_bar.html:49 users/templates/users/login.html:44
#: users/templates/users/login.html:61 #: users/templates/users/login.html:64
msgid "Login" msgid "Login"
msgstr "登录" msgstr "登录"
#: templates/_header_bar.html:58 templates/_nav.html:4 #: templates/_header_bar.html:62 templates/_nav.html:4
msgid "Dashboard" msgid "Dashboard"
msgstr "仪表盘" msgstr "仪表盘"
...@@ -1733,7 +1731,7 @@ msgid "" ...@@ -1733,7 +1731,7 @@ msgid ""
" " " "
msgstr "" msgstr ""
"\n" "\n"
" 您的ssh钥没有设置或已失效,请点击 <a href=" " 您的ssh钥没有设置或已失效,请点击 <a href="
"\"%(user_pubkey_update)s\"> 链接 </a> 更新\n" "\"%(user_pubkey_update)s\"> 链接 </a> 更新\n"
" " " "
...@@ -1741,58 +1739,54 @@ msgstr "" ...@@ -1741,58 +1739,54 @@ msgstr ""
msgid "Close" msgid "Close"
msgstr "关闭" msgstr "关闭"
#: templates/_nav.html:9 users/views/group.py:28 users/views/group.py:44 #: 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/login.py:200 #: users/views/group.py:62 users/views/group.py:79 users/views/group.py:95
#: users/views/login.py:249 users/views/user.py:57 users/views/user.py:72 #: users/views/login.py:209 users/views/login.py:258 users/views/user.py:59
#: users/views/user.py:91 users/views/user.py:147 users/views/user.py:300 #: users/views/user.py:74 users/views/user.py:93 users/views/user.py:149
#: users/views/user.py:312 users/views/user.py:348 users/views/user.py:370 #: users/views/user.py:304 users/views/user.py:351 users/views/user.py:373
msgid "Users" msgid "Users"
msgstr "用户管理" msgstr "用户管理"
#: templates/_nav.html:12 users/views/user.py:58 #: templates/_nav.html:13 users/views/user.py:60
msgid "User list" msgid "User list"
msgstr "用户列表" msgstr "用户列表"
#: templates/_nav.html:14 #: templates/_nav.html:15
msgid "Login logs" msgid "Login logs"
msgstr "登录日志" msgstr "登录日志"
#: templates/_nav.html:38 #: templates/_nav.html:39
msgid "Sessions" msgid "Sessions"
msgstr "会话管理" msgstr "会话管理"
#: templates/_nav.html:41 #: templates/_nav.html:42
msgid "Session online" msgid "Session online"
msgstr "在线会话" msgstr "在线会话"
#: templates/_nav.html:42 #: templates/_nav.html:43
msgid "Session offline" msgid "Session offline"
msgstr "历史会话" msgstr "历史会话"
#: templates/_nav.html:43 #: templates/_nav.html:44
msgid "Commands" msgid "Commands"
msgstr "命令记录" msgstr "命令记录"
#: templates/_nav.html:44 terminal/templates/terminal/session_list.html:75 #: templates/_nav.html:47 templates/_nav_user.html:14
msgid "Web terminal"
msgstr "Web终端"
#: templates/_nav.html:50 terminal/templates/terminal/session_list.html:75
#: terminal/views/command.py:47 terminal/views/session.py:75 #: terminal/views/command.py:47 terminal/views/session.py:75
#: terminal/views/session.py:92 terminal/views/session.py:114 #: terminal/views/session.py:93 terminal/views/session.py:115
#: terminal/views/terminal.py:31 terminal/views/terminal.py:46 #: terminal/views/terminal.py:31 terminal/views/terminal.py:46
#: terminal/views/terminal.py:58 #: terminal/views/terminal.py:58
msgid "Terminal" msgid "Terminal"
msgstr "终端管理" msgstr "终端管理"
#: templates/_nav.html:49 #: templates/_nav.html:55
msgid "Job Center" msgid "Job Center"
msgstr "作业中心" msgstr "作业中心"
#: templates/_nav_user.html:4
msgid "My assets"
msgstr "我的资产"
#: templates/_nav_user.html:14
msgid "Web terminal"
msgstr "Web终端"
#: templates/captcha/image.html:3 #: templates/captcha/image.html:3
msgid "Play CAPTCHA as audio file" msgid "Play CAPTCHA as audio file"
msgstr "语言播放验证码" msgstr "语言播放验证码"
...@@ -1819,71 +1813,75 @@ msgstr "输出" ...@@ -1819,71 +1813,75 @@ msgstr "输出"
msgid "Session" msgid "Session"
msgstr "会话" msgstr "会话"
#: terminal/forms.py:27 #: terminal/forms.py:44
msgid "Coco ssh listen port" msgid "Coco ssh listen port"
msgstr "SSH 监听端口" msgstr "SSH 监听端口"
#: terminal/forms.py:28 #: terminal/forms.py:45
msgid "Coco http/ws listen port" msgid "Coco http/ws listen port"
msgstr "Http/Websocket 监听端口" msgstr "Http/Websocket 监听端口"
#: terminal/models.py:16 #: terminal/models.py:17
msgid "Remote Address" msgid "Remote Address"
msgstr "远端地址" msgstr "远端地址"
#: terminal/models.py:17 #: terminal/models.py:18
msgid "SSH Port" msgid "SSH Port"
msgstr "SSH端口" msgstr "SSH端口"
#: terminal/models.py:18 #: terminal/models.py:19
msgid "HTTP Port" msgid "HTTP Port"
msgstr "HTTP端口" msgstr "HTTP端口"
#: terminal/models.py:91 #: terminal/models.py:98
msgid "Session Online" msgid "Session Online"
msgstr "在线会话" msgstr "在线会话"
#: terminal/models.py:92 #: terminal/models.py:99
msgid "CPU Usage" msgid "CPU Usage"
msgstr "CPU使用" msgstr "CPU使用"
#: terminal/models.py:93 #: terminal/models.py:100
msgid "Memory Used" msgid "Memory Used"
msgstr "内存使用" msgstr "内存使用"
#: terminal/models.py:94 #: terminal/models.py:101
msgid "Connections" msgid "Connections"
msgstr "连接数" msgstr "连接数"
#: terminal/models.py:95 #: terminal/models.py:102
msgid "Threads" msgid "Threads"
msgstr "线程数" msgstr "线程数"
#: terminal/models.py:96 #: terminal/models.py:103
msgid "Boot Time" msgid "Boot Time"
msgstr "运行时间" msgstr "运行时间"
#: terminal/models.py:119 terminal/templates/terminal/session_list.html:74 #: terminal/models.py:126 terminal/templates/terminal/session_list.html:74
#: terminal/templates/terminal/terminal_detail.html:47 #: terminal/templates/terminal/terminal_detail.html:47
msgid "Remote addr" msgid "Remote addr"
msgstr "远端地址" msgstr "远端地址"
#: terminal/models.py:121 terminal/templates/terminal/session_list.html:100 #: terminal/models.py:128 terminal/templates/terminal/session_list.html:102
msgid "Replay" msgid "Replay"
msgstr "回放" msgstr "回放"
#: terminal/models.py:122 terminal/templates/terminal/command_list.html:55 #: terminal/models.py:129 terminal/templates/terminal/command_list.html:55
#: terminal/templates/terminal/command_list.html:71 #: terminal/templates/terminal/command_list.html:71
#: terminal/templates/terminal/session_detail.html:48 #: terminal/templates/terminal/session_detail.html:48
#: terminal/templates/terminal/session_list.html:76 #: terminal/templates/terminal/session_list.html:76
msgid "Command" msgid "Command"
msgstr "命令" msgstr "命令"
#: terminal/models.py:125 #: terminal/models.py:131
msgid "Date last active"
msgstr "最后活跃日期"
#: terminal/models.py:133
msgid "Date end" msgid "Date end"
msgstr "结束日期" msgstr "结束日期"
#: terminal/models.py:142 #: terminal/models.py:150
msgid "Args" msgid "Args"
msgstr "参数" msgstr "参数"
...@@ -1892,7 +1890,7 @@ msgid "Goto" ...@@ -1892,7 +1890,7 @@ msgid "Goto"
msgstr "转到" msgstr "转到"
#: terminal/templates/terminal/session_detail.html:17 #: terminal/templates/terminal/session_detail.html:17
#: terminal/views/session.py:115 #: terminal/views/session.py:116
msgid "Session detail" msgid "Session detail"
msgstr "会话详情" msgstr "会话详情"
...@@ -1922,19 +1920,23 @@ msgstr "监控" ...@@ -1922,19 +1920,23 @@ msgstr "监控"
msgid "Terminate session" msgid "Terminate session"
msgstr "终止会话" msgstr "终止会话"
#: terminal/templates/terminal/session_list.html:78 #: terminal/templates/terminal/session_list.html:79
msgid "Duration" msgid "Duration"
msgstr "时长" msgstr "时长"
#: terminal/templates/terminal/session_list.html:102 #: terminal/templates/terminal/session_list.html:104
msgid "Monitor" msgid "Monitor"
msgstr "监控" msgstr "监控"
#: terminal/templates/terminal/session_list.html:103 #: terminal/templates/terminal/session_list.html:105
msgid "Terminate" msgid "Terminate"
msgstr "终断" msgstr "终断"
#: terminal/templates/terminal/session_list.html:119 #: terminal/templates/terminal/session_list.html:116
msgid "Terminate selected"
msgstr "终断所选"
#: terminal/templates/terminal/session_list.html:136
msgid "Terminate task send, waiting ..." msgid "Terminate task send, waiting ..."
msgstr "终断任务已发送,请等待" msgstr "终断任务已发送,请等待"
...@@ -1981,7 +1983,7 @@ msgstr "信息" ...@@ -1981,7 +1983,7 @@ msgstr "信息"
msgid "Session online list" msgid "Session online list"
msgstr "在线会话" msgstr "在线会话"
#: terminal/views/session.py:93 #: terminal/views/session.py:94
msgid "Session offline list" msgid "Session offline list"
msgstr "离线会话" msgstr "离线会话"
...@@ -2105,31 +2107,31 @@ msgstr "ssh密钥不合法" ...@@ -2105,31 +2107,31 @@ msgstr "ssh密钥不合法"
msgid "Select users" msgid "Select users"
msgstr "选择用户" msgstr "选择用户"
#: users/models/authentication.py:35 #: users/models/authentication.py:36
msgid "Private Token" msgid "Private Token"
msgstr "ssh密钥" msgstr "ssh密钥"
#: users/models/authentication.py:45 #: users/models/authentication.py:46
msgid "Login type" msgid "Login type"
msgstr "登录方式" msgstr "登录方式"
#: users/models/authentication.py:46 #: users/models/authentication.py:47
msgid "Login ip" msgid "Login ip"
msgstr "登录IP" msgstr "登录IP"
#: users/models/authentication.py:47 #: users/models/authentication.py:48
msgid "Login city" msgid "Login city"
msgstr "登录城市" msgstr "登录城市"
#: users/models/authentication.py:48 #: users/models/authentication.py:49
msgid "User agent" msgid "User agent"
msgstr "Agent" msgstr "Agent"
#: users/models/authentication.py:49 #: users/models/authentication.py:50
msgid "Date login" msgid "Date login"
msgstr "登录日期" msgstr "登录日期"
#: users/models/user.py:29 users/models/user.py:257 #: users/models/user.py:29 users/models/user.py:262
msgid "Administrator" msgid "Administrator"
msgstr "管理员" msgstr "管理员"
...@@ -2168,7 +2170,7 @@ msgstr "二次验证" ...@@ -2168,7 +2170,7 @@ msgstr "二次验证"
msgid "Public key" msgid "Public key"
msgstr "ssh公钥" msgstr "ssh公钥"
#: users/models/user.py:260 #: users/models/user.py:265
msgid "Administrator is the super user of system" msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员" msgstr "Administrator是初始的超级管理员"
...@@ -2239,7 +2241,7 @@ msgid " for more information" ...@@ -2239,7 +2241,7 @@ msgid " for more information"
msgstr "获取更多信息" msgstr "获取更多信息"
#: users/templates/users/forgot_password.html:26 #: users/templates/users/forgot_password.html:26
#: users/templates/users/login.html:64 #: users/templates/users/login.html:73
msgid "Forgot password" msgid "Forgot password"
msgstr "忘记密码" msgstr "忘记密码"
...@@ -2247,7 +2249,7 @@ msgstr "忘记密码" ...@@ -2247,7 +2249,7 @@ msgstr "忘记密码"
msgid "Input your email, that will send a mail to your" msgid "Input your email, that will send a mail to your"
msgstr "输入您的邮箱, 将会发一封重置邮件到您的邮箱中" msgstr "输入您的邮箱, 将会发一封重置邮件到您的邮箱中"
#: users/templates/users/login.html:47 #: users/templates/users/login.html:50
msgid "Captcha invalid" msgid "Captcha invalid"
msgstr "验证码错误" msgstr "验证码错误"
...@@ -2269,8 +2271,13 @@ msgstr "重置密码" ...@@ -2269,8 +2271,13 @@ msgstr "重置密码"
msgid "Password again" msgid "Password again"
msgstr "再次输入密码" msgstr "再次输入密码"
#: users/templates/users/reset_password.html:57
#: users/templates/users/user_profile.html:20
msgid "Setting"
msgstr "设置"
#: users/templates/users/user_create.html:4 #: users/templates/users/user_create.html:4
#: users/templates/users/user_list.html:16 users/views/user.py:72 #: users/templates/users/user_list.html:16 users/views/user.py:74
msgid "Create user" msgid "Create user"
msgstr "创建用户" msgstr "创建用户"
...@@ -2279,7 +2286,7 @@ msgid "Reset link will be generated and sent to the user. " ...@@ -2279,7 +2286,7 @@ msgid "Reset link will be generated and sent to the user. "
msgstr "生成重置密码连接,通过邮件发送给用户" msgstr "生成重置密码连接,通过邮件发送给用户"
#: users/templates/users/user_detail.html:19 #: users/templates/users/user_detail.html:19
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:148 #: users/templates/users/user_granted_asset.html:18 users/views/user.py:150
msgid "User detail" msgid "User detail"
msgstr "用户详情" msgstr "用户详情"
...@@ -2320,7 +2327,7 @@ msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱 ...@@ -2320,7 +2327,7 @@ msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱
msgid "" msgid ""
"The reset-ssh-public-key E-mail has been sent successfully. Please inform " "The reset-ssh-public-key E-mail has been sent successfully. Please inform "
"the user to update his new ssh public key." "the user to update his new ssh public key."
msgstr "重设钥邮件将会发送到用户邮箱" msgstr "重设钥邮件将会发送到用户邮箱"
#: users/templates/users/user_detail.html:350 #: users/templates/users/user_detail.html:350
#: users/templates/users/user_profile.html:140 #: users/templates/users/user_profile.html:140
...@@ -2329,7 +2336,7 @@ msgstr "重置SSH密钥" ...@@ -2329,7 +2336,7 @@ msgstr "重置SSH密钥"
#: users/templates/users/user_detail.html:360 #: users/templates/users/user_detail.html:360
msgid "This will reset the user public key and send a reset mail" msgid "This will reset the user public key and send a reset mail"
msgstr "将会失效用户当前钥,并发送重置邮件到用户邮箱" msgstr "将会失效用户当前钥,并发送重置邮件到用户邮箱"
#: users/templates/users/user_detail.html:377 #: users/templates/users/user_detail.html:377
#: users/templates/users/user_profile.html:166 #: users/templates/users/user_profile.html:166
...@@ -2351,7 +2358,7 @@ msgstr "取消" ...@@ -2351,7 +2358,7 @@ msgstr "取消"
#: users/templates/users/user_group_granted_asset.html:18 #: users/templates/users/user_group_granted_asset.html:18
#: users/views/group.py:80 #: users/views/group.py:80
msgid "User group detail" msgid "User group detail"
msgstr "资产组详情" msgstr "用户组详情"
#: users/templates/users/user_group_detail.html:86 #: users/templates/users/user_group_detail.html:86
msgid "Add user" msgid "Add user"
...@@ -2399,8 +2406,8 @@ msgstr "用户删除失败" ...@@ -2399,8 +2406,8 @@ msgstr "用户删除失败"
msgid "OTP" msgid "OTP"
msgstr "" msgstr ""
#: users/templates/users/user_profile.html:100 users/views/user.py:177 #: users/templates/users/user_profile.html:100 users/views/user.py:179
#: users/views/user.py:229 #: users/views/user.py:233
msgid "User groups" msgid "User groups"
msgstr "用户组" msgstr "用户组"
...@@ -2420,9 +2427,9 @@ msgstr "指纹" ...@@ -2420,9 +2427,9 @@ msgstr "指纹"
msgid "Update public key" msgid "Update public key"
msgstr "更新密钥" msgstr "更新密钥"
#: users/templates/users/user_update.html:4 users/views/user.py:91 #: users/templates/users/user_update.html:4 users/views/user.py:93
msgid "Update user" msgid "Update user"
msgstr "编辑用户" msgstr "更新用户"
#: users/utils.py:35 #: users/utils.py:35
msgid "Create account successfully" msgid "Create account successfully"
...@@ -2552,7 +2559,7 @@ msgstr "禁用或失效" ...@@ -2552,7 +2559,7 @@ msgstr "禁用或失效"
#: users/utils.py:154 #: users/utils.py:154
msgid "Password or SSH public key invalid" msgid "Password or SSH public key invalid"
msgstr "密码或钥不合法" msgstr "密码或钥不合法"
#: users/views/group.py:29 #: users/views/group.py:29
msgid "User group list" msgid "User group list"
...@@ -2560,78 +2567,84 @@ msgstr "用户组列表" ...@@ -2560,78 +2567,84 @@ msgstr "用户组列表"
#: users/views/group.py:63 #: users/views/group.py:63
msgid "Update user group" msgid "Update user group"
msgstr "编辑用户组" msgstr "更新用户组"
#: users/views/group.py:96
msgid "User group granted asset"
msgstr "用户组授权资产"
#: users/views/login.py:56 #: users/views/login.py:57
msgid "Please enable cookies and try again." msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie" msgstr "设置你的浏览器支持cookie"
#: users/views/login.py:90 #: users/views/login.py:99
msgid "Logout success" msgid "Logout success"
msgstr "退出登录成功" msgstr "退出登录成功"
#: users/views/login.py:91 #: users/views/login.py:100
msgid "Logout success, return login page" msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面" msgstr "退出登录成功,返回到登录页面"
#: users/views/login.py:107 #: users/views/login.py:116
msgid "Email address invalid, please input again" msgid "Email address invalid, please input again"
msgstr "邮箱地址错误,重新输入" msgstr "邮箱地址错误,重新输入"
#: users/views/login.py:120 #: users/views/login.py:129
msgid "Send reset password message" msgid "Send reset password message"
msgstr "发送重置密码邮件" msgstr "发送重置密码邮件"
#: users/views/login.py:121 #: users/views/login.py:130
msgid "Send reset password mail success, login your mail box and follow it " msgid "Send reset password mail success, login your mail box and follow it "
msgstr "" msgstr ""
"发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)" "发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)"
#: users/views/login.py:135 #: users/views/login.py:144
msgid "Reset password success" msgid "Reset password success"
msgstr "重置密码成功" msgstr "重置密码成功"
#: users/views/login.py:136 #: users/views/login.py:145
msgid "Reset password success, return to login page" msgid "Reset password success, return to login page"
msgstr "重置密码成功,返回到登录页面" msgstr "重置密码成功,返回到登录页面"
#: users/views/login.py:153 users/views/login.py:166 #: users/views/login.py:162 users/views/login.py:175
msgid "Token invalid or expired" msgid "Token invalid or expired"
msgstr "Token错误或失效" msgstr "Token错误或失效"
#: users/views/login.py:162 #: users/views/login.py:171
msgid "Password not same" msgid "Password not same"
msgstr "密码不一致" msgstr "密码不一致"
#: users/views/login.py:200 #: users/views/login.py:209
msgid "First login" msgid "First login"
msgstr "首次登陆" msgstr "首次登陆"
#: users/views/login.py:250 #: users/views/login.py:259
msgid "Login log list" msgid "Login log list"
msgstr "登录日志" msgstr "登录日志"
#: users/views/user.py:101 #: users/views/user.py:103
msgid "Bulk update user success" msgid "Bulk update user success"
msgstr "批量更新用户成功" msgstr "批量更新用户成功"
#: users/views/user.py:206 #: users/views/user.py:208
msgid "Invalid file." msgid "Invalid file."
msgstr "文件不合法" msgstr "文件不合法"
#: users/views/user.py:301 #: users/views/user.py:305
msgid "User granted assets" msgid "User granted assets"
msgstr "用户授权资产" msgstr "用户授权资产"
#: users/views/user.py:331 #: users/views/user.py:334
msgid "Profile setting" msgid "Profile setting"
msgstr "个人信息设置" msgstr "个人信息设置"
#: users/views/user.py:349 #: users/views/user.py:352
msgid "Password update" msgid "Password update"
msgstr "密码更新" msgstr "密码更新"
#: users/views/user.py:371 #: users/views/user.py:374
msgid "Public key update" msgid "Public key update"
msgstr "钥更新" msgstr "钥更新"
#~ msgid "Create asset permission "
#~ msgstr "创建资产权限"
...@@ -397,6 +397,6 @@ BOOTSTRAP3 = { ...@@ -397,6 +397,6 @@ BOOTSTRAP3 = {
} }
TOKEN_EXPIRATION = CONFIG.TOKEN_EXPIRATION or 3600 TOKEN_EXPIRATION = CONFIG.TOKEN_EXPIRATION or 3600
DISPLAY_PER_PAGE = CONFIG.DISPLAY_PER_PAGE DISPLAY_PER_PAGE = CONFIG.DISPLAY_PER_PAGE or 25
DEFAULT_EXPIRED_YEARS = 70 DEFAULT_EXPIRED_YEARS = 70
USER_GUIDE_URL = "" USER_GUIDE_URL = ""
...@@ -4,16 +4,16 @@ from __future__ import unicode_literals ...@@ -4,16 +4,16 @@ from __future__ import unicode_literals
from django.conf.urls import url, include from django.conf.urls import url, include
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from django.views.static import serve as static_serve
from rest_framework.schemas import get_schema_view from rest_framework.schemas import get_schema_view
from rest_framework_swagger.renderers import SwaggerUIRenderer, OpenAPIRenderer from rest_framework_swagger.renderers import SwaggerUIRenderer, OpenAPIRenderer
from .views import IndexView from .views import IndexView, LunaView
schema_view = get_schema_view(title='Users API', renderer_classes=[OpenAPIRenderer, SwaggerUIRenderer]) schema_view = get_schema_view(title='Users API', renderer_classes=[OpenAPIRenderer, SwaggerUIRenderer])
urlpatterns = [ urlpatterns = [
url(r'^$', IndexView.as_view(), name='index'), url(r'^$', IndexView.as_view(), name='index'),
url(r'^luna/', LunaView.as_view(), name='luna-error'),
url(r'^users/', include('users.urls.views_urls', namespace='users')), url(r'^users/', include('users.urls.views_urls', namespace='users')),
url(r'^assets/', include('assets.urls.views_urls', namespace='assets')), url(r'^assets/', include('assets.urls.views_urls', namespace='assets')),
url(r'^perms/', include('perms.urls.views_urls', namespace='perms')), url(r'^perms/', include('perms.urls.views_urls', namespace='perms')),
......
from django.views.generic import TemplateView import datetime
from django.http import HttpResponse
from django.views.generic import TemplateView, View
from django.utils import timezone from django.utils import timezone
from django.db.models import Count from django.db.models import Count
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
...@@ -45,15 +48,22 @@ class IndexView(LoginRequiredMixin, TemplateView): ...@@ -45,15 +48,22 @@ class IndexView(LoginRequiredMixin, TemplateView):
return self.session_week.values('user').distinct().count() return self.session_week.values('user').distinct().count()
def get_week_login_asset_count(self): def get_week_login_asset_count(self):
return self.session_week.values('asset').distinct().count() return self.session_week.count()
# return self.session_week.values('asset').distinct().count()
def get_month_day_metrics(self): def get_month_day_metrics(self):
month_str = [d.strftime('%m-%d') for d in self.session_month_dates] or ['0'] month_str = [d.strftime('%m-%d') for d in self.session_month_dates] or ['0']
return month_str return month_str
def get_month_login_metrics(self): def get_month_login_metrics(self):
return [self.session_month.filter(date_start__date=d).count() data = []
for d in self.session_month_dates] time_min = datetime.datetime.min.time()
time_max = datetime.datetime.max.time()
for d in self.session_month_dates:
ds = datetime.datetime.combine(d, time_min).replace(tzinfo=timezone.get_current_timezone())
de = datetime.datetime.combine(d, time_max).replace(tzinfo=timezone.get_current_timezone())
data.append(self.session_month.filter(date_start__range=(ds, de)).count())
return data
def get_month_active_user_metrics(self): def get_month_active_user_metrics(self):
if self.session_month_dates_archive: if self.session_month_dates_archive:
...@@ -119,10 +129,18 @@ class IndexView(LoginRequiredMixin, TemplateView): ...@@ -119,10 +129,18 @@ class IndexView(LoginRequiredMixin, TemplateView):
self.session_week = Session.objects.filter(date_start__gt=week_ago) self.session_week = Session.objects.filter(date_start__gt=week_ago)
self.session_month = Session.objects.filter(date_start__gt=month_ago) self.session_month = Session.objects.filter(date_start__gt=month_ago)
self.session_month_dates = self.session_month.dates('date_start', 'day') self.session_month_dates = self.session_month.dates('date_start', 'day')
self.session_month_dates_archive = [
self.session_month.filter(date_start__date=d) self.session_month_dates_archive = []
for d in self.session_month_dates time_min = datetime.datetime.min.time()
] time_max = datetime.datetime.max.time()
for d in self.session_month_dates:
ds = datetime.datetime.combine(d, time_min).replace(
tzinfo=timezone.get_current_timezone())
de = datetime.datetime.combine(d, time_max).replace(
tzinfo=timezone.get_current_timezone())
self.session_month_dates_archive.append(
self.session_month.filter(date_start__range=(ds, de)))
context = { context = {
'assets_count': self.get_asset_count(), 'assets_count': self.get_asset_count(),
...@@ -149,3 +167,12 @@ class IndexView(LoginRequiredMixin, TemplateView): ...@@ -149,3 +167,12 @@ class IndexView(LoginRequiredMixin, TemplateView):
kwargs.update(context) kwargs.update(context)
return super(IndexView, self).get_context_data(**kwargs) return super(IndexView, self).get_context_data(**kwargs)
class LunaView(View):
def get(self, request):
msg = """
Luna是单独部署的一个程序,你需要部署luna,coco,配置nginx做url分发,
如果你看到了这个页面,证明你访问的不是nginx监听的端口,祝你好运
"""
return HttpResponse(msg)
\ No newline at end of file
...@@ -12,7 +12,7 @@ class AssetPermissionCreateUpdateSerializer(serializers.ModelSerializer): ...@@ -12,7 +12,7 @@ class AssetPermissionCreateUpdateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = NodePermission model = NodePermission
fields = [ fields = [
'node', 'user_group', 'system_user', 'id', 'node', 'user_group', 'system_user',
'is_active', 'date_expired' 'is_active', 'date_expired'
] ]
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<div class="col-sm-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>{% trans 'Create asset permission ' %}</h5> <h5>{{ action }}</h5>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
......
...@@ -186,7 +186,7 @@ function initTree() { ...@@ -186,7 +186,7 @@ function initTree() {
{#if (value["key"] === "0") {#} {#if (value["key"] === "0") {#}
value["open"] = true; value["open"] = true;
{# }#} {# }#}
value["name"] = value["value"] + ' (' + value['assets_amount'] + ')' value["name"] = value["value"]
}); });
zNodes = data; zNodes = data;
$.fn.zTree.init($("#assetTree"), setting, zNodes); $.fn.zTree.init($("#assetTree"), setting, zNodes);
......
...@@ -427,3 +427,9 @@ div.dataTables_wrapper div.dataTables_filter { ...@@ -427,3 +427,9 @@ div.dataTables_wrapper div.dataTables_filter {
text-align: center; text-align: center;
padding: 5px 0; padding: 5px 0;
} }
.profile-dropdown li a {
font-size: 12px !important;
}
...@@ -3299,7 +3299,7 @@ body.tour-open .animated { ...@@ -3299,7 +3299,7 @@ body.tour-open .animated {
border-bottom: 1px solid #e7eaec; border-bottom: 1px solid #e7eaec;
} }
body { body {
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif; font-family: "open sans", "Helvetica Neue", "微软雅黑", Helvetica, Arial, sans-serif;
background-color: #2f4050; background-color: #2f4050;
font-size: 13px; font-size: 13px;
color: #676a6c; color: #676a6c;
......
apps/static/img/logo-text.png

12.4 KB | W: | H:

apps/static/img/logo-text.png

17.7 KB | W: | H:

apps/static/img/logo-text.png
apps/static/img/logo-text.png
apps/static/img/logo-text.png
apps/static/img/logo-text.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -14,8 +14,13 @@ ...@@ -14,8 +14,13 @@
{# <span class="m-r-sm text-muted welcome-message">{% trans 'Welcome to use Jumpserver system' %}</span>#} {# <span class="m-r-sm text-muted welcome-message">{% trans 'Welcome to use Jumpserver system' %}</span>#}
{# </li>#} {# </li>#}
<li class="dropdown"> <li class="dropdown">
<a class="dropdown-toggle count-info" data-toggle="dropdown" href="#"> <a class="count-info" href="https://market.aliyun.com/products/53690006/cmgj026011.html?spm=5176.730005.0.0.cY2io1" target="_blank">
<span class="m-r-sm text-muted welcome-message">{% trans 'Help' %}</span> <span class="m-r-sm text-muted welcome-message">{% trans 'Supports' %}</span>
</a>
</li>
<li class="dropdown">
<a class="count-info" href="http://jumpserver.readthedocs.io/" target="_blank">
<span class="m-r-sm text-muted welcome-message">{% trans 'Docs' %}</span>
</a> </a>
</li> </li>
<li class="dropdown"> <li class="dropdown">
...@@ -28,9 +33,8 @@ ...@@ -28,9 +33,8 @@
</span> </span>
</span> </span>
</a> </a>
<ul class="dropdown-menu animated fadeInRight m-t-xs"> <ul class="dropdown-menu animated fadeInRight m-t-xs profile-dropdown">
<li><a href="{% url 'users:user-profile' %}"><i class="fa fa-cogs"> </i><span> {% trans 'Profile' %}</span></a></li> <li><a href="{% url 'users:user-profile' %}"><i class="fa fa-cogs"> </i><span> {% trans 'Profile' %}</span></a></li>
<li class="divider"></li>
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
{% if request.COOKIES.IN_ADMIN_PAGE == 'No' %} {% if request.COOKIES.IN_ADMIN_PAGE == 'No' %}
<li><a id="switch_admin"><i class="fa fa-exchange"></i><span> {% trans 'Admin page' %}</span></a></li> <li><a id="switch_admin"><i class="fa fa-exchange"></i><span> {% trans 'Admin page' %}</span></a></li>
...@@ -57,11 +61,11 @@ ...@@ -57,11 +61,11 @@
<li> <li>
<a href="">{% trans 'Dashboard' %}</a> <a href="">{% trans 'Dashboard' %}</a>
</li> </li>
<li>
{% if app %} {% if app %}
<li>
<a>{{ app }}</a> <a>{{ app }}</a>
{% endif %}
</li> </li>
{% endif %}
{% if action %} {% if action %}
<li class="active"> <li class="active">
<strong>{{ action }}</strong> <strong>{{ action }}</strong>
......
...@@ -42,6 +42,11 @@ ...@@ -42,6 +42,11 @@
<li id="session-online"><a href="{% url 'terminal:session-online-list' %}">{% trans 'Session online' %}</a></li> <li id="session-online"><a href="{% url 'terminal:session-online-list' %}">{% trans 'Session online' %}</a></li>
<li id="session-offline"><a href="{% url 'terminal:session-offline-list' %}">{% trans 'Session offline' %}</a></li> <li id="session-offline"><a href="{% url 'terminal:session-offline-list' %}">{% trans 'Session offline' %}</a></li>
<li id="command"><a href="{% url 'terminal:command-list' %}">{% trans 'Commands' %}</a></li> <li id="command"><a href="{% url 'terminal:command-list' %}">{% trans 'Commands' %}</a></li>
<li>
<a href="{% url 'terminal:web-terminal' %}" target="_blank">
<span class="nav-label">{% trans 'Web terminal' %}</span>
</a>
</li>
<li id="terminal"><a href="{% url 'terminal:terminal-list' %}">{% trans 'Terminal' %}</a></li> <li id="terminal"><a href="{% url 'terminal:terminal-list' %}">{% trans 'Terminal' %}</a></li>
</ul> </ul>
</li> </li>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<li class="nav-header"> <li class="nav-header">
<div class="dropdown profile-element"> <div class="dropdown profile-element">
<div href="http://www.jumpserver.org" target="_blank"> <div href="http://www.jumpserver.org" target="_blank">
<img alt="image" height="55" src="/static/img/logo-text.png" style="margin-left: 10px"/> <img alt="logo" height="55" width="185" src="/static/img/logo-text.png" style="margin-left: 20px"/>
</div> </div>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
......
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
<div class="row"> <div class="row">
<div class="col-sm-2 border-bottom white-bg dashboard-header" style="margin-left:15px;height: 346px"> <div class="col-sm-2 border-bottom white-bg dashboard-header" style="margin-left:15px;height: 346px">
<h2>活跃用户TOP5</h2> <h2>活跃用户TOP5</h2>
<small>过去一周共有<span class="text-info">{{ user_visit_count_weekly }}</span>位用户登录<span class="text-success">{{ asset_visit_count_weekly }}</span>服务器.</small> <small>过去一周共有<span class="text-info">{{ user_visit_count_weekly }}</span>位用户登录<span class="text-success">{{ asset_visit_count_weekly }}</span>资产.</small>
<ul class="list-group clear-list m-t"> <ul class="list-group clear-list m-t">
{% for data in user_visit_count_top_five %} {% for data in user_visit_count_top_five %}
<li class="list-group-item fist-item"> <li class="list-group-item fist-item">
......
...@@ -5,14 +5,15 @@ import logging ...@@ -5,14 +5,15 @@ import logging
import os import os
import uuid import uuid
from rest_framework import viewsets, serializers
from rest_framework.views import APIView, Response
from rest_framework.permissions import AllowAny
from django.core.cache import cache from django.core.cache import cache
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.utils import timezone from django.utils import timezone
from django.core.files.storage import default_storage from django.core.files.storage import default_storage
from django.http import HttpResponseNotFound from django.http import HttpResponseNotFound
from rest_framework import viewsets, serializers
from rest_framework.views import APIView, Response
from rest_framework.permissions import AllowAny
from rest_framework_bulk import BulkModelViewSet
from common.utils import get_object_or_none from common.utils import get_object_or_none
from .models import Terminal, Status, Session, Task from .models import Terminal, Status, Session, Task
...@@ -179,12 +180,29 @@ class SessionViewSet(viewsets.ModelViewSet): ...@@ -179,12 +180,29 @@ class SessionViewSet(viewsets.ModelViewSet):
return self.queryset return self.queryset
class TaskViewSet(viewsets.ModelViewSet): class TaskViewSet(BulkModelViewSet):
queryset = Task.objects.all() queryset = Task.objects.all()
serializer_class = TaskSerializer serializer_class = TaskSerializer
permission_classes = (IsSuperUserOrAppUser,) permission_classes = (IsSuperUserOrAppUser,)
class KillSessionAPI(APIView):
permission_classes = (IsSuperUserOrAppUser,)
model = Task
def post(self, request, *args, **kwargs):
validated_session = []
for session_id in request.data:
session = get_object_or_none(Session, id=session_id)
if session and not session.is_finished:
validated_session.append(session_id)
self.model.objects.create(
name="kill_session", args=session.id,
terminal=session.terminal,
)
return Response({"ok": validated_session})
class CommandViewSet(viewsets.ViewSet): class CommandViewSet(viewsets.ViewSet):
"""接受app发送来的command log, 格式如下 """接受app发送来的command log, 格式如下
{ {
......
...@@ -129,7 +129,7 @@ class Session(models.Model): ...@@ -129,7 +129,7 @@ class Session(models.Model):
has_command = models.BooleanField(default=False, verbose_name=_("Command")) has_command = models.BooleanField(default=False, verbose_name=_("Command"))
terminal = models.ForeignKey(Terminal, null=True, on_delete=models.CASCADE) terminal = models.ForeignKey(Terminal, null=True, on_delete=models.CASCADE)
date_last_active = models.DateTimeField(verbose_name=_("Date last active"), default=timezone.now) date_last_active = models.DateTimeField(verbose_name=_("Date last active"), default=timezone.now)
date_start = models.DateTimeField(verbose_name=_("Date start")) date_start = models.DateTimeField(verbose_name=_("Date start"), db_index=True)
date_end = models.DateTimeField(verbose_name=_("Date end"), null=True) date_end = models.DateTimeField(verbose_name=_("Date end"), null=True)
class Meta: class Meta:
......
...@@ -3,7 +3,11 @@ ...@@ -3,7 +3,11 @@
from django.utils import timezone from django.utils import timezone
from rest_framework import serializers from rest_framework import serializers
from rest_framework_bulk.serializers import BulkListSerializer
from common.mixins import BulkSerializerMixin
from common.utils import get_object_or_none
from .models import Terminal, Status, Session, Task from .models import Terminal, Status, Session, Task
from .backends import get_multi_command_store from .backends import get_multi_command_store
...@@ -47,6 +51,7 @@ class SessionSerializer(serializers.ModelSerializer): ...@@ -47,6 +51,7 @@ class SessionSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Session model = Session
list_serializer_class = BulkListSerializer
fields = '__all__' fields = '__all__'
def get_command_amount(self, obj): def get_command_amount(self, obj):
...@@ -60,11 +65,12 @@ class StatusSerializer(serializers.ModelSerializer): ...@@ -60,11 +65,12 @@ class StatusSerializer(serializers.ModelSerializer):
model = Status model = Status
class TaskSerializer(serializers.ModelSerializer): class TaskSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class Meta: class Meta:
fields = '__all__' fields = '__all__'
model = Task model = Task
list_serializer_class = BulkListSerializer
class ReplaySerializer(serializers.Serializer): class ReplaySerializer(serializers.Serializer):
......
...@@ -8,7 +8,7 @@ from django.utils import timezone ...@@ -8,7 +8,7 @@ from django.utils import timezone
from common.celery import register_as_period_task, after_app_ready_start, \ from common.celery import register_as_period_task, after_app_ready_start, \
after_app_shutdown_clean after_app_shutdown_clean
from .models import Status from .models import Status, Session
CACHE_REFRESH_INTERVAL = 10 CACHE_REFRESH_INTERVAL = 10
...@@ -20,11 +20,17 @@ RUNNING = False ...@@ -20,11 +20,17 @@ RUNNING = False
@after_app_ready_start @after_app_ready_start
@after_app_shutdown_clean @after_app_shutdown_clean
def delete_terminal_status_period(): def delete_terminal_status_period():
yesterday = timezone.now() - datetime.timedelta(days=1) yesterday = timezone.now() - datetime.timedelta(days=3)
Status.objects.filter(date_created__lt=yesterday).delete() Status.objects.filter(date_created__lt=yesterday).delete()
@shared_task
@register_as_period_task(interval=3600)
@after_app_ready_start
@after_app_shutdown_clean
def clean_orphan_session():
active_sessions = Session.objects.filter(is_finished=False)
for session in active_sessions:
if not session.terminal.is_active:
session.is_finished = True
session.save()
...@@ -109,6 +109,21 @@ ...@@ -109,6 +109,21 @@
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}
{% block content_bottom_left %}
<div id="actions" {% if type != "online" %} style="display: none" {% endif %}>
<div class="input-group">
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
<option value="terminate">{% trans 'Terminate selected' %}</option>
</select>
<div class="input-group-btn pull-left" style="padding-left: 5px;">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
{% 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>
...@@ -119,7 +134,7 @@ ...@@ -119,7 +134,7 @@
}, 1000) }, 1000)
} }
var success_message = '{% trans "Terminate task send, waiting ..." %}'; var success_message = '{% trans "Terminate task send, waiting ..." %}';
var the_url = "{% url 'api-terminal:tasks-list' %}"; var the_url = "{% url 'api-terminal:kill-session' %}";
APIUpdateAttr({ APIUpdateAttr({
url: the_url, url: the_url,
method: 'POST', method: 'POST',
...@@ -150,14 +165,31 @@ ...@@ -150,14 +165,31 @@
}).on('click', '.btn-term', function () { }).on('click', '.btn-term', function () {
var $this = $(this); var $this = $(this);
var session_id = $this.attr('value'); var session_id = $this.attr('value');
var terminal_id = $this.attr('terminal'); var data = [
var data = { session_id
name: "kill_session", ];
args: session_id,
terminal: terminal_id
};
terminateSession(data) terminateSession(data)
}) }).on('click', '#btn_bulk_update', function () {
var action = $('#slct_bulk_update').val();
var id_list = [];
$(".cbx-term:checked").each(function (index, data) {
id_list.push($(data).attr("value"))
});
if (id_list.length === 0) {
return false;
}
function doTerminate() {
terminateSession(id_list)
}
switch(action) {
case 'terminate':
doTerminate();
break;
default:
break;
}
});
</script> </script>
{% endblock %} {% endblock %}
...@@ -22,6 +22,7 @@ urlpatterns = [ ...@@ -22,6 +22,7 @@ urlpatterns = [
url(r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-]{36})/replay/$', url(r'^v1/sessions/(?P<pk>[0-9a-zA-Z\-]{36})/replay/$',
api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}), api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}),
name='session-replay'), name='session-replay'),
url(r'^v1/tasks/kill-session/', api.KillSessionAPI.as_view(), name='kill-session'),
url(r'^v1/terminal/(?P<terminal>[a-zA-Z0-9\-]{36})/access-key', api.TerminalTokenApi.as_view(), name='terminal-access-key'), url(r'^v1/terminal/(?P<terminal>[a-zA-Z0-9\-]{36})/access-key', api.TerminalTokenApi.as_view(), name='terminal-access-key'),
url(r'^v1/terminal/config', api.TerminalConfig.as_view(), name='terminal-config'), url(r'^v1/terminal/config', api.TerminalConfig.as_view(), name='terminal-config'),
] ]
......
...@@ -6,7 +6,7 @@ from django.conf import settings ...@@ -6,7 +6,7 @@ from django.conf import settings
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from common.mixins import DatetimeSearchMixin from common.mixins import DatetimeSearchMixin, AdminUserRequiredMixin
from ..models import Command from ..models import Command
from .. import utils from .. import utils
from ..backends import get_multi_command_store from ..backends import get_multi_command_store
...@@ -15,7 +15,7 @@ __all__ = ['CommandListView'] ...@@ -15,7 +15,7 @@ __all__ = ['CommandListView']
common_storage = get_multi_command_store() common_storage = get_multi_command_store()
class CommandListView(DatetimeSearchMixin, ListView): class CommandListView(DatetimeSearchMixin, AdminUserRequiredMixin, ListView):
model = Command model = Command
template_name = "terminal/command_list.html" template_name = "terminal/command_list.html"
context_object_name = 'command_list' context_object_name = 'command_list'
......
...@@ -74,6 +74,7 @@ class SessionOnlineListView(SessionListView): ...@@ -74,6 +74,7 @@ class SessionOnlineListView(SessionListView):
context = { context = {
'app': _('Terminal'), 'app': _('Terminal'),
'action': _('Session online list'), 'action': _('Session online list'),
'type': 'online',
'now': timezone.now(), 'now': timezone.now(),
} }
kwargs.update(context) kwargs.update(context)
...@@ -97,7 +98,7 @@ class SessionOfflineListView(SessionListView): ...@@ -97,7 +98,7 @@ class SessionOfflineListView(SessionListView):
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class SessionDetailView(SingleObjectMixin, ListView): class SessionDetailView(SingleObjectMixin, AdminUserRequiredMixin, ListView):
template_name = 'terminal/session_detail.html' template_name = 'terminal/session_detail.html'
model = Session model = Session
object = None object = None
......
...@@ -145,7 +145,8 @@ class UserAuthApi(APIView): ...@@ -145,7 +145,8 @@ class UserAuthApi(APIView):
if not login_ip: if not login_ip:
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '').split(',') x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '').split(',')
if x_forwarded_for:
if x_forwarded_for and x_forwarded_for[0]:
login_ip = x_forwarded_for[0] login_ip = x_forwarded_for[0]
else: else:
login_ip = request.META.get("REMOTE_ADDR") login_ip = request.META.get("REMOTE_ADDR")
......
...@@ -16,7 +16,8 @@ class AccessKey(models.Model): ...@@ -16,7 +16,8 @@ class AccessKey(models.Model):
default=uuid.uuid4, editable=False) default=uuid.uuid4, editable=False)
secret = models.UUIDField(verbose_name='AccessKeySecret', secret = models.UUIDField(verbose_name='AccessKeySecret',
default=uuid.uuid4, editable=False) default=uuid.uuid4, editable=False)
user = models.ForeignKey(User, verbose_name='User', on_delete=models.CASCADE, related_name='access_key') user = models.ForeignKey(User, verbose_name='User',
on_delete=models.CASCADE, related_name='access_key')
def get_id(self): def get_id(self):
return str(self.id) return str(self.id)
......
...@@ -22,6 +22,7 @@ class UserGroup(NoDeleteModelMixin): ...@@ -22,6 +22,7 @@ class UserGroup(NoDeleteModelMixin):
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
verbose_name = _("User group")
@classmethod @classmethod
def initial(cls): def initial(cls):
......
...@@ -251,6 +251,7 @@ class User(AbstractUser): ...@@ -251,6 +251,7 @@ class User(AbstractUser):
class Meta: class Meta:
ordering = ['username'] ordering = ['username']
verbose_name = _("User")
#: Use this method initial user #: Use this method initial user
@classmethod @classmethod
......
...@@ -22,24 +22,27 @@ ...@@ -22,24 +22,27 @@
<div class="loginColumns animated fadeInDown"> <div class="loginColumns animated fadeInDown">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h2 class="font-bold">欢迎使用Jumpserver开源跳板</h2> <h2 class="font-bold">欢迎使用Jumpserver开源堡垒</h2>
<p> <p>
符合4A规范的专业运维审计系统:拥有跳板机的所有功能,认证,授权,审计,文件上传; 全球首款完全开源的堡垒机,使用GNU GPL v2.0开源协议,是符合 4A 的专业运维审计系统。
</p> </p>
<p> <p>
极致的用户使用体验:拥有时尚外观是区别与以往版本和其他软件的铭牌,高雅的气质让你爱不释手; 使用Python / Django 进行开发,遵循 Web 2.0 规范,配备了业界领先的 Web Terminal 解决方案,交互界面美观、用户体验好。
</p> </p>
<p> <p>
混合云环境下的堡垒机:怎么能容忍传统堡垒机的繁琐步骤,Jumpserver让你极致省力; 采纳分布式架构,支持多机房跨区域部署,中心节点提供 API,各机房部署登录节点,可横向扩展、无并发访问限制。
</p> </p>
<p> <p>
<small>改变世界,从一点点开始。</small> 改变世界,从一点点开始。
</p> </p>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="ibox-content"> <div class="ibox-content">
<div><img src="{% static 'img/logo.png' %}" width="82" height="82"> <span class="font-bold text-center" style="font-size: 32px; font-family: inherit">{% trans 'Login' %}</span></div> <div>
<img src="{% static 'img/logo.png' %}" width="60" height="60">
<span class="font-bold text-center" style="font-size: 24px; font-family: inherit; margin-left: 20px">{% trans 'Login' %}</span>
</div>
<form class="m-t" role="form" method="post" action=""> <form class="m-t" role="form" method="post" action="">
{% csrf_token %} {% csrf_token %}
{% if form.errors %} {% if form.errors %}
...@@ -60,12 +63,16 @@ ...@@ -60,12 +63,16 @@
</div> </div>
<button type="submit" class="btn btn-primary block full-width m-b">{% trans 'Login' %}</button> <button type="submit" class="btn btn-primary block full-width m-b">{% trans 'Login' %}</button>
{% if demo_mode %}
<p class="text-muted font-bold" style="color: red">
Demo账号: admin 密码: admin
</p>
{% endif %}
<a href="{% url 'users:forgot-password' %}"> <a href="{% url 'users:forgot-password' %}">
<small>{% trans 'Forgot password' %}?</small> <small>{% trans 'Forgot password' %}?</small>
</a> </a>
<p class="text-muted text-center">
</p>
</form> </form>
<p class="m-t"> <p class="m-t">
</p> </p>
......
...@@ -92,8 +92,8 @@ class UserGroupGrantedAssetView(AdminUserRequiredMixin, DetailView): ...@@ -92,8 +92,8 @@ class UserGroupGrantedAssetView(AdminUserRequiredMixin, DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
'app': 'User', 'app': _('Users'),
'action': 'User group granted asset', 'action': _('User group granted asset'),
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals from __future__ import unicode_literals
import os
from django import forms from django import forms
from django.shortcuts import render from django.shortcuts import render
from django.contrib.auth import login as auth_login, logout as auth_logout from django.contrib.auth import login as auth_login, logout as auth_logout
...@@ -56,6 +57,7 @@ class UserLoginView(FormView): ...@@ -56,6 +57,7 @@ class UserLoginView(FormView):
return HttpResponse(_("Please enable cookies and try again.")) return HttpResponse(_("Please enable cookies and try again."))
auth_login(self.request, form.get_user()) auth_login(self.request, form.get_user())
x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR', '').split(',') x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR', '').split(',')
if x_forwarded_for and x_forwarded_for[0]: if x_forwarded_for and x_forwarded_for[0]:
login_ip = x_forwarded_for[0] login_ip = x_forwarded_for[0]
else: else:
...@@ -75,6 +77,13 @@ class UserLoginView(FormView): ...@@ -75,6 +77,13 @@ class UserLoginView(FormView):
self.redirect_field_name, self.redirect_field_name,
self.request.GET.get(self.redirect_field_name, reverse('index'))) self.request.GET.get(self.redirect_field_name, reverse('index')))
def get_context_data(self, **kwargs):
context = {
'demo_mode': os.environ.get("DEMO_MODE"),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@method_decorator(never_cache, name='dispatch') @method_decorator(never_cache, name='dispatch')
class UserLogoutView(TemplateView): class UserLogoutView(TemplateView):
...@@ -237,7 +246,7 @@ class LoginLogListView(DatetimeSearchMixin, ListView): ...@@ -237,7 +246,7 @@ class LoginLogListView(DatetimeSearchMixin, ListView):
if self.user: if self.user:
queryset = queryset.filter(username=self.user) queryset = queryset.filter(username=self.user)
if self.keyword: if self.keyword:
queryset = self.queryset.filter( queryset = queryset.filter(
Q(ip__contains=self.keyword) | Q(ip__contains=self.keyword) |
Q(city__contains=self.keyword) | Q(city__contains=self.keyword) |
Q(username__contains=self.keyword) Q(username__contains=self.keyword)
......
...@@ -313,7 +313,6 @@ class UserProfileView(LoginRequiredMixin, TemplateView): ...@@ -313,7 +313,6 @@ class UserProfileView(LoginRequiredMixin, TemplateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
'app': _('Users'),
'action': _('Profile'), 'action': _('Profile'),
} }
kwargs.update(context) kwargs.update(context)
......
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = Jumpserver
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
\ No newline at end of file
资产管理模块
=============
\ No newline at end of file
管理文档
=========
这里介绍管理员功能。
.. toctree::
:maxdepth: 1
admin_user
admin_asset
用户管理
========
这里介绍用户管理模块的功能。
点击页面左侧“用户列表”菜单下的“用户列表,进入用户列表页面。
.. contents:: Topics
.. _create_user:
创建用户
````````
点击页面左上角“创建用户”按钮,进入创建用户页面,填写账户,角色安全,个人等信息,点击“提交”按钮,用户创建完成。
.. _update_user:
更新用户
````````
点击页面右边的“更新”按钮,进入编辑用户页面,编辑用户信息,点击“提交”按钮,更新用户完成。
.. _delete_user:
删除用户
````````
点击页面右边的“删除”按钮,弹出是否删除确认框,点击“确定”按钮,删除用户完成。
.. _export_user:
导出用户
````````
选中用户,点击右上角的“导出”按钮,导出用户完成。
.. _inport_user:
导入用户
````````
点击右上角的“导入”按钮,弹出导入对话框,选择要导入的CSV格式文件,点击“确认”按钮,导入用户完成。
.. _batch_operation:
批量操作
````````
选中用户,选择页面左下角的批量操作选项,点击”提交“按钮,批量操作完成。
\ No newline at end of file
REST API规范约定
----------------
这里仅考虑REST API的基本情况。参考
`RESTful API 设计指南`_
`github api文档`_
协议
~~~~
API与用户的通信协议,总是使用HTTPs协议。
域名
~~~~
这版api相对简单, 没有前后端分离, 没有独立app, 所以放在主域名下
::
https://example.org/api/
版本
~~~~
将API的版本号放入URL中, 由于一个项目多个app所以Jumpserver使用以下风格,
将版本号放到app后面
::
https://example.com/api/:app:/:version:/:resource:
https://example.com/api/assets/v1.0/assets [GET, POST]
https://example.com/api/assets/v1.0/assets/1 [GET, PUT, DELETE]
路径
~~~~
路径又称“终点”(endpoint),表示API的具体网址。
在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的“集合”(collection),所以API中的名词也应该使用复数。
举例来说 cmdb中的assets列表, idc列表
::
https://example.com/api/:app:/:version:/:resource:
https://example.com/api/assets/v1.0/assets [GET, POST]
https://example.com/api/assets/v1.0/assets/1 [GET, PUT, DELETE]
https://example.com/api/assets/v1.0/idcs [GET, POST]
一般性的增删查改(CRUD)API,完全使用HTTP
method加上url提供的语义,url中的可变部分(比如上面提到的)
一般用来传递该API操作的核心实体对象的唯一ID,如果有更多的参数需要提供,GET方法请使用url
parameter
(例如:“?client_id=xxxxx&app_id=xxxxxx”),PUT/POST/DELETE方法请使用请求体传递参数。
HTTP Method
~~~~~~~~~~~
对于资源的具体操作类型,由HTTP动词表示。
常用的HTTP动词有下面五个(括号里是对应的SQL命令)。
- GET(SELECT):从服务器取出资源(一项或多项)。
- POST(CREATE):在服务器新建一个资源。
- PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源, 幂等
- PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
- DELETE(DELETE):从服务器删除资源。
.. _RESTful API 设计指南: http://www.ruanyifeng.com/blog/2014/05/restful_api.html
.. _github api文档: https://developer.github.com/v3/
过滤信息
~~~~~~~~
常见参数约定
::
?keyword=localhost 模糊搜索
?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sort=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?asset_id=1:指定筛选条件
状态码
~~~~~~
服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。
- 200 OK -
[GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
- 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
- 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
- 204 NO CONTENT - [DELETE]:用户删除数据成功。
- 400 INVALID REQUEST -
[POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
- 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
- 403 Forbidden - [*]
表示用户得到授权(与401错误相对),但是访问是被禁止的。
- 404 NOT FOUND -
[*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
- 406 Not Acceptable -
[GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
- 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
- 422 Unprocesable entity - [POST/PUT/PATCH]
当创建一个对象时,发生一个验证错误。
- 500 INTERNAL SERVER ERROR -
[*]:服务器发生错误,用户将无法判断发出的请求是否成功。
错误处理
~~~~~~~~
如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。
::
{
error: "Invalid API key"
}
返回结果
~~~~~~~~
针对不同操作,服务器向用户返回的结果应该符合以下规范。
::
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档
Hypermedia API
~~~~~~~~~~~~~~
RESTful
API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
比如,当用户向api.example.com的根目录发出请求,会得到这样一个文档。
::
{"link": {
"rel": "collection https://www.example.com/zoos",
"href": "https://api.example.com/zoos",
"title": "List of zoos",
"type": "application/vnd.yourformat+json"
}}
上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步该调用什么API了。
rel表示这个API与当前网址的关系(collection关系,并给出该collection的网址),
href表示API的路径,title表示API的标题,type表示返回类型。 Hypermedia
API的设计被称为HATEOAS。 Github的API就是这种设计.
其它
~~~~
(1)API的身份认证应该使用OAuth 2.0框架。
(2)服务器返回的数据格式,应该尽量使用JSON
\ No newline at end of file
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/stable/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
import sphinx_rtd_theme
# -- Project information -----------------------------------------------------
project = 'jumpserver'
copyright = '北京堆栈科技有限公司 © 2014-2018'
author = 'Jumpserver team'
# The short X.Y version
version = ''
# The full version, including alpha/beta/rc tags
release = '0.5.0'
# -- General configuration ---------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.viewcode',
'sphinx.ext.githubpages',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'zh_CN'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path .
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
html_show_sourcelink = False
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
# html_theme = 'alabaster'
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
'logo_only': True,
'display_version': False
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'Jumpserver 文档'
# -- Options for LaTeX output ------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'jumpserver.tex', 'jumpserver Documentation',
'Jumpserver team', 'manual'),
]
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'jumpserver', 'jumpserver Documentation',
[author], 1)
]
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'jumpserver', 'jumpserver Documentation',
author, 'jumpserver', 'One line description of project.',
'Miscellaneous'),
]
# -- Extension configuration -------------------------------------------------
html_logo = '_static/img/logo-text.png'
联系方式
+++++++++++++++++++++++++
QQ群
~~~~~~~~
群1: 390139816
群2: 399218702
群3: 552054376
Github
~~~~~~~~
https://github.com/jumpserver/jumpserver.git
官网
~~~~~~~~
http://www.jumpserver.org
Demo
~~~~~~~~
http://demo.jumpserver.org:8080
邮件
~~~~~~~~
ibuler#fit2cloud.com (#替换为@)
\ No newline at end of file
贡献者
++++++++++++++++++++++++
感谢一下朋友为Jumpserver做出的贡献,世界因你们而不同,排名不分先后
- **小彧 <李磊>** Django资深开发者,为用户模块贡献了很多代码
- **sofia <周小侠>** 资深前端工程师, 前端代码贡献者
- **liuz <刘正> 全栈工程师** 编写了Web terminal大部分代码
- **jiaxiangkong <陈尚委>** Jumpserver测试运营
- **halcyon <王墉>** DevOps 资深开发者, 0.3.2 核心开发者之一
- **yumaojun03 <喻茂峻>** DevOps 资深开发者,擅长Python, Go以及PAAS平台开发
- **kelianchun <柯连春>** DevOps 资产开发者,fix了很多bug
\ No newline at end of file
开发文档
======================================
.. toctree::
:maxdepth: 1
:caption: 开发文档
api_style_guide
python_style_guide
project_structure
FAQ
+++++++++++++++++++++
\ No newline at end of file
.. jumpserver documentation master file, created by
sphinx-quickstart on Mon Feb 26 23:28:27 2018.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Jumpserver 文档
======================================
.. toctree::
:maxdepth: 2
:caption: 文档:
intro
installation
admin_guide
user_guide
development
contributor
contact
faq
索引
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
安装文档
++++++++++++++++++++++++
.. toctree::
:maxdepth: 1
quickstart
step_by_step
upgrade
简介
============
Jumpserver是混合云下更好用的堡垒机, 分布式架构设计无限扩展,轻松对接混合云资产,支持使用云存储(AWS S3, ES等)存储录像、命令
Jumpserver颠覆传统堡垒机, 无主机和并发数量限制,支持水平扩容,FIT2CLOUD提供完备的商业服务支持,用户无后顾之忧
Jumpserver拥有极致的用户体验, 极致UI体验,容器化的部署方式,部署过程方便快捷,可持续升级
组件说明
++++++++++++++++++++++++
Jumpserver
```````````
现指Jumpserver管理后台,是核心组件(Core), 使用 Django Class Based View 风格开发,支持Restful API。
`Github <https://github.com/jumpserver/jumpserver.git>`_
Coco
````````
实现了SSH Server 和 Web Terminal Server的组件,提供ssh和websocket接口, 使用 Paramiko 和 Flask 开发。
`Github <https://github.com/jumpserver/coco.git>`__
Luna
````````
现在是Web Terminal前端,计划前端页面都由该项目提供,Jumpserver只提供API,不再负责后台渲染html等。
`Github <https://github.com/jumpserver/luna.git>`__
Guacamole
```````````
Apache 跳板机项目,Jumpserver使用其组件实现RDP功能,Jumpserver并没有修改其代码而是添加了额外的插件,支持Jumpserver调用
Jumpserver-python-sdk
```````````````````````
Jumpserver API Python SDK,Coco目前使用该SDK与Jumpserver API交互
`Github <https://github.com/jumpserver/jumpserver-python-sdk.git>`__
组件架构图
++++++++++++++++++++++++
.. image:: _static/img/structure.png
:alt: 组件架构图
项目骨架
--------
说明如下:
::
.
├── config-example.py // 配置文件样例
├── docs // 所有doc文件放到该目录
│ └── README.md
├── LICENSE
├── README.md
├── install // 安装说明
├── logs // 日志目录
├── apps // 管理后台目录,也是各app所在目录
│ └── assets // app目录
│ │ ├── admin.py
│ │ ├── apps.py // 新版本django app设置文件
│ │ ├── api.py // api文件
│ │ ├── __init__.py // 对外暴露的接口,放到该文件中,方便别的app引用
│ │ ├── migrations // models Migrations版本控制目录
│ │ │ └── __init__.py
│ │ ├── models.py // 数据模型目录
│ │ ├── static // app下静态资源目录,如果需要
│ │ │ └── assets // 多一层目录,防止资源重名
│ │ │ └── some_image.png
│ │ ├── templates // app下模板目录
│ │ │ └── assets // 多一层目录,防止资源重名
│ │ │ └── asset_list.html
│ │ ├── templatetags // 模板标签目录
│ │ ├── tests.py // 测试用例文件
│ │ ├── urls.py // urlconf文件
│ │ ├── utils.py // 将views和api可复用的代码放在这里, api和views只是请求和返回不同
│ │ └── views.py // views文件
│ ├── common
│ │ ├── templatetags // 通用template tag
│ │ ├── utils.py // 通用的函数方法
│ │ └── views.py
│ ├── fixtures // 初始化数据目录
│ │ ├── init.json // 初始化项目数据库
│ │ └── fake.json // 生成大量测试数据
│ ├── jumpserver // 项目设置目录
│ │ ├── __init__.py
│ │ ├── settings.py // 项目设置文件
│ │ ├── urls.py // 项目入口urlconf
│ │ └── wsgi.py
│ ├── manage.py
│ ├── static // 项目静态资源目录
│ ├── i18n // 项目多语言目录
│ └── templates // 项目模板目录
\ No newline at end of file
Jumpserver 项目规范(Draft)
============================
语言框架
--------
1. Python 3.6.1 (当前最新)
2. Django 1.11 (当前最新)
3. Flask 0.12 Luna (当前最新)
4. Paramiko 2.12 Coco (当前最新)
Django规范
----------
1. 尽量使用Class Base View编程,更少代码
2. 使用Django Form
3. 每个url独立命名,不要硬编码,同理static也是
4. 数据库表名手动指定,不要使用默认
5. 代码优雅简洁
6. 注释明确优美
7. 测试案例尽可能完整
8. 尽可能利用Django造好的轮子
代码风格
--------
Python方面大致的风格,我们采用pocoo的\ `Style
Guidance`_\ ,但是有些细节部分会尽量放开 参考国内翻译
基本的代码布局
~~~~~~~~~~~~~~
缩进
^^^^
1. Python严格采用4个空格的缩进,任何python代码都都必须遵守此规定。
2. web部分代码(HTML, CSS,
JavaScript),Node.js采用2空格缩进,同样不使用tab (:raw-latex:`\t`)。
之所以与Python不同,是因为js中有大量回调式的写法,2空格可以显著降低视觉上的负担。
最大行长度
^^^^^^^^^^
按PEP8规范,Python一般限制最大79个字符,
但是Django的命名,url等通常比较长,
而且21世纪都是宽屏了,所以我们限制最大120字符
**补充说明:HTML代码不受此规范约束。**
长语句缩进
^^^^^^^^^^
编写长语句时,可以使用换行符()换行。在这种情况下,下一行应该与上一行的最后
一个“.”句点或“=”对齐,或者是缩进4个空格符
::
this_is_a_very_long(function_call, 'with many parameters') \
.that_returns_an_object_with_an_attribute
MyModel.query.filter(MyModel.scalar > 120) \
.order_by(MyModel.name.desc()) \
.limit(10)
如果你使用括号“()”或花括号“{}”为长语句换行,那么下一行应与括号或花括号对齐:
::
this_is_a_very_long(function_call, 'with many parameters',
23, 42, 'and even more')
对于元素众多的列表或元组,在第一个“[”或“(”之后马上换行:
::
items = [
'this is the first', 'set of items', 'with more items',
'to come in this line', 'like this'
]
.. _Style Guidance: http://www.pocoo.org/internal/styleguide/
空行
^^^^
顶层函数与类之间空两行,此外都只空一行。不要在代码中使用太多的空行来区分不同的逻辑模块。
::
def hello(name):
print 'Hello %s!' % name
def goodbye(name):
print 'See you %s.' % name
class MyClass(object):
"""This is a simple docstring."""
def __init__(self, name):
self.name = name
def get_annoying_name(self):
return self.name.upper() + '!!!!111'
语句和表达式
~~~~~~~~~~~~
一般空格规则
^^^^^^^^^^^^
1. 单目运算符与运算对象之间不空格(例如,-,~等),即使单目运算符位于括号内部也一样。
2. 双目运算符与运算对象之间要空格。
::
exp = -1.05
value = (item_value / item_count) * offset / exp
value = my_list[index]
value = my_dict['key']
比较
^^^^
1. 任意类型之间的比较,使用“==”和“!=”。
2. 与单例(singletons)进行比较时,使用is和is not。
3. 永远不要与True或False进行比较(例如,不要这样写:foo ==
False,而应该这样写:not foo)。
否定成员关系检查
^^^^^^^^^^^^^^^^
使用foo not in bar,而不是not foo in bar。
命名约定
~~~~~~~~
1. 类名称:采用骆驼拼写法(CamelCase),首字母缩略词保持大写不变(HTTPWriter,而不是HttpWriter)。
2. 变量名:小写_以及_下划线(lowercase_with_underscores)。
3. 方法与函数名:小写_以及_下划线(lowercase_with_underscores)。
4. 常量:大写_以及_下划线(UPPERCASE_WITH_UNDERSCORES)。
5. 预编译的正则表达式:name_re。
6. 受保护的元素以一个下划线为前缀。双下划线前缀只有定义混入类(mixin
classes)时才使用。
7. 如果使用关键词(keywords)作为类名称,应在名称后添加后置下划线(trailing
underscore)。
允许与内建变量重名,不要在变量名后添加下划线进行区分。如果函数需要访问重名的内建变量,请将内建变量重新绑定为其他名称。
8. 命名要有寓意, 不使用拼音,不使用无意义简单字母命名 (循环中计数例外 for
i in)
9. 命名缩写要谨慎, 尽量是大家认可的缩写
函数和方法的参数:
^^^^^^^^^^^^^^^^^^
1. 类方法:cls为第一个参数。
2. 实例方法:self为第一个参数。
3. property函数中使用匿名函数(lambdas)时,匿名函数的第一个参数可以用x替代,
例如:display_name = property(lambda x: x.real_name or x.username)。
文档注释(Docstring,即各方法,类的说明文档注释)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
所有文档字符串均以reStructuredText格式编写,方便Sphinx处理。文档字符串的行数不同,布局也不一样。
如果只有一行,代表字符串结束的三个引号与代表字符串开始的三个引号在同一行。
如果为多行,文档字符串中的文本紧接着代表字符串开始的三个引号编写,代表字符串结束的三个引号则自己独立成一行。
(有能力尽可能用英文, 否则请中文优雅注释)
::
def foo():
"""This is a simple docstring."""
def bar():
"""This is a longer docstring with so much information in there
that it spans three lines. In this case, the closing triple quote
is on its own line.
"""
文档字符串应分成简短摘要(尽量一行)和详细介绍。如果必要的话,摘要与详细介绍之间空一行。
模块头部
~~~~~~~~
模块文件的头部包含有utf-8编码声明(如果模块中使用了非ASCII编码的字符,建议进行声明),以及标准的文档字符串。
::
# -*- coding: utf-8 -*-
"""
package.module
~~~~~~~~~~~~~~
A brief description goes here.
:copyright: (c) YEAR by AUTHOR.
:license: LICENSE_NAME, see LICENSE_FILE for more details.
"""
注释(comment)
~~~~~~~~~~~~~
注释的规范与文档字符串编写规范类似。二者均以reStructuredText格式编写。
如果使用注释来编写类属性的文档,请在#符号后添加一个冒号“:”。
(有能力尽可能用英文, 否则请中文优雅注释)
::
class User(object):
#: the name of the user as unicode string
name = Column(String)
#: the sha1 hash of the password + inline salt
pw_hash = Column(String)
\ No newline at end of file
快速安装
==========================
Jumpserver 封装了一个All in one Docker,可以快速启动。该镜像集成了所有需要的组件,可以使用外置db和redis
Tips: 不建议在生产中使用
Docker 安装见: `Docker官方安装文档 <https://docs.docker.com/install/>`_
快速启动
```````````````
使用root命令行输入::
$ docker run -p 8080:80 -p 2222:2222 jumpserver/jumpserver:0.5.0-beta2
访问
```````````````
浏览器访问: http://localhost:8080
ssh访问: ssh -p 2222 localhost
额外环境变量
```````````````
- DB_ENGINE = mysql
- DB_HOST = mysql_host
- DB_PORT = 3306
- DB_USER = xxx
- DB_PASSWORD = xxxx
- DB_NAME = jumpserver
- REDIS_HOST = ''
- REDIS_PORT = ''
- REDIS_PASSWORD = ''
::
docker run -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 jumpserver/jumpserver:0.5.0-beta2
仓库地址
```````````````
https://github.com/jumpserver/Dockerfile
一步一步安装
--------------------------
环境
~~~~
- 系统: CentOS 7
- IP: 192.168.244.144
- 关闭 selinux和防火墙
::
# CentOS 7
$ setenforce 0 # 可以设置配置文件永久关闭
$ systemctl stop iptables.service
$ systemctl stop firewalld.service
# CentOS6
$ setenforce 0
$ service iptables stop
一. 准备Python3和Python虚拟环境
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**1.1 安装依赖包**
::
$ yum -y install wget sqlite-devel xz gcc automake zlib-devel openssl-devel epel-release
**1.2 编译安装**
::
$ wget https://www.python.org/ftp/python/3.6.1/Python-3.6.1.tar.xz
$ tar xvf Python-3.6.1.tar.xz && cd Python-3.6.1
$ ./configure && make && make install
**1.3 建立python虚拟环境**
因为CentOS
6/7自带的是Python2,而Yum等工具依赖原来的Python,为了不扰乱原来的环境我们来使用Python虚拟环境
::
$ cd /opt
$ python3 -m venv py3
$ source /opt/py3/bin/activate
# 看到下面的提示符代表成功,以后运行jumpserver都要先运行以上source命令,以下所有命令均在该虚拟环境中运行
(py3) [root@localhost py3]#
二. 安装Jumpserver 0.5.0
~~~~~~~~~~~~~~~~~~~~~~~~
**2.1 下载或clone项目**
项目提交较多git clone时较大,你可以选择去github项目页面直接下载
zip包,我的网速好,我直接clone了
::
$ cd /opt/
$ git clone --depth=1 https://github.com/jumpserver/jumpserver.git && cd jumpserver && git checkout dev
**2.2 安装依赖rpm包**
::
$ cd /opt/jumpserver/requirements
$ yum -y install $(cat rpm_requirements.txt) # 如果没有任何报错请继续
**2.3 安装python库依赖**
::
$ pip install -r requirements.txt # 不要指定-i参数,因为镜像上可能没有最新的包,如果没有任何报错请继续
**2.4 安装Redis, jumpserver使用redis做cache和celery broker**
::
$ yum -y install redis
$ service redis start
**2.5 安装MySQL**
本教程使用mysql作为数据库,如果不使用mysql可以跳过相关mysql安装和配置
::
# centos7
$ yum -y install mariadb mariadb-devel mariadb-server # centos7下安装的是mariadb
$ service mariadb start
# centos6
$ yum -y install mysql mysql-devel mysql-server
$ service mysqld start
**2.6 创建数据库 jumpserver并授权**
::
$ mysql
> create database jumpserver default charset 'utf8';
> grant all on jumpserver.* to 'jumpserver'@'127.0.0.1' identified by 'somepassword';
**2.7 修改jumpserver配置文件**
::
$ cd /opt/jumpserver
$ cp config_example.py config.py
$ vi config.py # 我们计划修改 DevelopmentConfig中的配置,因为默认jumpserver是使用该配置,它继承自Config
**注意: 配置文件是python格式,不要用tab,而要用空格** **注意:
配置文件是python格式,不要用tab,而要用空格** **注意:
配置文件是python格式,不要用tab,而要用空格**
::
class DevelopmentConfig(Config):
DEBUG = True
DB_ENGINE = 'mysql'
DB_HOST = '127.0.0.1'
DB_PORT = 3306
DB_USER = 'jumpserver'
DB_PASSWORD = 'somepassword'
DB_NAME = 'jumpserver'
...
config = DevelopmentConfig() # 确保使用的是刚才设置的配置文件
**2.8 生成数据库表结构和初始化数据**
::
$ cd /opt/jumpserver/utils
$ bash make_migrations.sh
**2.9 运行Jumpserver**
::
$ cd /opt/jumpserver
$ python run_server.py all
运行不报错,请浏览器访问 http://192.168.244.144:8080/
(这里只是jumpserver, 没有web terminal,所以访问web terminal会报错)
账号:admin 密码: admin
三. 安装 SSH Server和Web Socket Server: Coco
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**3.1 下载clone项目**
新开一个终端,连接测试机,别忘了 source /opt/py3/bin/activate
::
$ cd /opt
$ git clone https://github.com/jumpserver/coco.git && cd coco && git checkout dev
**3.2 安装依赖**
::
$ cd /opt/coco/requirements $ yum -y install $(cat rpm_requirements.txt) $ pip install requirements.txt
**3.2 安装依赖**
::
$ cd /opt/coco/requirements
$ yum -y install $(cat rpm_requirements.txt)
$ pip install -r requirements.txt
**3.3 查看配置文件并运行**
::
$ cd /opt/coco
$ cp conf_example.py conf.py
$ python run_server.py
这时需要去
jumpserver管理后台-终端-终端(http://192.168.244.144:8080/terminal/terminal/)接受coco的注册
::
Coco version 0.4.0, more see https://www.jumpserver.org
Starting ssh server at 0.0.0.0:2222
Quit the server with CONTROL-C.
**3.4 测试连接**
::
$ ssh -p2222 admin@192.168.244.144
密码: admin
如果是用在windows下,Xshell terminal登录语法如下
$ssh admin@192.168.244.144 2222
密码: admin
如果能登陆代表部署成功
四. 安装 Web Terminal 前端: Luna
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Luna已改为纯前端,需要nginx来运行访问
下载 release包,直接解压,不需要编译
访问 https://github.com/jumpserver/luna/releases,下载对应release包
4.1 解压luna
::
$ pwd
/opt/
$ tar xvf luna.tar.gz
$ ls /opt/luna
...
五. 安装Windows支持组件
~~~~~~~~~~~~~~~~~~~~~~~
使用docker启动 guacamole
.. code:: shell
docker run \
-p 8080:8080 \
-e JUMPSERVER_SERVER=http://<jumpserver>:8080 \
jumpserver/guacamole
这里所需要注意的是guacamole暴露出来的端口是8080,若与jumpserver部署在同一主机上自定义一下。
修改JUMPSERVER_SERVER的配置,填上jumpserver的内网地址
六. 配置 nginx 整合各组件
~~~~~~~~~~~~~~~~~~~~~~~~~
6.1 安装nginx 根据喜好选择安装方式和版本
6.2 配置文件
::
server {
listen 80;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location /luna/ {
try_files $uri / /index.html;
alias /opt/luna/;
}
location /media/ {
add_header Content-Encoding gzip;
root /opt/jumpserver/data/;
}
location /static/ {
root /opt/jumpserver/data/;
}
location /socket.io/ {
proxy_pass http://localhost:5000/socket.io/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /guacamole/ {
proxy_pass http://<guacamole>:8080/;
}
location / {
proxy_pass http://localhost:8080;
}
}
6.3 运行 nginx
6.4 访问 http://192.168.244.144
\ No newline at end of file
升级
----
1. 升级 jumpserver
::
$ git pull && pip install -r requirements/requirements.txt && cd utils && sh make_migrations.sh
2. 升级 coco
::
$ git pull && cd requirements && pip install -r requirements.txt # 不要指定 -i参数
3. 升级 luna
重新下载release包
\ No newline at end of file
个人资产
=========
这里介绍用户个人资产相关的功能。
.. contents:: Topics
.. _view_personal_assets:
查看个人资产
````````````
登录个人用户,默认展示个人资产列表。点击主机名,查看资产的详细信息。
.. _host_login:
主机登录
`````````
点解页面左侧的"Web终端",进入主机登录页,然后点击页面右侧的主机IP地址,连接主机,页面右侧会展示当前连接的终端信息。
.. _host_logout:
主机登出
`````````
在主机登录页面,选择左上角的“服务器”按钮,出现两个选项,一个“断开链接“按钮,断开当前连接的主机;另一个”断开所有链接“,断开当前所有连接的主机。
\ No newline at end of file
用户使用文档
=============
这部分给您介绍Jumpserver的用户管理模块的使用方法。
.. toctree::
:maxdepth: 1
user_asset
user_info
\ No newline at end of file
个人信息
=========
这里介绍个人信息相关的功能。
.. contents:: Topics
.. _view_personal_info:
查看个人信息
````````````
点击页面左侧的“个人信息”,查看用户的个人信息、SSH密钥。
.. _modify_personal_info:
修改个人信息
````````````
在个人信息页,点击页面右上角的“设置”按钮,进入个人信息修改页面,填写个人信息,点击“提交”按钮,完成个人信息修改。
.. _update_password:
更新密码
`````````
在个人信息页,点击页面右上角的“重置密码“按钮,进入密码更新页面,填写原来密码、新密码等信息,点击“提交”按钮,完成密码更新。
.. _update_ssh_key:
密钥更新
`````````
在个人信息页,点击页面左上角的“重置SSH密钥“按钮,进入密钥更新页面,填写SSH公钥,点击“提交”按钮,完成密钥更新。
\ No newline at end of file
...@@ -56,8 +56,8 @@ uritemplate==3.0.0 ...@@ -56,8 +56,8 @@ uritemplate==3.0.0
urllib3==1.22 urllib3==1.22
vine==1.1.4 vine==1.1.4
gunicorn==19.7.1 gunicorn==19.7.1
https://github.com/celery/django-celery-beat/zipball/master#egg=django-celery-beat #https://github.com/celery/django-celery-beat/zipball/master#egg=django-celery-beat
#django_celery_beat==1.1.0 django_celery_beat==1.1.1
ephem==3.7.6.0 ephem==3.7.6.0
python-gssapi==0.6.4 python-gssapi==0.6.4
jms-es-sdk jms-es-sdk
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment