diff --git a/apps/applications/templates/applications/remote_app_create_update.html b/apps/applications/templates/applications/remote_app_create_update.html
index ecd7254a1..897126f98 100644
--- a/apps/applications/templates/applications/remote_app_create_update.html
+++ b/apps/applications/templates/applications/remote_app_create_update.html
@@ -107,6 +107,21 @@ function hiddenFields(){
});
$('.' + app_type + '-fields').removeClass('hidden');
}
+function constructParams(data) {
+ var typeList = ['chrome', 'mysql_workbench', 'vmware_client', 'custom'];
+ var params = {};
+ for (var type in typeList){
+ if (data.type === type){
+ for (var k in data){
+ if (k.startsWith(data.type)){
+ params[k] = data[k]
+ }
+ }
+ break
+ }
+ }
+ return params;
+}
$(document).ready(function () {
$('.select2').select2({
closeOnSelect: true
@@ -118,6 +133,28 @@ $(document).ready(function () {
.on('change', app_type_id, function(){
hiddenFields();
setDefaultValue();
-});
+})
+.on("submit", "form", function (evt) {
+ evt.preventDefault();
+ var the_url = '{% url "api-applications:remote-app-list" %}';
+ var redirect_to = '{% url "applications:remote-app-list" %}';
+ var method = "POST";
+ {% if type == "update" %}
+ the_url = '{% url "api-applications:remote-app-detail" object.id %}';
+ method = "PUT";
+ {% endif %}
+ var form = $("form");
+ var data = form.serializeObject();
+ data["params"] = constructParams(data);
+ var props = {
+ url: the_url,
+ data: data,
+ method: method,
+ form: form,
+ redirect_to: redirect_to
+ };
+ formSubmit(props);
+ })
+;
{% endblock %}
\ No newline at end of file
diff --git a/apps/applications/views/remote_app.py b/apps/applications/views/remote_app.py
index 5576ed3bb..e7f6f0ccd 100644
--- a/apps/applications/views/remote_app.py
+++ b/apps/applications/views/remote_app.py
@@ -46,6 +46,7 @@ class RemoteAppCreateView(PermissionsMixin, SuccessMessageMixin, CreateView):
context = {
'app': _('Applications'),
'action': _('Create RemoteApp'),
+ 'type': 'create'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@@ -68,6 +69,7 @@ class RemoteAppUpdateView(PermissionsMixin, SuccessMessageMixin, UpdateView):
context = {
'app': _('Applications'),
'action': _('Update RemoteApp'),
+ 'type': 'update'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
diff --git a/apps/assets/api/label.py b/apps/assets/api/label.py
index eb8594e4a..d3537b20c 100644
--- a/apps/assets/api/label.py
+++ b/apps/assets/api/label.py
@@ -13,11 +13,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from rest_framework_bulk import BulkModelViewSet
from rest_framework.pagination import LimitOffsetPagination
from django.db.models import Count
from common.utils import get_logger
+from orgs.mixins import OrgBulkModelViewSet
from ..hands import IsOrgAdmin
from ..models import Label
from .. import serializers
@@ -27,7 +27,7 @@ logger = get_logger(__file__)
__all__ = ['LabelViewSet']
-class LabelViewSet(BulkModelViewSet):
+class LabelViewSet(OrgBulkModelViewSet):
filter_fields = ("name", "value")
search_fields = filter_fields
permission_classes = (IsOrgAdmin,)
diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py
index 51f9a8739..2478303d0 100644
--- a/apps/assets/api/node.py
+++ b/apps/assets/api/node.py
@@ -131,7 +131,7 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
if not include_assets:
return queryset
assets = self.node.get_assets().only(
- "id", "hostname", "ip", 'platform', "os", "org_id",
+ "id", "hostname", "ip", 'platform', "os", "org_id", "protocols",
)
for asset in assets:
queryset.append(asset.as_tree_node(self.node))
diff --git a/apps/assets/forms/asset.py b/apps/assets/forms/asset.py
index 5973f731b..a044988ab 100644
--- a/apps/assets/forms/asset.py
+++ b/apps/assets/forms/asset.py
@@ -29,9 +29,9 @@ class ProtocolForm(forms.Form):
class AssetCreateForm(OrgModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- if not self.data:
- nodes_field = self.fields['nodes']
- nodes_field._queryset = Node.get_queryset()
+ nodes_field = self.fields['nodes']
+ nodes_field.choices = ((n.id, n.full_value) for n in
+ Node.get_queryset())
class Meta:
model = Asset
diff --git a/apps/assets/migrations/0035_auto_20190711_2018.py b/apps/assets/migrations/0035_auto_20190711_2018.py
new file mode 100644
index 000000000..9dcbad1db
--- /dev/null
+++ b/apps/assets/migrations/0035_auto_20190711_2018.py
@@ -0,0 +1,34 @@
+# Generated by Django 2.1.7 on 2019-07-11 12:18
+
+import common.fields.model
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('assets', '0034_auto_20190705_1348'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='adminuser',
+ name='private_key',
+ field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
+ ),
+ migrations.AlterField(
+ model_name='authbook',
+ name='private_key',
+ field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
+ ),
+ migrations.AlterField(
+ model_name='gateway',
+ name='private_key',
+ field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
+ ),
+ migrations.AlterField(
+ model_name='systemuser',
+ name='private_key',
+ field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
+ ),
+ ]
diff --git a/apps/assets/models/asset.py b/apps/assets/models/asset.py
index a37aa16b1..2161113e2 100644
--- a/apps/assets/models/asset.py
+++ b/apps/assets/models/asset.py
@@ -6,7 +6,8 @@ import uuid
import logging
import random
from functools import reduce
-from collections import OrderedDict
+from collections import OrderedDict, defaultdict
+from django.core.cache import cache
from django.db import models
from django.utils.translation import ugettext_lazy as _
@@ -96,7 +97,53 @@ class ProtocolsMixin:
return self.protocols_as_dict.get("ssh", 22)
-class Asset(ProtocolsMixin, OrgModelMixin):
+class NodesRelationMixin:
+ NODES_CACHE_KEY = 'ASSET_NODES_{}'
+ ALL_ASSET_NODES_CACHE_KEY = 'ALL_ASSETS_NODES'
+ CACHE_TIME = 3600 * 24 * 7
+ id = ""
+ _all_nodes_keys = None
+
+ @classmethod
+ def get_all_nodes_keys(cls):
+ """
+ :return: {asset.id: [node.key, ]}
+ """
+ from .node import Node
+ cache_key = cls.ALL_ASSET_NODES_CACHE_KEY
+ cached = cache.get(cache_key)
+ if cached:
+ return cached
+ assets = Asset.objects.all().only('id').prefetch_related(
+ models.Prefetch('nodes', queryset=Node.objects.all().only('key'))
+ )
+ assets_nodes_keys = {}
+ for asset in assets:
+ assets_nodes_keys[asset.id] = [n.key for n in asset.nodes.all()]
+ cache.set(cache_key, assets_nodes_keys, cls.CACHE_TIME)
+ return assets_nodes_keys
+
+ @classmethod
+ def expire_all_nodes_keys_cache(cls):
+ cache_key = cls.ALL_ASSET_NODES_CACHE_KEY
+ cache.delete(cache_key)
+
+ def get_nodes(self):
+ from .node import Node
+ nodes = self.nodes.all() or [Node.root()]
+ return nodes
+
+ def get_all_nodes(self, flat=False):
+ nodes = []
+ for node in self.get_nodes():
+ _nodes = node.get_ancestor(with_self=True)
+ nodes.append(_nodes)
+ if flat:
+ nodes = list(reduce(lambda x, y: set(x) | set(y), nodes))
+ return nodes
+
+
+class Asset(ProtocolsMixin, NodesRelationMixin, OrgModelMixin):
# Important
PLATFORM_CHOICES = (
('Linux', 'Linux'),
@@ -182,20 +229,6 @@ class Asset(ProtocolsMixin, OrgModelMixin):
def is_support_ansible(self):
return self.has_protocol('ssh') and self.platform not in ("Other",)
- def get_nodes(self):
- from .node import Node
- nodes = self.nodes.all() or [Node.root()]
- return nodes
-
- def get_all_nodes(self, flat=False):
- nodes = []
- for node in self.get_nodes():
- _nodes = node.get_ancestor(with_self=True)
- nodes.append(_nodes)
- if flat:
- nodes = list(reduce(lambda x, y: set(x) | set(y), nodes))
- return nodes
-
@property
def cpu_info(self):
info = ""
diff --git a/apps/assets/models/base.py b/apps/assets/models/base.py
index b372bc9fd..75f81917f 100644
--- a/apps/assets/models/base.py
+++ b/apps/assets/models/base.py
@@ -28,7 +28,7 @@ class AssetUser(OrgModelMixin):
name = models.CharField(max_length=128, verbose_name=_('Name'))
username = models.CharField(max_length=32, blank=True, verbose_name=_('Username'), validators=[alphanumeric])
password = fields.EncryptCharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
- private_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
+ private_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH private key'))
public_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH public key'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_("Date created"))
diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py
index aab5ebaf4..d668cea51 100644
--- a/apps/assets/models/node.py
+++ b/apps/assets/models/node.py
@@ -212,14 +212,12 @@ class AssetsAmountMixin:
if cached is not None:
return cached
assets_amount = self.get_all_assets().count()
- self.assets_amount = assets_amount
+ cache.set(cache_key, assets_amount, self.cache_time)
return assets_amount
@assets_amount.setter
def assets_amount(self, value):
self._assets_amount = value
- cache_key = self._assets_amount_cache_key.format(self.key)
- cache.set(cache_key, value, self.cache_time)
def expire_assets_amount(self):
ancestor_keys = self.get_ancestor_keys(with_self=True)
diff --git a/apps/assets/models/user.py b/apps/assets/models/user.py
index 32f569b80..bbd808b80 100644
--- a/apps/assets/models/user.py
+++ b/apps/assets/models/user.py
@@ -117,16 +117,6 @@ class SystemUser(AssetUser):
def __str__(self):
return '{0.name}({0.username})'.format(self)
- def to_json(self):
- return {
- 'id': self.id,
- 'name': self.name,
- 'username': self.username,
- 'protocol': self.protocol,
- 'priority': self.priority,
- 'auto_push': self.auto_push,
- }
-
@property
def login_mode_display(self):
return self.get_login_mode_display()
diff --git a/apps/assets/serializers/admin_user.py b/apps/assets/serializers/admin_user.py
index b05de01f6..0efc09801 100644
--- a/apps/assets/serializers/admin_user.py
+++ b/apps/assets/serializers/admin_user.py
@@ -21,19 +21,15 @@ class AdminUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
model = AdminUser
fields = [
'id', 'name', 'username', 'password', 'private_key', 'public_key',
- 'comment', 'connectivity_amount', 'assets_amount',
- 'date_created', 'date_updated', 'created_by',
+ 'comment', 'assets_amount', 'date_created', 'date_updated', 'created_by',
]
+ read_only_fields = ['date_created', 'date_updated', 'created_by', 'assets_amount']
extra_kwargs = {
'password': {"write_only": True},
'private_key': {"write_only": True},
'public_key': {"write_only": True},
- 'date_created': {'read_only': True},
- 'date_updated': {'read_only': True},
- 'created_by': {'read_only': True},
'assets_amount': {'label': _('Asset')},
- 'connectivity_amount': {'label': _('Connectivity')},
}
diff --git a/apps/assets/serializers/cmd_filter.py b/apps/assets/serializers/cmd_filter.py
index e5ab62037..dfdff2cdb 100644
--- a/apps/assets/serializers/cmd_filter.py
+++ b/apps/assets/serializers/cmd_filter.py
@@ -10,13 +10,19 @@ from orgs.mixins import BulkOrgResourceModelSerializer
class CommandFilterSerializer(BulkOrgResourceModelSerializer):
- rules = serializers.PrimaryKeyRelatedField(queryset=CommandFilterRule.objects.all(), many=True)
- system_users = serializers.PrimaryKeyRelatedField(queryset=SystemUser.objects.all(), many=True)
class Meta:
model = CommandFilter
list_serializer_class = AdaptedBulkListSerializer
- fields = '__all__'
+ fields = [
+ 'id', 'name', 'org_id', 'org_name', 'is_active', 'comment',
+ 'created_by', 'date_created', 'date_updated', 'rules', 'system_users'
+ ]
+
+ extra_kwargs = {
+ 'rules': {'read_only': True},
+ 'system_users': {'read_only': True}
+ }
class CommandFilterRuleSerializer(BulkOrgResourceModelSerializer):
diff --git a/apps/assets/serializers/domain.py b/apps/assets/serializers/domain.py
index cda208b9f..68feccb41 100644
--- a/apps/assets/serializers/domain.py
+++ b/apps/assets/serializers/domain.py
@@ -6,6 +6,7 @@ from common.serializers import AdaptedBulkListSerializer
from orgs.mixins import BulkOrgResourceModelSerializer
from ..models import Domain, Gateway
+from .base import AuthSerializerMixin
class DomainSerializer(BulkOrgResourceModelSerializer):
@@ -14,7 +15,11 @@ class DomainSerializer(BulkOrgResourceModelSerializer):
class Meta:
model = Domain
- fields = '__all__'
+ fields = [
+ 'id', 'name', 'asset_count', 'gateway_count', 'comment', 'assets',
+ 'date_created'
+ ]
+ read_only_fields = ( 'asset_count', 'gateway_count', 'date_created')
list_serializer_class = AdaptedBulkListSerializer
@staticmethod
@@ -26,14 +31,14 @@ class DomainSerializer(BulkOrgResourceModelSerializer):
return obj.gateway_set.all().count()
-class GatewaySerializer(BulkOrgResourceModelSerializer):
+class GatewaySerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
class Meta:
model = Gateway
list_serializer_class = AdaptedBulkListSerializer
fields = [
- 'id', 'name', 'ip', 'port', 'protocol', 'username',
- 'domain', 'is_active', 'date_created', 'date_updated',
- 'created_by', 'comment',
+ 'id', 'name', 'ip', 'port', 'protocol', 'username', 'password',
+ 'private_key', 'public_key', 'domain', 'is_active', 'date_created',
+ 'date_updated', 'created_by', 'comment',
]
diff --git a/apps/assets/serializers/label.py b/apps/assets/serializers/label.py
index 526580216..a20c43a11 100644
--- a/apps/assets/serializers/label.py
+++ b/apps/assets/serializers/label.py
@@ -13,7 +13,13 @@ class LabelSerializer(BulkOrgResourceModelSerializer):
class Meta:
model = Label
- fields = '__all__'
+ fields = [
+ 'id', 'name', 'value', 'category', 'is_active', 'comment',
+ 'date_created', 'asset_count', 'assets', 'get_category_display'
+ ]
+ read_only_fields = (
+ 'category', 'date_created', 'asset_count', 'get_category_display'
+ )
list_serializer_class = AdaptedBulkListSerializer
@staticmethod
diff --git a/apps/assets/serializers/node.py b/apps/assets/serializers/node.py
index b33f22116..ea4aa7355 100644
--- a/apps/assets/serializers/node.py
+++ b/apps/assets/serializers/node.py
@@ -17,9 +17,8 @@ class NodeSerializer(BulkOrgResourceModelSerializer):
class Meta:
model = Node
- fields = [
- 'id', 'key', 'value', 'assets_amount', 'org_id',
- ]
+ only_fields = ['id', 'key', 'value', 'org_id']
+ fields = only_fields + ['assets_amount']
read_only_fields = [
'key', 'assets_amount', 'org_id',
]
diff --git a/apps/assets/serializers/system_user.py b/apps/assets/serializers/system_user.py
index d853984e2..70855c9f7 100644
--- a/apps/assets/serializers/system_user.py
+++ b/apps/assets/serializers/system_user.py
@@ -21,14 +21,13 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
'id', 'name', 'username', 'password', 'public_key', 'private_key',
'login_mode', 'login_mode_display', 'priority', 'protocol',
'auto_push', 'cmd_filters', 'sudo', 'shell', 'comment', 'nodes',
- 'assets_amount', 'connectivity_amount', 'auto_generate_key'
+ 'assets_amount', 'auto_generate_key'
]
extra_kwargs = {
'password': {"write_only": True},
'public_key': {"write_only": True},
'private_key': {"write_only": True},
'assets_amount': {'label': _('Asset')},
- 'connectivity_amount': {'label': _('Connectivity')},
'login_mode_display': {'label': _('Login mode display')},
'created_by': {'read_only': True},
}
diff --git a/apps/assets/signals_handler.py b/apps/assets/signals_handler.py
index 59d01c98a..b2316d7d0 100644
--- a/apps/assets/signals_handler.py
+++ b/apps/assets/signals_handler.py
@@ -78,6 +78,7 @@ def on_system_user_assets_change(sender, instance=None, **kwargs):
@receiver(m2m_changed, sender=Asset.nodes.through)
def on_asset_node_changed(sender, instance=None, **kwargs):
logger.debug("Asset nodes change signal received")
+ Asset.expire_all_nodes_keys_cache()
if isinstance(instance, Asset):
if kwargs['action'] == 'pre_remove':
nodes = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
diff --git a/apps/assets/templates/assets/_asset_user_auth_view_modal.html b/apps/assets/templates/assets/_asset_user_auth_view_modal.html
index 6fbd48fcd..417e1021d 100644
--- a/apps/assets/templates/assets/_asset_user_auth_view_modal.html
+++ b/apps/assets/templates/assets/_asset_user_auth_view_modal.html
@@ -70,7 +70,7 @@ function showAuth() {
var msg = "{% trans 'Get auth info error' %}";
toastr.error(msg)
};
- APIUpdateAttr({
+ requestApi({
url: url,
method: "GET",
success: success,
diff --git a/apps/assets/templates/assets/_asset_user_list.html b/apps/assets/templates/assets/_asset_user_list.html
index 381aec13d..f76754391 100644
--- a/apps/assets/templates/assets/_asset_user_list.html
+++ b/apps/assets/templates/assets/_asset_user_list.html
@@ -141,7 +141,7 @@ $(document).ready(function(){
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
diff --git a/apps/assets/templates/assets/_node_tree.html b/apps/assets/templates/assets/_node_tree.html
index 93aed7d89..9a4004060 100644
--- a/apps/assets/templates/assets/_node_tree.html
+++ b/apps/assets/templates/assets/_node_tree.html
@@ -235,7 +235,7 @@ function onRename(event, treeId, treeNode, isCancel){
if (isCancel){
return
}
- APIUpdateAttr({
+ requestApi({
url: url,
body: JSON.stringify(data),
method: "PATCH",
@@ -274,7 +274,7 @@ function onDrop(event, treeId, treeNodes, targetNode, moveType) {
var the_url = "{% url 'api-assets:node-add-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", targetNode.meta.node.id);
var body = {nodes: treeNodesIds};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: "PUT",
body: JSON.stringify(body)
@@ -291,42 +291,6 @@ function defaultCallback(action) {
$(document).ready(function () {
})
-.on('click', '.btn-refresh-hardware', function () {
- var url = "{% url 'api-assets:node-refresh-hardware-info' pk=DEFAULT_PK %}";
- var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
- function success(data) {
- rMenu.css({"visibility" : "hidden"});
- var task_id = data.task;
- var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
- window.open(url, '', 'width=800,height=600')
- }
- APIUpdateAttr({
- url: the_url,
- method: "GET",
- success: success,
- flash_message: false
- });
-
-})
-.on('click', '.btn-test-connective', function () {
- var url = "{% url 'api-assets:node-test-connective' pk=DEFAULT_PK %}";
- if (!current_node_id) {
- return null;
- }
- var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
- function success(data) {
- rMenu.css({"visibility" : "hidden"});
- var task_id = data.task;
- var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
- window.open(url, '', 'width=800,height=600')
- }
- APIUpdateAttr({
- url: the_url,
- method: "GET",
- success: success,
- flash_message: false
- });
-})
.on('click', '.btn-show-current-asset', function(){
hideRMenu();
$(this).css('display', 'none');
@@ -341,17 +305,5 @@ $(document).ready(function () {
setCookie('show_current_asset', '');
location.reload();
})
-.on('click', '.btn-test-connective', function () {
- hideRMenu();
-})
-.on('click', '#menu_refresh_assets_amount', function () {
- hideRMenu();
- var url = "{% url 'api-assets:refresh-assets-amount' %}";
- APIUpdateAttr({
- 'url': url,
- 'method': 'GET'
- });
- window.location.reload();
-})
\ No newline at end of file
diff --git a/apps/assets/templates/assets/_system_user.html b/apps/assets/templates/assets/_system_user.html
index ef78187b5..5cc3e04ba 100644
--- a/apps/assets/templates/assets/_system_user.html
+++ b/apps/assets/templates/assets/_system_user.html
@@ -228,6 +228,7 @@ $(document).ready(function () {
var form = $("form");
var data = form.serializeObject();
+ objectAttrsIsList(data, ['cmd_filters']);
objectAttrsIsBool(data, ["auto_generate_key", "auto_push"]);
data["private_key"] = $("#id_private_key_file").data('file');
diff --git a/apps/assets/templates/assets/admin_user_assets.html b/apps/assets/templates/assets/admin_user_assets.html
index 7c97259ab..9ca433930 100644
--- a/apps/assets/templates/assets/admin_user_assets.html
+++ b/apps/assets/templates/assets/admin_user_assets.html
@@ -88,7 +88,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
diff --git a/apps/assets/templates/assets/admin_user_detail.html b/apps/assets/templates/assets/admin_user_detail.html
index f00e2352a..9e3365509 100644
--- a/apps/assets/templates/assets/admin_user_detail.html
+++ b/apps/assets/templates/assets/admin_user_detail.html
@@ -131,7 +131,7 @@ function replaceNodeAssetsAdminUser(nodes) {
// clear jumpserver.groups_selected
jumpserver.nodes_selected = {};
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
diff --git a/apps/assets/templates/assets/admin_user_list.html b/apps/assets/templates/assets/admin_user_list.html
index 0a17eccaa..61389ad08 100644
--- a/apps/assets/templates/assets/admin_user_list.html
+++ b/apps/assets/templates/assets/admin_user_list.html
@@ -2,8 +2,6 @@
{% load i18n static %}
{% block help_message %}
-{# 管理用户是资产(被控服务器)上的root,或拥有 NOPASSWD: ALL sudo权限的用户,Jumpserver使用该用户来 `推送系统用户`、`获取资产硬件信息`等。#}
-{# Windows或其它硬件可以随意设置一个#}
{% trans 'Admin users are asset (charged server) on the root, or have NOPASSWD: ALL sudo permissions users, '%}
{% trans 'Jumpserver users of the system using the user to `push system user`, `get assets hardware information`, etc. '%}
{% trans 'You can set any one for Windows or other hardware.' %}
@@ -47,9 +45,9 @@
{% trans 'Name' %} |
{% trans 'Username' %} |
{% trans 'Asset' %} |
-
{% trans 'Reachable' %} |
-
{% trans 'Unreachable' %} |
-
{% trans 'Ratio' %} |
+{#
{% trans 'Reachable' %} | #}
+{#
{% trans 'Unreachable' %} | #}
+{#
{% trans 'Ratio' %} | #}
{% trans 'Comment' %} |
{% trans 'Action' %} |
@@ -73,44 +71,44 @@ function initTable() {
var detail_btn = '
' + cellData + '';
return detail_btn.replace('{{ DEFAULT_PK }}', rowData.id);
}},
- {targets: 4, createdCell: function (td, cellData) {
- var innerHtml = "";
- var data = cellData.reachable;
- if (data !== 0) {
- innerHtml = "
" + data + "";
- } else {
- innerHtml = "
" + data + "";
- }
- $(td).html(innerHtml)
- }},
- {targets: 5, createdCell: function (td, cellData) {
- var data = cellData.unreachable;
- var innerHtml = "";
- if (data !== 0) {
- innerHtml = "
" + data + "";
- } else {
- innerHtml = "
" + data + "";
- }
- $(td).html('
' + innerHtml + '');
- }},
- {targets: 6, createdCell: function (td, cellData, rowData) {
- var val = 0;
- var innerHtml = "";
- var total = rowData.assets_amount;
- var reachable = cellData.reachable;
- if (total !== 0) {
- val = reachable/total * 100;
- }
-
- if (val === 100) {
- innerHtml = "
" + val + "% ";
- } else {
- var num = new Number(val);
- innerHtml = "
" + num.toFixed(1) + "% ";
- }
- $(td).html('
' + innerHtml + '');
- }},
- {targets: 8, createdCell: function (td, cellData, rowData) {
+ {#{targets: 4, createdCell: function (td, cellData) {#}
+ {# var innerHtml = "";#}
+ {# var data = cellData.reachable;#}
+ {# if (data !== 0) {#}
+ {# innerHtml = "
" + data + "";#}
+ {# } else {#}
+ {# innerHtml = "
" + data + "";#}
+ {# }#}
+ {# $(td).html(innerHtml)#}
+ {#}},#}
+ {#{targets: 5, createdCell: function (td, cellData) {#}
+ {# var data = cellData.unreachable;#}
+ {# var innerHtml = "";#}
+ {# if (data !== 0) {#}
+ {# innerHtml = "
" + data + "";#}
+ {# } else {#}
+ {# innerHtml = "
" + data + "";#}
+ {# }#}
+ {# $(td).html('
' + innerHtml + '');#}
+ {#}},#}
+ {#{targets: 6, createdCell: function (td, cellData, rowData) {#}
+ {# var val = 0;#}
+ {# var innerHtml = "";#}
+ {# var total = rowData.assets_amount;#}
+ {# var reachable = cellData.reachable;#}
+ {# if (total !== 0) {#}
+ {# val = reachable/total * 100;#}
+ {# }#}
+ {##}
+ {# if (val === 100) {#}
+ {# innerHtml = "
" + val + "% ";#}
+ {# } else {#}
+ {# var num = new Number(val);#}
+ {# innerHtml = "
" + num.toFixed(1) + "% ";#}
+ {# }#}
+ {# $(td).html('
' + innerHtml + '');#}
+ {#}},#}
+ {targets: 5, createdCell: function (td, cellData, rowData) {
var update_btn = '
{% trans "Update" %}'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '
{% trans "Delete" %}'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn)
@@ -118,7 +116,7 @@ function initTable() {
ajax_url: '{% url "api-assets:admin-user-list" %}',
columns: [
{data: function(){return ""}}, {data: "name"}, {data: "username" }, {data: "assets_amount" },
- {data: "connectivity_amount"}, {data: "connectivity_amount"}, {data: "connectivity_amount"},
+ {#{data: "connectivity_amount"}, {data: "connectivity_amount"}, {data: "connectivity_amount"},#}
{data: "comment"}, {data: "id"}
]
};
diff --git a/apps/assets/templates/assets/asset_asset_user_list.html b/apps/assets/templates/assets/asset_asset_user_list.html
index 39e4816b9..bf3cba583 100644
--- a/apps/assets/templates/assets/asset_asset_user_list.html
+++ b/apps/assets/templates/assets/asset_asset_user_list.html
@@ -84,7 +84,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
diff --git a/apps/assets/templates/assets/asset_create.html b/apps/assets/templates/assets/asset_create.html
index 15e75971e..1b5636be5 100644
--- a/apps/assets/templates/assets/asset_create.html
+++ b/apps/assets/templates/assets/asset_create.html
@@ -137,7 +137,6 @@ $(document).ready(function () {
protocolRef.val(protocolShould);
protocolRef.trigger("change")
}
-
})
.on("click", ".btn-protocol.btn-del", function () {
$(this).parent().parent().remove();
diff --git a/apps/assets/templates/assets/asset_detail.html b/apps/assets/templates/assets/asset_detail.html
index ad635ca5b..760cc7e6d 100644
--- a/apps/assets/templates/assets/asset_detail.html
+++ b/apps/assets/templates/assets/asset_detail.html
@@ -70,7 +70,7 @@
{% trans 'Protocol' %} |
- {{ asset.protocols }} |
+ {{ asset.protocols }} |
{% trans 'Admin user' %}: |
@@ -267,7 +267,7 @@ function updateAssetNodes(nodes) {
// clear jumpserver.groups_selected
jumpserver.nodes_selected = {};
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
@@ -282,7 +282,7 @@ function refreshAssetHardware() {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
success: success,
method: 'GET'
@@ -306,7 +306,7 @@ $(document).ready(function () {
};
var success = '{% trans "Update successfully!" %}';
var status = $(".ibox-content > table > tbody > tr:nth-child(13) > td:last >b").text();
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success_message: success
@@ -360,7 +360,7 @@ $(document).ready(function () {
window.open(url, '', 'width=800,height=600')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success
diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html
index 3b9df3373..0cdcb176a 100644
--- a/apps/assets/templates/assets/asset_list.html
+++ b/apps/assets/templates/assets/asset_list.html
@@ -167,7 +167,7 @@ function initTable() {
}},
{targets: 5, createdCell: function (td, cellData, rowData) {
var update_btn = '{% trans "Update" %}'.replace("{{ DEFAULT_PK }}", cellData);
- var del_btn = '{% trans "Delete" %}'.replace('{{ DEFAULT_PK }}', cellData);
+ var del_btn = '{% trans "Delete" %}'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn)
}}
],
@@ -325,8 +325,7 @@ $(document).ready(function(){
}
window.open(url, '_self');
})
-
-.on('click', '.btn_asset_delete', function () {
+.on('click', '.btn-asset-delete', function () {
var $this = $(this);
var $data_table = $("#asset_list_table").DataTable();
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
@@ -361,7 +360,7 @@ $(document).ready(function(){
setTimeout( function () {
window.location.reload();}, 500);
}
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'PATCH',
body: JSON.stringify(data),
@@ -378,7 +377,7 @@ $(document).ready(function(){
setTimeout( function () {
window.location.reload();}, 300);
}
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'PATCH',
body: JSON.stringify(data),
@@ -398,7 +397,7 @@ $(document).ready(function(){
},function () {
function success(data) {
url = setUrlParam(the_url, 'spm', data.spm);
- APIUpdateAttr({
+ requestApi({
url:url,
method:'DELETE',
success:refreshTag,
@@ -411,7 +410,7 @@ $(document).ready(function(){
var msg = "{% trans 'Asset Deleting failed.' %}";
swal("{% trans 'Asset Delete' %}", msg, "error");
}
- APIUpdateAttr({
+ requestApi({
url: "{% url 'api-common:resources-cache' %}",
method:'POST',
body:JSON.stringify(data),
@@ -429,7 +428,7 @@ $(document).ready(function(){
var url = "{% url 'assets:asset-bulk-update' %}";
location.href= setUrlParam(url, 'spm', data.spm);
}
- APIUpdateAttr({
+ requestApi({
url: "{% url 'api-common:resources-cache' %}",
method:'POST',
body:JSON.stringify(data),
@@ -453,7 +452,7 @@ $(document).ready(function(){
asset_table.ajax.reload()
};
- APIUpdateAttr({
+ requestApi({
'url': '/api/assets/v1/nodes/' + current_node_id + '/assets/remove/',
'method': 'PUT',
'body': JSON.stringify(data),
@@ -501,7 +500,7 @@ $(document).ready(function(){
url = "{% url 'api-assets:node-add-assets' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
}
- APIUpdateAttr({
+ requestApi({
'url': url,
'method': 'PUT',
'body': JSON.stringify(data),
@@ -513,6 +512,40 @@ $(document).ready(function(){
update_node_action = "add"
}).on('click', '#menu_asset_move', function () {
update_node_action = "move"
+}).on('click', '.btn-test-connective', function () {
+ var url = "{% url 'api-assets:node-test-connective' pk=DEFAULT_PK %}";
+ if (!current_node_id) {
+ return null;
+ }
+ var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
+ function success(data) {
+ rMenu.css({"visibility" : "hidden"});
+ var task_id = data.task;
+ var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
+ window.open(url, '', 'width=800,height=600')
+ }
+ requestApi({
+ url: the_url,
+ method: "GET",
+ success: success,
+ flash_message: false
+ });
+}).on('click', '.btn-refresh-hardware', function () {
+ var url = "{% url 'api-assets:node-refresh-hardware-info' pk=DEFAULT_PK %}";
+ var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
+ function success(data) {
+ rMenu.css({"visibility" : "hidden"});
+ var task_id = data.task;
+ var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
+ window.open(url, '', 'width=800,height=600')
+ }
+ requestApi({
+ url: the_url,
+ method: "GET",
+ success: success,
+ flash_message: false
+ });
+
})
diff --git a/apps/assets/templates/assets/cmd_filter_create_update.html b/apps/assets/templates/assets/cmd_filter_create_update.html
index b1f7a57a8..678e1e3eb 100644
--- a/apps/assets/templates/assets/cmd_filter_create_update.html
+++ b/apps/assets/templates/assets/cmd_filter_create_update.html
@@ -18,3 +18,29 @@
{% endblock %}
+{% block custom_foot_js %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/templates/assets/cmd_filter_detail.html b/apps/assets/templates/assets/cmd_filter_detail.html
index ee68ff2f6..b98828f4e 100644
--- a/apps/assets/templates/assets/cmd_filter_detail.html
+++ b/apps/assets/templates/assets/cmd_filter_detail.html
@@ -136,7 +136,7 @@ function updateCMDFilterSystemUsers(system_users) {
var success = function(data) {
location.reload();
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
method: 'PATCH',
diff --git a/apps/assets/templates/assets/cmd_filter_rule_create_update.html b/apps/assets/templates/assets/cmd_filter_rule_create_update.html
index 9b240bd74..2edaa97dc 100644
--- a/apps/assets/templates/assets/cmd_filter_rule_create_update.html
+++ b/apps/assets/templates/assets/cmd_filter_rule_create_update.html
@@ -70,5 +70,25 @@ $(document).ready(function(){
content_help_ref.html(content_origin_help_text);
}
})
+.on("submit", "form", function (evt) {
+ evt.preventDefault();
+ var form = $("form");
+ var data = form.serializeObject();
+ var the_url = '{% url "api-assets:cmd-filter-rule-list" filter_pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", data.filter);
+ var redirect_to = '{% url "assets:cmd-filter-rule-list" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", data.filter);
+ var method = "POST";
+ {% if request_type == "update" %}
+ the_url = '{% url "api-assets:cmd-filter-rule-detail" filter_pk=DEFAULT_PK pk=rule.id %}'.replace('{{ DEFAULT_PK }}', data.filter);
+ method = "PUT";
+ {% endif %}
+ var props = {
+ url: the_url,
+ data: data,
+ method: method,
+ form: form,
+ redirect_to: redirect_to
+ };
+ formSubmit(props);
+})
{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/templates/assets/domain_create_update.html b/apps/assets/templates/assets/domain_create_update.html
index 7a31e3e88..399b38011 100644
--- a/apps/assets/templates/assets/domain_create_update.html
+++ b/apps/assets/templates/assets/domain_create_update.html
@@ -48,5 +48,26 @@ $(document).ready(function () {
$("#asset_list_modal").modal('hide');
})
+.on("submit", "form", function (evt) {
+ evt.preventDefault();
+ var form = $("form");
+ var data = form.serializeObject();
+ var method = "POST";
+ var the_url = '{% url "api-assets:domain-list" %}';
+ var redirect_to = '{% url "assets:domain-list" %}';
+ {% if type == "update" %}
+ the_url = '{% url 'api-assets:domain-detail' pk=object.id %}';
+ method = "PUT";
+ {% endif %}
+ objectAttrsIsList(data, ['assets']);
+ var props = {
+ url:the_url,
+ data:data,
+ method:method,
+ form:form,
+ redirect_to:redirect_to
+ };
+ formSubmit(props);
+ })
{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/templates/assets/domain_gateway_list.html b/apps/assets/templates/assets/domain_gateway_list.html
index d621fb0ec..eb348141e 100644
--- a/apps/assets/templates/assets/domain_gateway_list.html
+++ b/apps/assets/templates/assets/domain_gateway_list.html
@@ -134,7 +134,7 @@ $(document).ready(function(){
var data = $("#test_gateway_form").serializeObject();
var uid = data.gateway_id;
var the_url = '{% url "api-assets:test-gateway-connective" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: "POST",
body: JSON.stringify({'port': parseInt(data.port)}),
diff --git a/apps/assets/templates/assets/gateway_create_update.html b/apps/assets/templates/assets/gateway_create_update.html
index fea540385..a22428087 100644
--- a/apps/assets/templates/assets/gateway_create_update.html
+++ b/apps/assets/templates/assets/gateway_create_update.html
@@ -95,6 +95,32 @@ function protocolChange() {
$(document).ready(function(){
protocolChange();
})
+.on("submit", "form", function (evt) {
+ evt.preventDefault();
+ var form = $("form");
+ var data = form.serializeObject();
+ data["private_key"] = $("#id_private_key_file").data('file');
+ var method = "POST";
+ var the_url = '{% url "api-assets:gateway-list" %}';
+ var redirect_to = '{% url "assets:domain-gateway-list" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", data.domain);
+ {% if type == "update" %}
+ the_url = '{% url 'api-assets:gateway-detail' pk=object.id %}';
+ method = "PUT";
+ {% endif %}
+ var props = {
+ url:the_url,
+ data:data,
+ method:method,
+ form:form,
+ redirect_to:redirect_to
+ };
+ formSubmit(props);
+})
+.on('change', '#id_private_key_file', function () {
+ readFile($(this)).on("onload", function (evt, data) {
+ $(this).attr("data-file", data)
+ })
+})
.on('change', protocol_id, function(){
protocolChange();
});
diff --git a/apps/assets/templates/assets/label_create_update.html b/apps/assets/templates/assets/label_create_update.html
index d55bb8827..a6b9582a5 100644
--- a/apps/assets/templates/assets/label_create_update.html
+++ b/apps/assets/templates/assets/label_create_update.html
@@ -51,5 +51,26 @@ $(document).ready(function () {
$('#id_assets').val(assets).trigger('change');
$("#asset_list_modal").modal('hide');
})
+.on("submit", "form", function (evt) {
+ evt.preventDefault();
+ var the_url = '{% url 'api-assets:label-list' %}';
+ var redirect_to = '{% url "assets:label-list" %}';
+ var method = "POST";
+ {% if type == "update" %}
+ the_url = '{% url 'api-assets:label-detail' pk=object.id %}';
+ method = "PUT";
+ {% endif %}
+ var form = $("form");
+ var data = form.serializeObject();
+ objectAttrsIsList(data, ['assets']);
+ var props = {
+ url: the_url,
+ data: data,
+ method: method,
+ form: form,
+ redirect_to: redirect_to
+ };
+ formSubmit(props);
+})
{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/templates/assets/system_user_assets.html b/apps/assets/templates/assets/system_user_assets.html
index 546111130..5818e4ce6 100644
--- a/apps/assets/templates/assets/system_user_assets.html
+++ b/apps/assets/templates/assets/system_user_assets.html
@@ -146,7 +146,7 @@ function updateSystemUserNode(nodes) {
// clear jumpserver.nodes_selected
jumpserver.nodes_selected = {};
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
@@ -206,7 +206,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
error: error,
method: 'GET',
@@ -226,7 +226,7 @@ $(document).ready(function () {
var error = function (data) {
alert(data)
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
@@ -243,7 +243,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
error: error,
method: 'GET',
diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html
index 55f625d81..d9ff1a641 100644
--- a/apps/assets/templates/assets/system_user_detail.html
+++ b/apps/assets/templates/assets/system_user_detail.html
@@ -212,7 +212,7 @@ function updateCommandFilters(command_filters) {
var success = function(data) {
location.reload();
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
@@ -235,7 +235,7 @@ $(document).ready(function () {
var body = {
'auto_push': checked
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body)
});
@@ -254,7 +254,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
@@ -268,7 +268,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
diff --git a/apps/assets/templates/assets/system_user_list.html b/apps/assets/templates/assets/system_user_list.html
index 680bfa421..621e18201 100644
--- a/apps/assets/templates/assets/system_user_list.html
+++ b/apps/assets/templates/assets/system_user_list.html
@@ -53,9 +53,9 @@
{% trans 'Protocol' %} |
{% trans 'Login mode' %} |
{% trans 'Asset' %} |
- {% trans 'Reachable' %} |
- {% trans 'Unreachable' %} |
- {% trans 'Ratio' %} |
+{# {% trans 'Reachable' %} | #}
+{# {% trans 'Unreachable' %} | #}
+{# {% trans 'Ratio' %} | #}
{% trans 'Comment' %} |
{% trans 'Action' %} |
@@ -78,44 +78,44 @@ function initTable() {
var detail_btn = '
' + cellData + '';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
- {targets: 6, createdCell: function (td, cellData) {
- var innerHtml = "";
- var data = cellData.reachable;
- if (data !== 0) {
- innerHtml = "
" + data + "";
- } else {
- innerHtml = "
" + data + "";
- }
- $(td).html(innerHtml)
- }},
- {targets: 7, createdCell: function (td, cellData) {
- var data = cellData.unreachable;
- var innerHtml = "";
- if (data !== 0) {
- innerHtml = "
" + data + "";
- } else {
- innerHtml = "
" + data + "";
- }
- $(td).html('
' + innerHtml + '');
- }},
- {targets: 8, createdCell: function (td, cellData, rowData) {
- var val = 0;
- var innerHtml = "";
- var total = rowData.assets_amount;
- var reachable = cellData.reachable;
- if (total && total !== 0) {
- val = reachable/total * 100;
- }
-
- if (val === 100) {
- innerHtml = "
" + val + "% ";
- } else {
- var num = new Number(val);
- innerHtml = "
" + num.toFixed(1) + "% ";
- }
- $(td).html('
' + innerHtml + '');
- }},
- {targets: 10, createdCell: function (td, cellData, rowData) {
+ {#{targets: 6, createdCell: function (td, cellData) {#}
+ {# var innerHtml = "";#}
+ {# var data = cellData.reachable;#}
+ {# if (data !== 0) {#}
+ {# innerHtml = "
" + data + "";#}
+ {# } else {#}
+ {# innerHtml = "
" + data + "";#}
+ {# }#}
+ {# $(td).html(innerHtml)#}
+ {#}},#}
+ {#{targets: 7, createdCell: function (td, cellData) {#}
+ {# var data = cellData.unreachable;#}
+ {# var innerHtml = "";#}
+ {# if (data !== 0) {#}
+ {# innerHtml = "
" + data + "";#}
+ {# } else {#}
+ {# innerHtml = "
" + data + "";#}
+ {# }#}
+ {# $(td).html('
' + innerHtml + '');#}
+ {#}},#}
+ {#{targets: 8, createdCell: function (td, cellData, rowData) {#}
+ {# var val = 0;#}
+ {# var innerHtml = "";#}
+ {# var total = rowData.assets_amount;#}
+ {# var reachable = cellData.reachable;#}
+ {# if (total && total !== 0) {#}
+ {# val = reachable/total * 100;#}
+ {# }#}
+ {##}
+ {# if (val === 100) {#}
+ {# innerHtml = "
" + val + "% ";#}
+ {# } else {#}
+ {# var num = new Number(val);#}
+ {# innerHtml = "
" + num.toFixed(1) + "% ";#}
+ {# }#}
+ {# $(td).html('
' + innerHtml + '');#}
+ {#}},#}
+ {targets: 7, createdCell: function (td, cellData, rowData) {
var update_btn = '
{% trans "Update" %}'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '
{% trans "Delete" %}'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn)
@@ -124,7 +124,7 @@ function initTable() {
ajax_url: '{% url "api-assets:system-user-list" %}',
columns: [
{data: "id" }, {data: "name" }, {data: "username" }, {data: "protocol"}, {data: "login_mode_display"}, {data: "assets_amount" },
- {data: "connectivity_amount"}, {data: "connectivity_amount"}, {data: "connectivity_amount"}, {data: "comment" }, {data: "id" }
+ {data: "comment" }, {data: "id" }
],
op_html: $('#actions').html()
};
@@ -182,7 +182,7 @@ $(document).ready(function(){
swal("{% trans 'System Users Delete' %}", msg, "error");
};
var url_delete = the_url + '?id__in=' + JSON.stringify(plain_id_list);
- APIUpdateAttr({url: url_delete, method: 'DELETE', success: success, error: fail});
+ requestApi({url: url_delete, method: 'DELETE', success: success, error: fail});
$data_table.ajax.reload();
jumpserver.checked = false;
});
diff --git a/apps/assets/templates/assets/user_asset_list.html b/apps/assets/templates/assets/user_asset_list.html
index 23d0b34ed..d021df0d7 100644
--- a/apps/assets/templates/assets/user_asset_list.html
+++ b/apps/assets/templates/assets/user_asset_list.html
@@ -11,48 +11,7 @@
{% block content %}
-
-
+ {% include 'users/_granted_assets.html' %}
@@ -62,130 +21,52 @@
{% block custom_foot_js %}
-
{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/utils.py b/apps/assets/utils.py
index b64fea35e..be8a80351 100644
--- a/apps/assets/utils.py
+++ b/apps/assets/utils.py
@@ -1,7 +1,8 @@
# ~*~ coding: utf-8 ~*~
#
import time
-from django.db.models import Prefetch
+from functools import reduce
+from django.db.models import Prefetch, Q
from common.utils import get_object_or_none, get_logger
from common.struct import Stack
@@ -21,24 +22,34 @@ def get_system_user_by_id(id):
return system_user
-class LabelFilter:
- def filter_queryset(self, queryset):
- queryset = super().filter_queryset(queryset)
- query_keys = self.request.query_params.keys()
+class LabelFilterMixin:
+ def get_filter_labels_ids(self):
+ query_params = self.request.query_params
+ query_keys = query_params.keys()
all_label_keys = Label.objects.values_list('name', flat=True)
valid_keys = set(all_label_keys) & set(query_keys)
- labels_query = {}
- for key in valid_keys:
- labels_query[key] = self.request.query_params.get(key)
- conditions = []
- for k, v in labels_query.items():
- query = {'labels__name': k, 'labels__value': v}
- conditions.append(query)
+ if not valid_keys:
+ return []
- if conditions:
- for kwargs in conditions:
- queryset = queryset.filter(**kwargs)
+ labels_query = [
+ {"name": key, "value": query_params[key]}
+ for key in valid_keys
+ ]
+ args = [Q(**kwargs) for kwargs in labels_query]
+ args = reduce(lambda x, y: x | y, args)
+ labels_id = Label.objects.filter(args).values_list('id', flat=True)
+ return labels_id
+
+
+class LabelFilter(LabelFilterMixin):
+ def filter_queryset(self, queryset):
+ queryset = super().filter_queryset(queryset)
+ labels_ids = self.get_filter_labels_ids()
+ if not labels_ids:
+ return queryset
+ for labels_id in labels_ids:
+ queryset = queryset.filter(labels=labels_id)
return queryset
@@ -104,7 +115,7 @@ class NodeUtil:
_node._assets_amount = len(_node._assets)
delattr(_node, '_assets')
self.stack.top._children.append(_node)
- self.stack.top._all_children.extend([_node] + _node._children)
+ self.stack.top._all_children.extend([_node] + _node._all_children)
def init(self):
all_nodes = self.get_all_nodes()
@@ -145,29 +156,69 @@ class NodeUtil:
def nodes(self):
return list(self._nodes.values())
+ def get_family_by_key(self, key):
+ tree_nodes = set()
+ node = self.get_node_by_key(key)
+ if not node:
+ return []
+ tree_nodes.update(node._parents)
+ tree_nodes.add(node)
+ tree_nodes.update(node._all_children)
+ return list(tree_nodes)
+
# 使用给定节点生成一颗树
# 找到他们的祖先节点
# 可选找到他们的子孙节点
- def get_family(self, nodes, with_children=False):
- tree_nodes = set()
- for n in nodes:
- node = self.get_node_by_key(n.key)
- if not node:
- continue
- tree_nodes.update(node._parents)
- tree_nodes.add(node)
- if with_children:
- tree_nodes.update(node._children)
- return list(tree_nodes)
+ def get_family(self, node):
+ return self.get_family_by_key(node.key)
- def get_nodes_parents(self, nodes, with_self=True):
+ def get_family_keys_by_key(self, key):
+ nodes = self.get_family_by_key(key)
+ return [n.key for n in nodes]
+
+ def get_some_nodes_family_by_keys(self, keys):
+ family = set()
+ for key in keys:
+ family.update(self.get_family_by_key(key))
+ return family
+
+ def get_some_nodes_family_keys_by_keys(self, keys):
+ family = self.get_some_nodes_family_by_keys(keys)
+ return [n.key for n in family]
+
+ def get_nodes_parents_by_key(self, key, with_self=True):
parents = set()
- for n in nodes:
- node = self.get_node_by_key(n.key)
- parents.update(set(node._parents))
- if with_self:
- parents.add(node)
- return parents
+ node = self.get_node_by_key(key)
+ if not node:
+ return []
+ parents.update(set(node._parents))
+ if with_self:
+ parents.add(node)
+ return list(parents)
+
+ def get_node_parents(self, node, with_self=True):
+ return self.get_nodes_parents_by_key(node.key, with_self=with_self)
+
+ def get_nodes_parents_keys_by_key(self, key, with_self=True):
+ nodes = self.get_nodes_parents_by_key(key, with_self=with_self)
+ return [n.key for n in nodes]
+
+ def get_all_children_by_key(self, key, with_self=True):
+ children = set()
+ node = self.get_node_by_key(key)
+ if not node:
+ return []
+ children.update(set(node._all_children))
+ if with_self:
+ children.add(node)
+ return list(children)
+
+ def get_children(self, node, with_self=True):
+ return self.get_all_children_by_key(node.key, with_self=with_self)
+
+ def get_children_keys_by_key(self, key, with_self=True):
+ nodes = self.get_all_children_by_key(key, with_self=with_self)
+ return [n.key for n in nodes]
def test_node_tree():
diff --git a/apps/assets/views/asset.py b/apps/assets/views/asset.py
index ce701b129..40601d27f 100644
--- a/apps/assets/views/asset.py
+++ b/apps/assets/views/asset.py
@@ -69,7 +69,7 @@ class UserAssetListView(PermissionsMixin, TemplateView):
context = {
'action': _('My assets'),
'labels': Label.objects.all().order_by('name'),
- 'system_users': SystemUser.objects.all(),
+ 'show_actions': True
}
kwargs.update(context)
return super().get_context_data(**kwargs)
diff --git a/apps/assets/views/cmd_filter.py b/apps/assets/views/cmd_filter.py
index 354c1d852..530f4193b 100644
--- a/apps/assets/views/cmd_filter.py
+++ b/apps/assets/views/cmd_filter.py
@@ -47,6 +47,7 @@ class CommandFilterCreateView(PermissionsMixin, CreateView):
context = {
'app': _('Assets'),
'action': _('Create command filter'),
+ 'type': 'create'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@@ -64,6 +65,7 @@ class CommandFilterUpdateView(PermissionsMixin, UpdateView):
context = {
'app': _('Assets'),
'action': _('Update command filter'),
+ 'type': 'update'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@@ -136,6 +138,7 @@ class CommandFilterRuleCreateView(PermissionsMixin, CreateView):
'app': _('Assets'),
'action': _('Create command filter rule'),
'object': self.cmd_filter,
+ 'request_type': 'create'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@@ -170,6 +173,8 @@ class CommandFilterRuleUpdateView(PermissionsMixin, UpdateView):
'app': _('Assets'),
'action': _('Update command filter rule'),
'object': self.cmd_filter,
+ 'rule': self.get_object(),
+ 'request_type': 'update'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
\ No newline at end of file
diff --git a/apps/assets/views/domain.py b/apps/assets/views/domain.py
index 797bae1f4..7b4dcfcce 100644
--- a/apps/assets/views/domain.py
+++ b/apps/assets/views/domain.py
@@ -46,6 +46,7 @@ class DomainCreateView(PermissionsMixin, CreateView):
context = {
'app': _('Assets'),
'action': _('Create domain'),
+ 'type': 'create'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@@ -63,6 +64,7 @@ class DomainUpdateView(PermissionsMixin, UpdateView):
context = {
'app': _('Assets'),
'action': _('Update domain'),
+ 'type': 'update'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@@ -132,6 +134,7 @@ class DomainGatewayCreateView(PermissionsMixin, CreateView):
context = {
'app': _('Assets'),
'action': _('Create gateway'),
+ 'type': 'create'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@@ -152,6 +155,7 @@ class DomainGatewayUpdateView(PermissionsMixin, UpdateView):
context = {
'app': _('Assets'),
'action': _('Update gateway'),
+ "type": "update"
}
kwargs.update(context)
return super().get_context_data(**kwargs)
diff --git a/apps/assets/views/label.py b/apps/assets/views/label.py
index b53a5d040..522962ce3 100644
--- a/apps/assets/views/label.py
+++ b/apps/assets/views/label.py
@@ -44,6 +44,7 @@ class LabelCreateView(PermissionsMixin, CreateView):
context = {
'app': _('Assets'),
'action': _('Create label'),
+ 'type': 'create'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@@ -71,6 +72,7 @@ class LabelUpdateView(PermissionsMixin, UpdateView):
context = {
'app': _('Assets'),
'action': _('Update label'),
+ 'type': 'update'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
diff --git a/apps/authentication/templates/authentication/_mfa_confirm_modal.html b/apps/authentication/templates/authentication/_mfa_confirm_modal.html
index 0d7b794bb..60512d7de 100644
--- a/apps/authentication/templates/authentication/_mfa_confirm_modal.html
+++ b/apps/authentication/templates/authentication/_mfa_confirm_modal.html
@@ -38,7 +38,7 @@ $(document).ready(function () {
var error = function () {
$("#mfa_error").addClass("text-danger").html(codeError);
};
- APIUpdateAttr({
+ requestApi({
url: url,
method: "POST",
body: JSON.stringify(data),
diff --git a/apps/common/api.py b/apps/common/api.py
index bf41312d7..a3b1938be 100644
--- a/apps/common/api.py
+++ b/apps/common/api.py
@@ -4,11 +4,13 @@ import os
import uuid
from django.core.cache import cache
+from django.views.decorators.csrf import csrf_exempt
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import generics, serializers
+from .http import HttpResponseTemporaryRedirect
from .const import KEY_CACHE_RESOURCES_ID
__all__ = [
@@ -86,3 +88,11 @@ class ResourcesIDCacheApi(APIView):
cache_key = KEY_CACHE_RESOURCES_ID.format(spm)
cache.set(cache_key, resources_id, 300)
return Response({'spm': spm})
+
+
+@csrf_exempt
+def redirect_plural_name_api(request, *args, **kwargs):
+ resource = kwargs.get("resource", "")
+ full_path = request.get_full_path()
+ full_path = full_path.replace(resource, resource+"s", 1)
+ return HttpResponseTemporaryRedirect(full_path)
diff --git a/apps/common/http.py b/apps/common/http.py
new file mode 100644
index 000000000..df6b9a78f
--- /dev/null
+++ b/apps/common/http.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+#
+from django.http import HttpResponse
+from django.utils.encoding import iri_to_uri
+
+
+class HttpResponseTemporaryRedirect(HttpResponse):
+ status_code = 307
+
+ def __init__(self, redirect_to):
+ HttpResponse.__init__(self)
+ self['Location'] = iri_to_uri(redirect_to)
diff --git a/apps/common/permissions.py b/apps/common/permissions.py
index edb5ee4d0..bdc25fe21 100644
--- a/apps/common/permissions.py
+++ b/apps/common/permissions.py
@@ -145,13 +145,13 @@ class NeedMFAVerify(permissions.BasePermission):
return False
-class CanUpdateSuperUser(permissions.BasePermission):
+class CanUpdateDeleteSuperUser(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in ['GET', 'OPTIONS']:
return True
- if str(request.user.id) == str(obj.id):
+ elif request.method == 'DELETE' and str(request.user.id) == str(obj.id):
return False
- if request.user.is_superuser:
+ elif request.user.is_superuser:
return True
if hasattr(obj, 'is_superuser') and obj.is_superuser:
return False
diff --git a/apps/common/tree.py b/apps/common/tree.py
index 13756a35d..e73b43aa6 100644
--- a/apps/common/tree.py
+++ b/apps/common/tree.py
@@ -46,12 +46,17 @@ class TreeNode:
def __gt__(self, other):
if self.isParent and not other.isParent:
- return False
+ result = False
elif not self.isParent and other.isParent:
- return True
- if self.pId != other.pId:
- return self.pId > other.pId
- return self.name > other.name
+ result = True
+ elif self.pId != other.pId:
+ result = self.pId > other.pId
+ else:
+ result = self.name > other.name
+ return result
+
+ def __le__(self, other):
+ return not self.__gt__(other)
def __eq__(self, other):
return self.id == other.id
@@ -74,7 +79,7 @@ class Tree:
raise ValueError("Parent must not be node parent")
node.pId = parent.id
parent.isParent = True
- self.nodes[node.id] = node
+ self.nodes[node.key] = node
def get_nodes(self):
return sorted(self.nodes.values())
diff --git a/apps/common/utils/common.py b/apps/common/utils/common.py
index fdd4827d3..c0bd771e4 100644
--- a/apps/common/utils/common.py
+++ b/apps/common/utils/common.py
@@ -7,6 +7,7 @@ import logging
import datetime
import uuid
from functools import wraps
+import time
import copy
import ipaddress
@@ -179,3 +180,18 @@ def random_string(length):
charset = string.ascii_letters + string.digits
s = [random.choice(charset) for i in range(length)]
return ''.join(s)
+
+
+logger = get_logger(__name__)
+
+
+def timeit(func):
+ def wrapper(*args, **kwargs):
+ logger.debug("Start call: {}".format(func.__name__))
+ now = time.time()
+ result = func(*args, **kwargs)
+ using = (time.time() - now) * 1000
+ msg = "Call {} end, using: {:.1f}ms".format(func.__name__, using)
+ logger.debug(msg)
+ return result
+ return wrapper
diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py
index 17d660be8..ce43c13b1 100644
--- a/apps/jumpserver/conf.py
+++ b/apps/jumpserver/conf.py
@@ -359,6 +359,7 @@ defaults = {
'TERMINAL_TELNET_REGEX': '',
'TERMINAL_COMMAND_STORAGE': {},
'SECURITY_MFA_AUTH': False,
+ 'SECURITY_SERVICE_ACCOUNT_REGISTRATION': True,
'SECURITY_LOGIN_LIMIT_COUNT': 7,
'SECURITY_LOGIN_LIMIT_TIME': 30,
'SECURITY_MAX_IDLE_TIME': 30,
diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py
index 35ffebc25..6ee9f7a74 100644
--- a/apps/jumpserver/settings.py
+++ b/apps/jumpserver/settings.py
@@ -568,7 +568,7 @@ SECURITY_PASSWORD_RULES = [
'SECURITY_PASSWORD_SPECIAL_CHAR'
]
SECURITY_MFA_VERIFY_TTL = CONFIG.SECURITY_MFA_VERIFY_TTL
-
+SECURITY_SERVICE_ACCOUNT_REGISTRATION = CONFIG.SECURITY_SERVICE_ACCOUNT_REGISTRATION
TERMINAL_PASSWORD_AUTH = CONFIG.TERMINAL_PASSWORD_AUTH
TERMINAL_PUBLIC_KEY_AUTH = CONFIG.TERMINAL_PUBLIC_KEY_AUTH
TERMINAL_HEARTBEAT_INTERVAL = CONFIG.TERMINAL_HEARTBEAT_INTERVAL
diff --git a/apps/jumpserver/views.py b/apps/jumpserver/views.py
index 7f7662add..9ad8f7b39 100644
--- a/apps/jumpserver/views.py
+++ b/apps/jumpserver/views.py
@@ -2,7 +2,7 @@ import datetime
import re
import time
-from django.http import HttpResponse, HttpResponseRedirect
+from django.http import HttpResponseRedirect
from django.conf import settings
from django.views.generic import TemplateView, View
from django.utils import timezone
@@ -13,13 +13,14 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
-from django.utils.encoding import iri_to_uri
+
from users.models import User
from assets.models import Asset
from terminal.models import Session
from orgs.utils import current_org
from common.permissions import PermissionsMixin, IsValidUser
+from common.http import HttpResponseTemporaryRedirect
class IndexView(PermissionsMixin, TemplateView):
@@ -203,14 +204,6 @@ class I18NView(View):
api_url_pattern = re.compile(r'^/api/(?P
\w+)/(?P\w+)/(?P.*)$')
-class HttpResponseTemporaryRedirect(HttpResponse):
- status_code = 307
-
- def __init__(self, redirect_to):
- HttpResponse.__init__(self)
- self['Location'] = iri_to_uri(redirect_to)
-
-
@csrf_exempt
def redirect_format_api(request, *args, **kwargs):
_path, query = request.path, request.GET.urlencode()
diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo
index 3ca6363f6..9dc31d0c8 100644
Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ
diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po
index 8406a09cd..1da5e158c 100644
--- a/apps/locale/zh/LC_MESSAGES/django.po
+++ b/apps/locale/zh/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-07-08 15:32+0800\n"
+"POT-Creation-Date: 2019-07-15 14:43+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler \n"
"Language-Team: Jumpserver team\n"
@@ -76,17 +76,17 @@ msgstr "运行参数"
#: applications/templates/applications/remote_app_list.html:22
#: applications/templates/applications/user_remote_app_list.html:18
#: assets/forms/domain.py:15 assets/forms/label.py:13
-#: assets/models/asset.py:286 assets/models/authbook.py:24
-#: assets/serializers/admin_user.py:35 assets/serializers/asset_user.py:81
+#: assets/models/asset.py:319 assets/models/authbook.py:24
+#: assets/serializers/admin_user.py:32 assets/serializers/asset_user.py:81
#: assets/serializers/system_user.py:30
-#: assets/templates/assets/admin_user_list.html:49
+#: assets/templates/assets/admin_user_list.html:47
#: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_list.html:26
#: assets/templates/assets/label_list.html:16
#: assets/templates/assets/system_user_list.html:55 audits/models.py:19
#: audits/templates/audits/ftp_log_list.html:41
#: audits/templates/audits/ftp_log_list.html:71
-#: perms/forms/asset_permission.py:68 perms/models/asset_permission.py:76
+#: perms/forms/asset_permission.py:69 perms/models/asset_permission.py:78
#: perms/templates/perms/asset_permission_create_update.html:45
#: perms/templates/perms/asset_permission_list.html:48
#: perms/templates/perms/asset_permission_list.html:117
@@ -95,7 +95,7 @@ msgstr "运行参数"
#: terminal/templates/terminal/command_list.html:66
#: terminal/templates/terminal/session_list.html:28
#: terminal/templates/terminal/session_list.html:72
-#: xpack/plugins/change_auth_plan/forms.py:114
+#: xpack/plugins/change_auth_plan/forms.py:115
#: xpack/plugins/change_auth_plan/models.py:413
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:46
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:54
@@ -112,11 +112,11 @@ msgstr "资产"
#: applications/templates/applications/remote_app_detail.html:61
#: applications/templates/applications/remote_app_list.html:23
#: applications/templates/applications/user_remote_app_list.html:19
-#: assets/models/user.py:160 assets/templates/assets/user_asset_list.html:172
+#: assets/models/user.py:150 assets/templates/assets/user_asset_list.html:52
#: audits/models.py:20 audits/templates/audits/ftp_log_list.html:49
#: audits/templates/audits/ftp_log_list.html:72
-#: perms/forms/asset_permission.py:74 perms/models/asset_permission.py:78
-#: perms/models/asset_permission.py:103
+#: perms/forms/asset_permission.py:75 perms/models/asset_permission.py:80
+#: perms/models/asset_permission.py:114
#: perms/templates/perms/asset_permission_detail.html:140
#: perms/templates/perms/asset_permission_list.html:50
#: perms/templates/perms/asset_permission_list.html:71
@@ -126,6 +126,7 @@ msgstr "资产"
#: terminal/templates/terminal/command_list.html:67
#: terminal/templates/terminal/session_list.html:29
#: terminal/templates/terminal/session_list.html:73
+#: users/templates/users/_granted_assets.html:26
#: xpack/plugins/orgs/templates/orgs/org_list.html:19
msgid "System user"
msgstr "系统用户"
@@ -139,7 +140,7 @@ msgstr "系统用户"
#: assets/models/cmd_filter.py:20 assets/models/domain.py:20
#: assets/models/group.py:20 assets/models/label.py:18
#: assets/templates/assets/admin_user_detail.html:56
-#: assets/templates/assets/admin_user_list.html:47
+#: assets/templates/assets/admin_user_list.html:45
#: assets/templates/assets/cmd_filter_detail.html:61
#: assets/templates/assets/cmd_filter_list.html:24
#: assets/templates/assets/domain_detail.html:56
@@ -166,14 +167,14 @@ msgstr "系统用户"
#: settings/templates/settings/terminal_setting.html:105 terminal/models.py:22
#: terminal/models.py:258 terminal/templates/terminal/terminal_detail.html:43
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
-#: users/models/user.py:64 users/templates/users/_select_user_modal.html:13
+#: users/models/user.py:324 users/templates/users/_select_user_modal.html:13
#: users/templates/users/user_detail.html:63
#: users/templates/users/user_group_detail.html:55
#: users/templates/users/user_group_list.html:35
#: users/templates/users/user_list.html:35
#: users/templates/users/user_profile.html:51
#: users/templates/users/user_pubkey_update.html:53
-#: xpack/plugins/change_auth_plan/forms.py:97
+#: xpack/plugins/change_auth_plan/forms.py:98
#: xpack/plugins/change_auth_plan/models.py:61
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:61
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:12
@@ -205,7 +206,7 @@ msgstr "参数"
#: applications/models/remote_app.py:43
#: applications/templates/applications/remote_app_detail.html:77
-#: assets/models/asset.py:151 assets/models/base.py:36
+#: assets/models/asset.py:198 assets/models/base.py:36
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:25
#: assets/models/cmd_filter.py:58 assets/models/group.py:21
#: assets/templates/assets/admin_user_detail.html:68
@@ -214,10 +215,10 @@ msgstr "参数"
#: assets/templates/assets/domain_detail.html:72
#: assets/templates/assets/system_user_detail.html:100
#: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:14
-#: perms/models/asset_permission.py:106 perms/models/base.py:41
+#: perms/models/asset_permission.py:117 perms/models/base.py:41
#: perms/templates/perms/asset_permission_detail.html:98
#: perms/templates/perms/remote_app_permission_detail.html:90
-#: users/models/user.py:105 users/serializers/v1.py:116
+#: users/models/user.py:365 users/serializers/v1.py:120
#: users/templates/users/user_detail.html:111
#: xpack/plugins/change_auth_plan/models.py:106
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113
@@ -229,7 +230,7 @@ msgstr "创建者"
# msgstr "创建者"
#: applications/models/remote_app.py:46
#: applications/templates/applications/remote_app_detail.html:73
-#: assets/models/asset.py:152 assets/models/base.py:34
+#: assets/models/asset.py:199 assets/models/base.py:34
#: assets/models/cluster.py:26 assets/models/domain.py:23
#: assets/models/group.py:22 assets/models/label.py:25
#: assets/templates/assets/admin_user_detail.html:64
@@ -237,7 +238,7 @@ msgstr "创建者"
#: assets/templates/assets/domain_detail.html:68
#: assets/templates/assets/system_user_detail.html:96
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:64
-#: orgs/models.py:15 perms/models/asset_permission.py:107
+#: orgs/models.py:15 perms/models/asset_permission.py:118
#: perms/models/base.py:42
#: perms/templates/perms/asset_permission_detail.html:94
#: perms/templates/perms/remote_app_permission_detail.html:86
@@ -257,12 +258,12 @@ msgstr "创建日期"
#: applications/templates/applications/remote_app_detail.html:81
#: applications/templates/applications/remote_app_list.html:24
#: applications/templates/applications/user_remote_app_list.html:20
-#: assets/models/asset.py:153 assets/models/base.py:33
+#: assets/models/asset.py:200 assets/models/base.py:33
#: assets/models/cluster.py:29 assets/models/cmd_filter.py:22
#: assets/models/cmd_filter.py:55 assets/models/domain.py:21
#: assets/models/domain.py:53 assets/models/group.py:23
#: assets/models/label.py:23 assets/templates/assets/admin_user_detail.html:72
-#: assets/templates/assets/admin_user_list.html:53
+#: assets/templates/assets/admin_user_list.html:51
#: assets/templates/assets/asset_detail.html:132
#: assets/templates/assets/cmd_filter_detail.html:65
#: assets/templates/assets/cmd_filter_list.html:27
@@ -271,15 +272,14 @@ msgstr "创建日期"
#: assets/templates/assets/domain_gateway_list.html:72
#: assets/templates/assets/domain_list.html:28
#: assets/templates/assets/system_user_detail.html:104
-#: assets/templates/assets/system_user_list.html:59
-#: assets/templates/assets/user_asset_list.html:175 ops/models/adhoc.py:43
-#: orgs/models.py:16 perms/models/asset_permission.py:108
+#: assets/templates/assets/system_user_list.html:59 ops/models/adhoc.py:43
+#: orgs/models.py:16 perms/models/asset_permission.py:119
#: perms/models/base.py:43
#: perms/templates/perms/asset_permission_detail.html:102
#: perms/templates/perms/remote_app_permission_detail.html:94
#: settings/models.py:34 terminal/models.py:32
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15
-#: users/models/user.py:97 users/templates/users/user_detail.html:127
+#: users/models/user.py:357 users/templates/users/user_detail.html:127
#: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_list.html:37
#: users/templates/users/user_profile.html:134
@@ -412,8 +412,8 @@ msgstr "详情"
#: applications/templates/applications/remote_app_list.html:56
#: assets/templates/assets/_asset_user_list.html:70
#: assets/templates/assets/admin_user_detail.html:24
-#: assets/templates/assets/admin_user_list.html:29
-#: assets/templates/assets/admin_user_list.html:114
+#: assets/templates/assets/admin_user_list.html:27
+#: assets/templates/assets/admin_user_list.html:112
#: assets/templates/assets/asset_detail.html:27
#: assets/templates/assets/asset_list.html:78
#: assets/templates/assets/asset_list.html:169
@@ -456,7 +456,7 @@ msgstr "更新"
#: applications/templates/applications/remote_app_detail.html:25
#: applications/templates/applications/remote_app_list.html:57
#: assets/templates/assets/admin_user_detail.html:28
-#: assets/templates/assets/admin_user_list.html:115
+#: assets/templates/assets/admin_user_list.html:113
#: assets/templates/assets/asset_detail.html:31
#: assets/templates/assets/asset_list.html:170
#: assets/templates/assets/cmd_filter_detail.html:33
@@ -515,15 +515,14 @@ msgstr "创建远程应用"
#: applications/templates/applications/user_remote_app_list.html:21
#: assets/models/cmd_filter.py:54
#: assets/templates/assets/_asset_user_list.html:20
-#: assets/templates/assets/admin_user_list.html:54
+#: assets/templates/assets/admin_user_list.html:52
#: assets/templates/assets/asset_list.html:100
#: assets/templates/assets/cmd_filter_list.html:28
#: assets/templates/assets/cmd_filter_rule_list.html:63
#: assets/templates/assets/domain_gateway_list.html:73
#: assets/templates/assets/domain_list.html:29
#: assets/templates/assets/label_list.html:17
-#: assets/templates/assets/system_user_list.html:60
-#: assets/templates/assets/user_asset_list.html:48 audits/models.py:38
+#: assets/templates/assets/system_user_list.html:60 audits/models.py:38
#: audits/templates/audits/operate_log_list.html:41
#: audits/templates/audits/operate_log_list.html:67
#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64
@@ -537,6 +536,7 @@ msgstr "创建远程应用"
#: settings/templates/settings/terminal_setting.html:107
#: terminal/templates/terminal/session_list.html:36
#: terminal/templates/terminal/terminal_list.html:36
+#: users/templates/users/_granted_assets.html:28
#: users/templates/users/user_group_list.html:38
#: users/templates/users/user_list.html:41
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:60
@@ -549,8 +549,8 @@ msgid "Action"
msgstr "动作"
#: applications/templates/applications/user_remote_app_list.html:57
-#: assets/templates/assets/user_asset_list.html:100
-#: perms/models/asset_permission.py:28
+#: assets/templates/assets/user_asset_list.html:31
+#: perms/models/asset_permission.py:30
msgid "Connect"
msgstr "连接"
@@ -598,42 +598,36 @@ msgid "Test if the assets under the node are connectable: {}"
msgstr "测试节点下资产是否可连接: {}"
#: assets/const.py:77 assets/models/utils.py:43
-#: assets/templates/assets/admin_user_list.html:51
-#: assets/templates/assets/system_user_list.html:57
msgid "Unreachable"
msgstr "不可达"
#: assets/const.py:78 assets/models/utils.py:44
-#: assets/templates/assets/admin_user_list.html:50
#: assets/templates/assets/asset_list.html:99
-#: assets/templates/assets/system_user_list.html:56
-#: users/templates/users/user_group_granted_asset.html:47
msgid "Reachable"
msgstr "可连接"
#: assets/const.py:79 assets/models/utils.py:45 authentication/utils.py:9
-#: xpack/plugins/license/models.py:79
+#: xpack/plugins/license/models.py:78
msgid "Unknown"
msgstr "未知"
-#: assets/forms/asset.py:24 assets/models/asset.py:117
+#: assets/forms/asset.py:24 assets/models/asset.py:164
#: assets/models/domain.py:50
#: assets/templates/assets/domain_gateway_list.html:69
-#: assets/templates/assets/user_asset_list.html:168
#: settings/templates/settings/replay_storage_create.html:59
msgid "Port"
msgstr "端口"
-#: assets/forms/asset.py:45 assets/models/asset.py:122
+#: assets/forms/asset.py:45 assets/models/asset.py:169
#: assets/models/user.py:107 assets/templates/assets/asset_detail.html:190
#: assets/templates/assets/asset_detail.html:198
#: assets/templates/assets/system_user_assets.html:83
-#: perms/models/asset_permission.py:77
+#: perms/models/asset_permission.py:79
#: xpack/plugins/change_auth_plan/models.py:72
msgid "Nodes"
msgstr "节点"
-#: assets/forms/asset.py:48 assets/forms/asset.py:83 assets/models/asset.py:126
+#: assets/forms/asset.py:48 assets/forms/asset.py:83 assets/models/asset.py:173
#: assets/models/cluster.py:19 assets/models/user.py:65
#: assets/templates/assets/asset_detail.html:76 templates/_nav.html:24
#: xpack/plugins/cloud/models.py:124
@@ -646,28 +640,28 @@ msgstr "管理用户"
#: assets/templates/assets/asset_create.html:48
#: assets/templates/assets/asset_create.html:50
#: assets/templates/assets/asset_list.html:85
-#: assets/templates/assets/user_asset_list.html:33
+#: users/templates/users/_granted_assets.html:16
#: xpack/plugins/orgs/templates/orgs/org_list.html:20
msgid "Label"
msgstr "标签"
-#: assets/forms/asset.py:54 assets/forms/asset.py:89 assets/models/asset.py:121
+#: assets/forms/asset.py:54 assets/forms/asset.py:89 assets/models/asset.py:168
#: assets/models/domain.py:26 assets/models/domain.py:52
#: assets/templates/assets/asset_detail.html:80
-#: assets/templates/assets/user_asset_list.html:173
+#: assets/templates/assets/user_asset_list.html:53
#: xpack/plugins/orgs/templates/orgs/org_list.html:17
msgid "Domain"
msgstr "网域"
#: assets/forms/asset.py:58 assets/forms/asset.py:80 assets/forms/asset.py:93
-#: assets/forms/asset.py:128 assets/models/node.py:255
+#: assets/forms/asset.py:128 assets/models/node.py:253
#: assets/templates/assets/asset_create.html:42
-#: perms/forms/asset_permission.py:71 perms/forms/asset_permission.py:78
-#: perms/models/asset_permission.py:101
+#: perms/forms/asset_permission.py:72 perms/forms/asset_permission.py:79
+#: perms/models/asset_permission.py:112
#: perms/templates/perms/asset_permission_list.html:49
#: perms/templates/perms/asset_permission_list.html:70
#: perms/templates/perms/asset_permission_list.html:120
-#: xpack/plugins/change_auth_plan/forms.py:115
+#: xpack/plugins/change_auth_plan/forms.py:116
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:55
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:15
#: xpack/plugins/cloud/models.py:123
@@ -695,13 +689,13 @@ msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,
#: assets/forms/asset.py:108 assets/forms/asset.py:112
#: assets/forms/domain.py:17 assets/forms/label.py:15
-#: perms/templates/perms/asset_permission_asset.html:88
-#: xpack/plugins/change_auth_plan/forms.py:105
+#: perms/templates/perms/asset_permission_asset.html:78
+#: xpack/plugins/change_auth_plan/forms.py:106
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:84
msgid "Select assets"
msgstr "选择资产"
-#: assets/forms/cmd_filter.py:37 assets/serializers/cmd_filter.py:34
+#: assets/forms/cmd_filter.py:37 assets/serializers/cmd_filter.py:40
msgid "Content should not be contain: {}"
msgstr "内容不能包含: {}"
@@ -719,7 +713,7 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC"
#: assets/templates/assets/_asset_user_auth_view_modal.html:21
#: assets/templates/assets/_asset_user_list.html:16
#: assets/templates/assets/admin_user_detail.html:60
-#: assets/templates/assets/admin_user_list.html:48
+#: assets/templates/assets/admin_user_list.html:46
#: assets/templates/assets/domain_gateway_list.html:71
#: assets/templates/assets/system_user_detail.html:62
#: assets/templates/assets/system_user_list.html:52 audits/models.py:94
@@ -730,11 +724,11 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC"
#: perms/templates/perms/asset_permission_user.html:55
#: perms/templates/perms/remote_app_permission_user.html:54
#: settings/templates/settings/_ldap_list_users_modal.html:37 users/forms.py:14
-#: users/models/user.py:62 users/templates/users/_select_user_modal.html:14
+#: users/models/user.py:322 users/templates/users/_select_user_modal.html:14
#: users/templates/users/user_detail.html:67
#: users/templates/users/user_list.html:36
#: users/templates/users/user_profile.html:47
-#: xpack/plugins/change_auth_plan/forms.py:99
+#: xpack/plugins/change_auth_plan/forms.py:100
#: xpack/plugins/change_auth_plan/models.py:63
#: xpack/plugins/change_auth_plan/models.py:409
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:65
@@ -769,7 +763,7 @@ msgstr "密码"
#: assets/forms/user.py:29 assets/serializers/asset_user.py:70
#: assets/templates/assets/_asset_user_auth_update_modal.html:27
-#: users/models/user.py:91
+#: users/models/user.py:351
msgid "Private key"
msgstr "ssh私钥"
@@ -809,135 +803,129 @@ msgstr "如果选择手动登录模式,用户名和密码可以不填写"
msgid "Use comma split multi command, ex: /bin/whoami,/bin/ifconfig"
msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig"
-#: assets/models/asset.py:112 assets/models/domain.py:49
+#: assets/models/asset.py:159 assets/models/domain.py:49
#: assets/serializers/asset_user.py:28
#: assets/templates/assets/_asset_list_modal.html:46
#: assets/templates/assets/_asset_user_list.html:15
#: assets/templates/assets/asset_detail.html:64
#: assets/templates/assets/asset_list.html:97
#: assets/templates/assets/domain_gateway_list.html:68
-#: assets/templates/assets/user_asset_list.html:45
-#: assets/templates/assets/user_asset_list.html:167
+#: assets/templates/assets/user_asset_list.html:49
#: audits/templates/audits/login_log_list.html:54
-#: perms/templates/perms/asset_permission_asset.html:55 settings/forms.py:140
-#: users/templates/users/user_granted_asset.html:45
-#: users/templates/users/user_group_granted_asset.html:45
+#: perms/templates/perms/asset_permission_asset.html:58 settings/forms.py:140
+#: users/templates/users/_granted_assets.html:25
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:51
msgid "IP"
msgstr "IP"
-#: assets/models/asset.py:113 assets/serializers/asset_user.py:27
+#: assets/models/asset.py:160 assets/serializers/asset_user.py:27
#: assets/templates/assets/_asset_list_modal.html:45
#: assets/templates/assets/_asset_user_auth_update_modal.html:9
#: assets/templates/assets/_asset_user_auth_view_modal.html:15
#: assets/templates/assets/_asset_user_list.html:14
#: assets/templates/assets/asset_detail.html:60
#: assets/templates/assets/asset_list.html:96
-#: assets/templates/assets/user_asset_list.html:44
-#: assets/templates/assets/user_asset_list.html:166
-#: perms/templates/perms/asset_permission_asset.html:54
+#: assets/templates/assets/user_asset_list.html:48
+#: perms/templates/perms/asset_permission_asset.html:57
#: perms/templates/perms/asset_permission_list.html:69 settings/forms.py:139
-#: users/templates/users/user_granted_asset.html:44
-#: users/templates/users/user_group_granted_asset.html:44
+#: users/templates/users/_granted_assets.html:24
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:50
msgid "Hostname"
msgstr "主机名"
-#: assets/models/asset.py:116 assets/models/domain.py:51
+#: assets/models/asset.py:163 assets/models/domain.py:51
#: assets/models/user.py:110 assets/templates/assets/asset_detail.html:72
#: assets/templates/assets/domain_gateway_list.html:70
#: assets/templates/assets/system_user_detail.html:70
#: assets/templates/assets/system_user_list.html:53
-#: assets/templates/assets/user_asset_list.html:169
#: terminal/templates/terminal/session_list.html:31
-#: terminal/templates/terminal/session_list.html:75
msgid "Protocol"
msgstr "协议"
-#: assets/models/asset.py:119 assets/serializers/asset.py:63
+#: assets/models/asset.py:166 assets/serializers/asset.py:63
#: assets/templates/assets/asset_create.html:24
+#: assets/templates/assets/user_asset_list.html:50
+#: perms/serializers/user_permission.py:38
msgid "Protocols"
msgstr "协议组"
-#: assets/models/asset.py:120 assets/templates/assets/asset_detail.html:104
-#: assets/templates/assets/user_asset_list.html:170
+#: assets/models/asset.py:167 assets/templates/assets/asset_detail.html:104
+#: assets/templates/assets/user_asset_list.html:51
msgid "Platform"
msgstr "系统平台"
-#: assets/models/asset.py:123 assets/models/cmd_filter.py:21
+#: assets/models/asset.py:170 assets/models/cmd_filter.py:21
#: assets/models/domain.py:54 assets/models/label.py:22
#: assets/templates/assets/asset_detail.html:112
-#: assets/templates/assets/user_asset_list.html:174
msgid "Is active"
msgstr "激活"
-#: assets/models/asset.py:129 assets/templates/assets/asset_detail.html:68
+#: assets/models/asset.py:176 assets/templates/assets/asset_detail.html:68
msgid "Public IP"
msgstr "公网IP"
-#: assets/models/asset.py:130 assets/templates/assets/asset_detail.html:120
+#: assets/models/asset.py:177 assets/templates/assets/asset_detail.html:120
msgid "Asset number"
msgstr "资产编号"
-#: assets/models/asset.py:133 assets/templates/assets/asset_detail.html:84
+#: assets/models/asset.py:180 assets/templates/assets/asset_detail.html:84
msgid "Vendor"
msgstr "制造商"
-#: assets/models/asset.py:134 assets/templates/assets/asset_detail.html:88
+#: assets/models/asset.py:181 assets/templates/assets/asset_detail.html:88
msgid "Model"
msgstr "型号"
-#: assets/models/asset.py:135 assets/templates/assets/asset_detail.html:116
+#: assets/models/asset.py:182 assets/templates/assets/asset_detail.html:116
msgid "Serial number"
msgstr "序列号"
-#: assets/models/asset.py:137
+#: assets/models/asset.py:184
msgid "CPU model"
msgstr "CPU型号"
-#: assets/models/asset.py:138
+#: assets/models/asset.py:185
#: xpack/plugins/license/templates/license/license_detail.html:80
msgid "CPU count"
msgstr "CPU数量"
-#: assets/models/asset.py:139
+#: assets/models/asset.py:186
msgid "CPU cores"
msgstr "CPU核数"
-#: assets/models/asset.py:140
+#: assets/models/asset.py:187
msgid "CPU vcpus"
msgstr "CPU总数"
-#: assets/models/asset.py:141 assets/templates/assets/asset_detail.html:96
+#: assets/models/asset.py:188 assets/templates/assets/asset_detail.html:96
msgid "Memory"
msgstr "内存"
-#: assets/models/asset.py:142
+#: assets/models/asset.py:189
msgid "Disk total"
msgstr "硬盘大小"
-#: assets/models/asset.py:143
+#: assets/models/asset.py:190
msgid "Disk info"
msgstr "硬盘信息"
-#: assets/models/asset.py:145 assets/templates/assets/asset_detail.html:108
-#: assets/templates/assets/user_asset_list.html:171
+#: assets/models/asset.py:192 assets/templates/assets/asset_detail.html:108
msgid "OS"
msgstr "操作系统"
-#: assets/models/asset.py:146
+#: assets/models/asset.py:193
msgid "OS version"
msgstr "系统版本"
-#: assets/models/asset.py:147
+#: assets/models/asset.py:194
msgid "OS arch"
msgstr "系统架构"
-#: assets/models/asset.py:148
+#: assets/models/asset.py:195
msgid "Hostname raw"
msgstr "主机名原始"
-#: assets/models/asset.py:150 assets/templates/assets/asset_create.html:46
+#: assets/models/asset.py:197 assets/templates/assets/asset_create.html:46
#: assets/templates/assets/asset_detail.html:227 templates/_nav.html:26
msgid "Labels"
msgstr "标签管理"
@@ -981,7 +969,7 @@ msgstr "带宽"
msgid "Contact"
msgstr "联系人"
-#: assets/models/cluster.py:22 users/models/user.py:83
+#: assets/models/cluster.py:22 users/models/user.py:343
#: users/templates/users/user_detail.html:76
msgid "Phone"
msgstr "手机"
@@ -1003,12 +991,11 @@ msgid "Operator"
msgstr "运营商"
#: assets/models/cluster.py:36 assets/models/group.py:34
-#: perms/utils/asset_permission.py:106
msgid "Default"
msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:14
-#: users/models/user.py:453
+#: users/models/user.py:451
msgid "System"
msgstr "系统"
@@ -1115,7 +1102,7 @@ msgstr "默认资产组"
#: audits/templates/audits/password_change_log_list.html:50
#: ops/templates/ops/command_execution_list.html:35
#: ops/templates/ops/command_execution_list.html:60
-#: perms/forms/asset_permission.py:62 perms/forms/remote_app_permission.py:31
+#: perms/forms/asset_permission.py:63 perms/forms/remote_app_permission.py:31
#: perms/models/base.py:36
#: perms/templates/perms/asset_permission_create_update.html:41
#: perms/templates/perms/asset_permission_list.html:46
@@ -1127,8 +1114,8 @@ msgstr "默认资产组"
#: terminal/templates/terminal/command_list.html:65
#: terminal/templates/terminal/session_list.html:27
#: terminal/templates/terminal/session_list.html:71 users/forms.py:316
-#: users/models/user.py:38 users/models/user.py:441 users/serializers/v1.py:105
-#: users/templates/users/user_group_detail.html:78
+#: users/models/user.py:121 users/models/user.py:439
+#: users/serializers/v1.py:109 users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:36 users/views/user.py:251
#: xpack/plugins/orgs/forms.py:26
#: xpack/plugins/orgs/templates/orgs/org_detail.html:113
@@ -1136,7 +1123,7 @@ msgstr "默认资产组"
msgid "User"
msgstr "用户"
-#: assets/models/label.py:19 assets/models/node.py:246
+#: assets/models/label.py:19 assets/models/node.py:244
#: assets/templates/assets/label_list.html:15 settings/models.py:30
msgid "Value"
msgstr "值"
@@ -1145,11 +1132,11 @@ msgstr "值"
msgid "Category"
msgstr "分类"
-#: assets/models/node.py:245
+#: assets/models/node.py:243
msgid "Key"
msgstr "键"
-#: assets/models/node.py:303
+#: assets/models/node.py:301
msgid "New node"
msgstr "新节点"
@@ -1171,13 +1158,13 @@ msgstr "手动登录"
#: assets/views/asset.py:57 assets/views/asset.py:106 assets/views/asset.py:133
#: assets/views/asset.py:173 assets/views/asset.py:203
#: assets/views/cmd_filter.py:31 assets/views/cmd_filter.py:48
-#: assets/views/cmd_filter.py:65 assets/views/cmd_filter.py:82
-#: assets/views/cmd_filter.py:102 assets/views/cmd_filter.py:136
-#: assets/views/cmd_filter.py:170 assets/views/domain.py:30
-#: assets/views/domain.py:47 assets/views/domain.py:64
-#: assets/views/domain.py:78 assets/views/domain.py:104
-#: assets/views/domain.py:133 assets/views/domain.py:153
-#: assets/views/label.py:27 assets/views/label.py:45 assets/views/label.py:72
+#: assets/views/cmd_filter.py:66 assets/views/cmd_filter.py:84
+#: assets/views/cmd_filter.py:104 assets/views/cmd_filter.py:138
+#: assets/views/cmd_filter.py:173 assets/views/domain.py:30
+#: assets/views/domain.py:47 assets/views/domain.py:65
+#: assets/views/domain.py:80 assets/views/domain.py:106
+#: assets/views/domain.py:135 assets/views/domain.py:156
+#: assets/views/label.py:27 assets/views/label.py:45 assets/views/label.py:73
#: assets/views/system_user.py:29 assets/views/system_user.py:46
#: assets/views/system_user.py:63 assets/views/system_user.py:79
#: templates/_nav.html:19 xpack/plugins/change_auth_plan/models.py:68
@@ -1208,12 +1195,6 @@ msgstr "登录模式"
msgid "%(value)s is not an even number"
msgstr "%(value)s is not an even number"
-#: assets/serializers/admin_user.py:36 assets/serializers/asset.py:64
-#: assets/serializers/asset_user.py:29 assets/serializers/system_user.py:31
-#: assets/templates/assets/_asset_user_list.html:18
-msgid "Connectivity"
-msgstr "连接"
-
#: assets/serializers/asset.py:21
msgid "Protocol format should {}/{}"
msgstr "协议格式 {}/{}"
@@ -1222,6 +1203,11 @@ msgstr "协议格式 {}/{}"
msgid "Protocol duplicate: {}"
msgstr "协议重复: {}"
+#: assets/serializers/asset.py:64 assets/serializers/asset_user.py:29
+#: assets/templates/assets/_asset_user_list.html:18
+msgid "Connectivity"
+msgstr "连接"
+
#: assets/serializers/asset.py:90
msgid "Hardware info"
msgstr "硬件信息"
@@ -1235,7 +1221,7 @@ msgid "Backend"
msgstr "后端"
#: assets/serializers/asset_user.py:66 users/forms.py:263
-#: users/models/user.py:94 users/templates/users/first_login.html:42
+#: users/models/user.py:354 users/templates/users/first_login.html:42
#: users/templates/users/user_password_update.html:46
#: users/templates/users/user_profile.html:68
#: users/templates/users/user_profile_update.html:43
@@ -1247,19 +1233,19 @@ msgstr "ssh公钥"
msgid "private key invalid"
msgstr "密钥不合法"
-#: assets/serializers/node.py:33
+#: assets/serializers/node.py:32
msgid "The same level node name cannot be the same"
msgstr "同级别节点名字不能重复"
-#: assets/serializers/system_user.py:32
+#: assets/serializers/system_user.py:31
msgid "Login mode display"
msgstr "登录模式显示"
-#: assets/serializers/system_user.py:67
+#: assets/serializers/system_user.py:66
msgid "* Automatic login mode must fill in the username."
msgstr "自动登录模式,必须填写用户名"
-#: assets/serializers/system_user.py:76
+#: assets/serializers/system_user.py:75
msgid "Password or private key required"
msgstr "密码或密钥密码需要一个"
@@ -1370,8 +1356,6 @@ msgstr "选择资产"
#: assets/templates/assets/_asset_group_bulk_update_modal.html:21
#: assets/templates/assets/cmd_filter_detail.html:89
#: assets/templates/assets/cmd_filter_list.html:26
-#: assets/templates/assets/user_asset_list.html:47
-#: users/templates/users/user_granted_asset.html:47
msgid "System users"
msgstr "系统用户"
@@ -1401,7 +1385,7 @@ msgid "Update asset user auth"
msgstr "更新资产用户认证信息"
#: assets/templates/assets/_asset_user_auth_update_modal.html:23
-#: xpack/plugins/change_auth_plan/forms.py:101
+#: xpack/plugins/change_auth_plan/forms.py:102
msgid "Please input password"
msgstr "请输入密码"
@@ -1490,19 +1474,19 @@ msgstr "重命名节点"
msgid "Delete node"
msgstr "删除节点"
-#: assets/templates/assets/_node_tree.html:155
+#: assets/templates/assets/_node_tree.html:154
msgid "Create node failed"
msgstr "创建节点失败"
-#: assets/templates/assets/_node_tree.html:167
+#: assets/templates/assets/_node_tree.html:166
msgid "Have child node, cancel"
msgstr "存在子节点,不能删除"
-#: assets/templates/assets/_node_tree.html:169
+#: assets/templates/assets/_node_tree.html:168
msgid "Have assets, cancel"
msgstr "存在资产,不能删除"
-#: assets/templates/assets/_node_tree.html:243
+#: assets/templates/assets/_node_tree.html:242
msgid "Rename success"
msgstr "重命名成功"
@@ -1581,15 +1565,15 @@ msgid "Replace node assets admin user with this"
msgstr "替换资产的管理员"
#: assets/templates/assets/admin_user_detail.html:91
-#: perms/templates/perms/asset_permission_asset.html:116
-#: xpack/plugins/change_auth_plan/forms.py:109
+#: perms/templates/perms/asset_permission_asset.html:103
+#: xpack/plugins/change_auth_plan/forms.py:110
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:112
msgid "Select nodes"
msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:207
-#: assets/templates/assets/asset_list.html:396
+#: assets/templates/assets/asset_list.html:395
#: assets/templates/assets/cmd_filter_detail.html:106
#: assets/templates/assets/system_user_assets.html:100
#: assets/templates/assets/system_user_detail.html:182
@@ -1611,24 +1595,24 @@ msgstr "选择节点"
msgid "Confirm"
msgstr "确认"
-#: assets/templates/assets/admin_user_list.html:7
+#: assets/templates/assets/admin_user_list.html:5
msgid ""
"Admin users are asset (charged server) on the root, or have NOPASSWD: ALL "
"sudo permissions users, "
msgstr ""
"管理用户是资产(被控服务器)上的root,或拥有 NOPASSWD: ALL sudo权限的用户,"
-#: assets/templates/assets/admin_user_list.html:8
+#: assets/templates/assets/admin_user_list.html:6
msgid ""
"Jumpserver users of the system using the user to `push system user`, `get "
"assets hardware information`, etc. "
msgstr "Jumpserver使用该用户来 `推送系统用户`、`获取资产硬件信息`等。"
-#: assets/templates/assets/admin_user_list.html:9
+#: assets/templates/assets/admin_user_list.html:7
msgid "You can set any one for Windows or other hardware."
msgstr "Windows或其它硬件可以随意设置一个"
-#: assets/templates/assets/admin_user_list.html:19
+#: assets/templates/assets/admin_user_list.html:17
#: assets/templates/assets/asset_list.html:68
#: assets/templates/assets/system_user_list.html:23
#: audits/templates/audits/login_log_list.html:85
@@ -1638,7 +1622,7 @@ msgstr "Windows或其它硬件可以随意设置一个"
msgid "Export"
msgstr "导出"
-#: assets/templates/assets/admin_user_list.html:24
+#: assets/templates/assets/admin_user_list.html:22
#: assets/templates/assets/asset_list.html:73
#: assets/templates/assets/system_user_list.html:28
#: settings/templates/settings/_ldap_list_users_modal.html:100
@@ -1649,20 +1633,13 @@ msgstr "导出"
msgid "Import"
msgstr "导入"
-#: assets/templates/assets/admin_user_list.html:39
+#: assets/templates/assets/admin_user_list.html:37
#: assets/views/admin_user.py:50
msgid "Create admin user"
msgstr "创建管理用户"
-#: assets/templates/assets/admin_user_list.html:52
-#: assets/templates/assets/system_user_list.html:58
-#: ops/templates/ops/adhoc_history.html:54
-#: ops/templates/ops/task_history.html:60
-msgid "Ratio"
-msgstr "比例"
-
-#: assets/templates/assets/admin_user_list.html:165
-#: assets/templates/assets/admin_user_list.html:196
+#: assets/templates/assets/admin_user_list.html:163
+#: assets/templates/assets/admin_user_list.html:194
#: assets/templates/assets/asset_list.html:268
#: assets/templates/assets/asset_list.html:305
#: assets/templates/assets/system_user_list.html:225
@@ -1719,8 +1696,7 @@ msgid "Date joined"
msgstr "创建日期"
#: assets/templates/assets/asset_detail.html:150
-#: assets/templates/assets/user_asset_list.html:46
-#: perms/models/asset_permission.py:104 perms/models/base.py:38
+#: perms/models/asset_permission.py:115 perms/models/base.py:38
#: perms/templates/perms/asset_permission_create_update.html:55
#: perms/templates/perms/asset_permission_detail.html:120
#: perms/templates/perms/remote_app_permission_create_update.html:54
@@ -1728,8 +1704,6 @@ msgstr "创建日期"
#: terminal/templates/terminal/terminal_list.html:34
#: users/templates/users/_select_user_modal.html:18
#: users/templates/users/user_detail.html:144
-#: users/templates/users/user_granted_asset.html:46
-#: users/templates/users/user_group_granted_asset.html:46
#: users/templates/users/user_profile.html:63
msgid "Active"
msgstr "激活中"
@@ -1807,7 +1781,7 @@ msgstr "仅显示当前节点资产"
msgid "Displays all child node assets"
msgstr "显示所有子节点资产"
-#: assets/templates/assets/asset_list.html:390
+#: assets/templates/assets/asset_list.html:389
#: assets/templates/assets/system_user_list.html:166
#: users/templates/users/user_detail.html:382
#: users/templates/users/user_detail.html:408
@@ -1818,11 +1792,11 @@ msgstr "显示所有子节点资产"
msgid "Are you sure?"
msgstr "你确认吗?"
-#: assets/templates/assets/asset_list.html:391
+#: assets/templates/assets/asset_list.html:390
msgid "This will delete the selected assets !!!"
msgstr "删除选择资产"
-#: assets/templates/assets/asset_list.html:394
+#: assets/templates/assets/asset_list.html:393
#: assets/templates/assets/system_user_list.html:170
#: settings/templates/settings/terminal_setting.html:166
#: users/templates/users/user_detail.html:386
@@ -1836,16 +1810,16 @@ msgstr "删除选择资产"
msgid "Cancel"
msgstr "取消"
-#: assets/templates/assets/asset_list.html:407
+#: assets/templates/assets/asset_list.html:406
msgid "Asset Deleted."
msgstr "已被删除"
-#: assets/templates/assets/asset_list.html:408
-#: assets/templates/assets/asset_list.html:412
+#: assets/templates/assets/asset_list.html:407
+#: assets/templates/assets/asset_list.html:411
msgid "Asset Delete"
msgstr "删除"
-#: assets/templates/assets/asset_list.html:411
+#: assets/templates/assets/asset_list.html:410
msgid "Asset Deleting failed."
msgstr "删除失败"
@@ -1895,7 +1869,7 @@ msgid "Create command filter"
msgstr "创建命令过滤器"
#: assets/templates/assets/cmd_filter_rule_list.html:33
-#: assets/views/cmd_filter.py:103
+#: assets/views/cmd_filter.py:105
msgid "Command filter rule list"
msgstr "命令过滤器规则列表"
@@ -1922,7 +1896,7 @@ msgid "Gateway list"
msgstr "网关列表"
#: assets/templates/assets/domain_gateway_list.html:56
-#: assets/views/domain.py:134
+#: assets/views/domain.py:136
msgid "Create gateway"
msgstr "创建网关"
@@ -2070,19 +2044,19 @@ msgstr "批量更新资产"
msgid "Command filter list"
msgstr "命令过滤器列表"
-#: assets/views/cmd_filter.py:66
+#: assets/views/cmd_filter.py:67
msgid "Update command filter"
msgstr "更新命令过滤器"
-#: assets/views/cmd_filter.py:83
+#: assets/views/cmd_filter.py:85
msgid "Command filter detail"
msgstr "命令过滤器详情"
-#: assets/views/cmd_filter.py:137
+#: assets/views/cmd_filter.py:139
msgid "Create command filter rule"
msgstr "创建命令过滤器规则"
-#: assets/views/cmd_filter.py:171
+#: assets/views/cmd_filter.py:174
msgid "Update command filter rule"
msgstr "更新命令过滤器规则"
@@ -2090,19 +2064,19 @@ msgstr "更新命令过滤器规则"
msgid "Domain list"
msgstr "网域列表"
-#: assets/views/domain.py:65
+#: assets/views/domain.py:66
msgid "Update domain"
msgstr "更新网域"
-#: assets/views/domain.py:79
+#: assets/views/domain.py:81
msgid "Domain detail"
msgstr "网域详情"
-#: assets/views/domain.py:105
+#: assets/views/domain.py:107
msgid "Domain gateway list"
msgstr "域网关列表"
-#: assets/views/domain.py:154
+#: assets/views/domain.py:157
msgid "Update gateway"
msgstr "创建网关"
@@ -2110,11 +2084,11 @@ msgstr "创建网关"
msgid "Label list"
msgstr "标签列表"
-#: assets/views/label.py:55
+#: assets/views/label.py:56
msgid "Tips: Avoid using label names reserved internally: {}"
msgstr "提示: 请避免使用内部预留标签名: {}"
-#: assets/views/label.py:73
+#: assets/views/label.py:74
msgid "Update label"
msgstr "更新标签"
@@ -2232,7 +2206,7 @@ msgstr "Agent"
#: audits/models.py:99 audits/templates/audits/login_log_list.html:56
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
-#: users/forms.py:175 users/models/user.py:86
+#: users/forms.py:175 users/models/user.py:346
#: users/templates/users/first_login.html:45
msgid "MFA"
msgstr "MFA"
@@ -2445,7 +2419,7 @@ msgstr "代码错误"
#: authentication/templates/authentication/login.html:27
#: authentication/templates/authentication/login_otp.html:27
#: users/templates/users/reset_password.html:25
-#: xpack/plugins/interface/models.py:39
+#: xpack/plugins/interface/models.py:36
msgid "Welcome to the Jumpserver open source fortress"
msgstr "欢迎使用Jumpserver开源堡垒机"
@@ -2650,7 +2624,7 @@ msgstr "不能包含特殊字符"
msgid "This field must be unique."
msgstr "字段必须唯一"
-#: jumpserver/views.py:190
+#: jumpserver/views.py:191
msgid ""
"Luna is a separately deployed program, you need to deploy Luna, coco, "
"configure nginx for url distribution,
If you see this page, "
@@ -2853,6 +2827,11 @@ msgstr "执行历史"
msgid "F/S/T"
msgstr "失败/成功/总"
+#: ops/templates/ops/adhoc_history.html:54
+#: ops/templates/ops/task_history.html:60
+msgid "Ratio"
+msgstr "比例"
+
#: ops/templates/ops/adhoc_history_detail.html:19 ops/views/adhoc.py:142
msgid "Run history detail"
msgstr "执行历史详情"
@@ -3005,63 +2984,71 @@ msgstr "命令执行"
msgid "Organization"
msgstr "组织"
-#: perms/forms/asset_permission.py:65 perms/forms/remote_app_permission.py:34
-#: perms/models/asset_permission.py:102 perms/models/base.py:37
+#: perms/api/mixin.py:128
+msgid "ungrouped"
+msgstr "未分组"
+
+#: perms/api/mixin.py:133
+msgid "empty"
+msgstr "空"
+
+#: perms/forms/asset_permission.py:66 perms/forms/remote_app_permission.py:34
+#: perms/models/asset_permission.py:113 perms/models/base.py:37
#: perms/templates/perms/asset_permission_list.html:47
#: perms/templates/perms/asset_permission_list.html:67
#: perms/templates/perms/asset_permission_list.html:114
#: perms/templates/perms/remote_app_permission_list.html:16
#: templates/_nav.html:14 users/forms.py:286 users/models/group.py:26
-#: users/models/user.py:70 users/templates/users/_select_user_modal.html:16
+#: users/models/user.py:330 users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:213
#: users/templates/users/user_list.html:38
#: xpack/plugins/orgs/templates/orgs/org_list.html:15
msgid "User group"
msgstr "用户组"
-#: perms/forms/asset_permission.py:81
+#: perms/forms/asset_permission.py:82
msgid ""
"Tips: The RDP protocol does not support separate controls for uploading or "
"downloading files"
msgstr "提示:RDP 协议不支持单独控制上传或下载文件"
-#: perms/forms/asset_permission.py:91 perms/forms/remote_app_permission.py:47
+#: perms/forms/asset_permission.py:92 perms/forms/remote_app_permission.py:47
msgid "User or group at least one required"
msgstr "用户和用户组至少选一个"
-#: perms/forms/asset_permission.py:100
+#: perms/forms/asset_permission.py:101
msgid "Asset or group at least one required"
msgstr "资产和节点至少选一个"
-#: perms/models/asset_permission.py:27 settings/forms.py:143
+#: perms/models/asset_permission.py:29 settings/forms.py:143
msgid "All"
msgstr "全部"
-#: perms/models/asset_permission.py:29
+#: perms/models/asset_permission.py:31
msgid "Upload file"
msgstr "上传文件"
-#: perms/models/asset_permission.py:30
+#: perms/models/asset_permission.py:32
msgid "Download file"
msgstr "下载文件"
-#: perms/models/asset_permission.py:31
+#: perms/models/asset_permission.py:33
msgid "Upload download"
msgstr "上传下载"
-#: perms/models/asset_permission.py:80
+#: perms/models/asset_permission.py:82
msgid "Actions"
msgstr "动作"
-#: perms/models/asset_permission.py:84 perms/models/asset_permission.py:114
+#: perms/models/asset_permission.py:86 perms/models/asset_permission.py:125
#: templates/_nav.html:44
msgid "Asset permission"
msgstr "资产授权"
-#: perms/models/asset_permission.py:105 perms/models/base.py:40
+#: perms/models/asset_permission.py:116 perms/models/base.py:40
#: perms/templates/perms/asset_permission_detail.html:90
#: perms/templates/perms/remote_app_permission_detail.html:82
-#: users/models/user.py:102 users/templates/users/user_detail.html:107
+#: users/models/user.py:362 users/templates/users/user_detail.html:107
#: users/templates/users/user_profile.html:116
msgid "Date expired"
msgstr "失效日期"
@@ -3088,11 +3075,11 @@ msgstr "用户或用户组"
msgid "Assets and node"
msgstr "资产或节点"
-#: perms/templates/perms/asset_permission_asset.html:80
+#: perms/templates/perms/asset_permission_asset.html:70
msgid "Add asset to this permission"
msgstr "添加资产"
-#: perms/templates/perms/asset_permission_asset.html:97
+#: perms/templates/perms/asset_permission_asset.html:84
#: perms/templates/perms/asset_permission_detail.html:157
#: perms/templates/perms/asset_permission_user.html:97
#: perms/templates/perms/asset_permission_user.html:125
@@ -3108,11 +3095,11 @@ msgstr "添加资产"
msgid "Add"
msgstr "添加"
-#: perms/templates/perms/asset_permission_asset.html:108
+#: perms/templates/perms/asset_permission_asset.html:95
msgid "Add node to this permission"
msgstr "添加节点"
-#: perms/templates/perms/asset_permission_asset.html:125
+#: perms/templates/perms/asset_permission_asset.html:112
#: users/templates/users/user_detail.html:230
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:121
msgid "Join"
@@ -3207,19 +3194,15 @@ msgstr "添加用户"
msgid "Add user group to this permission"
msgstr "添加用户组"
-#: perms/utils/asset_permission.py:115
-msgid "Empty"
-msgstr "空"
-
#: perms/views/asset_permission.py:33 perms/views/asset_permission.py:64
#: perms/views/asset_permission.py:81 perms/views/asset_permission.py:98
-#: perms/views/asset_permission.py:135 perms/views/asset_permission.py:168
+#: perms/views/asset_permission.py:135 perms/views/asset_permission.py:169
#: perms/views/remote_app_permission.py:33
#: perms/views/remote_app_permission.py:49
-#: perms/views/remote_app_permission.py:65
-#: perms/views/remote_app_permission.py:79
-#: perms/views/remote_app_permission.py:106
-#: perms/views/remote_app_permission.py:143 templates/_nav.html:41
+#: perms/views/remote_app_permission.py:66
+#: perms/views/remote_app_permission.py:81
+#: perms/views/remote_app_permission.py:108
+#: perms/views/remote_app_permission.py:145 templates/_nav.html:41
#: xpack/plugins/orgs/templates/orgs/org_list.html:21
msgid "Perms"
msgstr "权限管理"
@@ -3244,7 +3227,7 @@ msgstr "资产授权详情"
msgid "Asset permission user list"
msgstr "资产授权用户列表"
-#: perms/views/asset_permission.py:169
+#: perms/views/asset_permission.py:170
msgid "Asset permission asset list"
msgstr "资产授权资产列表"
@@ -3256,19 +3239,19 @@ msgstr "远程应用授权列表"
msgid "Create RemoteApp permission"
msgstr "创建远程应用授权规则"
-#: perms/views/remote_app_permission.py:66
+#: perms/views/remote_app_permission.py:67
msgid "Update RemoteApp permission"
msgstr "更新远程应用授权规则"
-#: perms/views/remote_app_permission.py:80
+#: perms/views/remote_app_permission.py:82
msgid "RemoteApp permission detail"
msgstr "远程应用授权详情"
-#: perms/views/remote_app_permission.py:107
+#: perms/views/remote_app_permission.py:109
msgid "RemoteApp permission user list"
msgstr "远程应用授权用户列表"
-#: perms/views/remote_app_permission.py:144
+#: perms/views/remote_app_permission.py:146
msgid "RemoteApp permission RemoteApp list"
msgstr "远程应用授权远程应用列表"
@@ -3471,35 +3454,45 @@ msgstr "批量命令"
msgid "Allow user batch execute commands"
msgstr "允许用户批量执行命令"
-#: settings/forms.py:198
+#: settings/forms.py:196
+msgid "Service account registration"
+msgstr "终端注册"
+
+#: settings/forms.py:197
+msgid ""
+"Allow using bootstrap token register service account, when terminal setup, "
+"can disable it"
+msgstr "允许使用bootstrap token注册终端, 当终端注册成功后可以禁止"
+
+#: settings/forms.py:203
msgid "Limit the number of login failures"
msgstr "限制登录失败次数"
-#: settings/forms.py:202
+#: settings/forms.py:207
msgid "No logon interval"
msgstr "禁止登录时间间隔"
-#: settings/forms.py:204
+#: settings/forms.py:209
msgid ""
"Tip: (unit/minute) if the user has failed to log in for a limited number of "
"times, no login is allowed during this time interval."
msgstr ""
"提示:(单位:分)当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录"
-#: settings/forms.py:211
+#: settings/forms.py:216
msgid "Connection max idle time"
msgstr "SSH最大空闲时间"
-#: settings/forms.py:213
+#: settings/forms.py:218
msgid ""
"If idle time more than it, disconnect connection(only ssh now) Unit: minute"
msgstr "提示:(单位:分)如果超过该配置没有操作,连接会被断开(仅ssh)"
-#: settings/forms.py:219
+#: settings/forms.py:224
msgid "Password expiration time"
msgstr "密码过期时间"
-#: settings/forms.py:221
+#: settings/forms.py:226
msgid ""
"Tip: (unit: day) If the user does not update the password during the time, "
"the user password will expire failure;The password expiration reminder mail "
@@ -3509,81 +3502,81 @@ msgstr ""
"提示:(单位:天)如果用户在此期间没有更新密码,用户密码将过期失效; 密码过期"
"提醒邮件将在密码过期前5天内由系统(每天)自动发送给用户"
-#: settings/forms.py:230
+#: settings/forms.py:235
msgid "Password minimum length"
msgstr "密码最小长度 "
-#: settings/forms.py:234
+#: settings/forms.py:239
msgid "Must contain capital letters"
msgstr "必须包含大写字母"
-#: settings/forms.py:236
+#: settings/forms.py:241
msgid ""
"After opening, the user password changes and resets must contain uppercase "
"letters"
msgstr "开启后,用户密码修改、重置必须包含大写字母"
-#: settings/forms.py:241
+#: settings/forms.py:246
msgid "Must contain lowercase letters"
msgstr "必须包含小写字母"
-#: settings/forms.py:242
+#: settings/forms.py:247
msgid ""
"After opening, the user password changes and resets must contain lowercase "
"letters"
msgstr "开启后,用户密码修改、重置必须包含小写字母"
-#: settings/forms.py:247
+#: settings/forms.py:252
msgid "Must contain numeric characters"
msgstr "必须包含数字字符"
-#: settings/forms.py:248
+#: settings/forms.py:253
msgid ""
"After opening, the user password changes and resets must contain numeric "
"characters"
msgstr "开启后,用户密码修改、重置必须包含数字字符"
-#: settings/forms.py:253
+#: settings/forms.py:258
msgid "Must contain special characters"
msgstr "必须包含特殊字符"
-#: settings/forms.py:254
+#: settings/forms.py:259
msgid ""
"After opening, the user password changes and resets must contain special "
"characters"
msgstr "开启后,用户密码修改、重置必须包含特殊字符"
-#: settings/forms.py:261
+#: settings/forms.py:266
msgid "Create user email subject"
msgstr "创建用户邮件的主题"
-#: settings/forms.py:262
+#: settings/forms.py:267
msgid ""
"Tips: When creating a user, send the subject of the email (eg:Create account "
"successfully)"
msgstr "提示: 创建用户时,发送设置密码邮件的主题 (例如: 创建用户成功)"
-#: settings/forms.py:266
+#: settings/forms.py:271
msgid "Create user honorific"
msgstr "创建用户邮件的敬语"
-#: settings/forms.py:267
+#: settings/forms.py:272
msgid "Tips: When creating a user, send the honorific of the email (eg:Hello)"
msgstr "提示: 创建用户时,发送设置密码邮件的敬语 (例如: 您好)"
-#: settings/forms.py:272
+#: settings/forms.py:277
msgid "Create user email content"
msgstr "创建用户邮件的内容"
-#: settings/forms.py:273
+#: settings/forms.py:278
msgid "Tips:When creating a user, send the content of the email"
msgstr "提示: 创建用户时,发送设置密码邮件的内容"
-#: settings/forms.py:276
+#: settings/forms.py:281
msgid "Signature"
msgstr "署名"
-#: settings/forms.py:277
+#: settings/forms.py:282
msgid "Tips: Email signature (eg:jumpserver)"
msgstr "提示: 邮件的署名 (例如: jumpserver)"
@@ -3601,7 +3594,7 @@ msgid "Please submit the LDAP configuration before import"
msgstr "请先提交LDAP配置再进行导入"
#: settings/templates/settings/_ldap_list_users_modal.html:39
-#: users/models/user.py:66 users/templates/users/user_detail.html:71
+#: users/models/user.py:326 users/templates/users/user_detail.html:71
#: users/templates/users/user_profile.html:59
msgid "Email"
msgstr "邮件"
@@ -3935,7 +3928,7 @@ msgstr ""
" "
#: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:45
-#: users/views/group.py:62 users/views/group.py:79 users/views/group.py:96
+#: users/views/group.py:63 users/views/group.py:81 users/views/group.py:98
#: users/views/login.py:154 users/views/user.py:68 users/views/user.py:85
#: users/views/user.py:129 users/views/user.py:196 users/views/user.py:218
#: users/views/user.py:270 users/views/user.py:311
@@ -4389,7 +4382,7 @@ msgstr "你没有权限"
msgid "Could not reset self otp, use profile reset instead"
msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
-#: users/forms.py:33 users/models/user.py:74
+#: users/forms.py:33 users/models/user.py:334
#: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:87
#: users/templates/users/user_list.html:37
@@ -4417,7 +4410,7 @@ msgstr "添加到用户组"
msgid "Public key should not be the same as your old one."
msgstr "不能和原来的密钥相同"
-#: users/forms.py:91 users/forms.py:252 users/serializers/v1.py:91
+#: users/forms.py:91 users/forms.py:252 users/serializers/v1.py:95
msgid "Not a valid ssh public key"
msgstr "ssh密钥不合法"
@@ -4502,57 +4495,57 @@ msgstr "复制你的公钥到这里"
msgid "Select users"
msgstr "选择用户"
-#: users/models/user.py:37 users/models/user.py:449
+#: users/models/user.py:50 users/templates/users/user_update.html:22
+#: users/views/login.py:46 users/views/login.py:107 users/views/user.py:283
+msgid "User auth from {}, go there change password"
+msgstr "用户认证源来自 {}, 请去相应系统修改密码"
+
+#: users/models/user.py:120 users/models/user.py:447
msgid "Administrator"
msgstr "管理员"
-#: users/models/user.py:39
+#: users/models/user.py:122
msgid "Application"
msgstr "应用程序"
-#: users/models/user.py:40
+#: users/models/user.py:123
msgid "Auditor"
msgstr "审计员"
-#: users/models/user.py:43 users/templates/users/user_profile.html:92
+#: users/models/user.py:281 users/templates/users/user_profile.html:92
#: users/templates/users/user_profile.html:159
#: users/templates/users/user_profile.html:162
msgid "Disable"
msgstr "禁用"
-#: users/models/user.py:44 users/templates/users/user_profile.html:90
+#: users/models/user.py:282 users/templates/users/user_profile.html:90
#: users/templates/users/user_profile.html:166
msgid "Enable"
msgstr "启用"
-#: users/models/user.py:45 users/templates/users/user_profile.html:88
+#: users/models/user.py:283 users/templates/users/user_profile.html:88
msgid "Force enable"
msgstr "强制启用"
-#: users/models/user.py:77
+#: users/models/user.py:337
msgid "Avatar"
msgstr "头像"
-#: users/models/user.py:80 users/templates/users/user_detail.html:82
+#: users/models/user.py:340 users/templates/users/user_detail.html:82
msgid "Wechat"
msgstr "微信"
-#: users/models/user.py:109 users/templates/users/user_detail.html:103
+#: users/models/user.py:369 users/templates/users/user_detail.html:103
#: users/templates/users/user_list.html:39
#: users/templates/users/user_profile.html:100
msgid "Source"
msgstr "用户来源"
-#: users/models/user.py:113
+#: users/models/user.py:373
msgid "Date password last updated"
msgstr "最后更新密码日期"
-#: users/models/user.py:139 users/templates/users/user_update.html:22
-#: users/views/login.py:46 users/views/login.py:107 users/views/user.py:283
-msgid "User auth from {}, go there change password"
-msgstr "用户认证源来自 {}, 请去相应系统修改密码"
-
-#: users/models/user.py:452
+#: users/models/user.py:450
msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员"
@@ -4588,7 +4581,7 @@ msgstr "头像路径"
msgid "Role limit to {}"
msgstr "角色只能为 {}"
-#: users/serializers/v1.py:63
+#: users/serializers/v1.py:67
msgid "Password does not match security rules"
msgstr "密码不满足安全规则"
@@ -4633,7 +4626,7 @@ msgid "Import user groups"
msgstr "导入用户组"
#: users/templates/users/_user_groups_update_modal.html:4
-#: users/views/group.py:63
+#: users/views/group.py:64
msgid "Update user group"
msgstr "更新用户组"
@@ -4720,14 +4713,14 @@ msgid "Reset password"
msgstr "重置密码"
#: users/templates/users/reset_password.html:59
-#: users/templates/users/user_create.html:15
+#: users/templates/users/user_create.html:13
#: users/templates/users/user_password_update.html:61
#: users/templates/users/user_update.html:13
msgid "Your password must satisfy"
msgstr "您的密码必须满足:"
#: users/templates/users/reset_password.html:60
-#: users/templates/users/user_create.html:16
+#: users/templates/users/user_create.html:14
#: users/templates/users/user_password_update.html:62
#: users/templates/users/user_update.html:14
msgid "Password strength"
@@ -4738,42 +4731,42 @@ msgid "Password again"
msgstr "再次输入密码"
#: users/templates/users/reset_password.html:105
-#: users/templates/users/user_create.html:35
+#: users/templates/users/user_create.html:33
#: users/templates/users/user_password_update.html:99
#: users/templates/users/user_update.html:46
msgid "Very weak"
msgstr "很弱"
#: users/templates/users/reset_password.html:106
-#: users/templates/users/user_create.html:36
+#: users/templates/users/user_create.html:34
#: users/templates/users/user_password_update.html:100
#: users/templates/users/user_update.html:47
msgid "Weak"
msgstr "弱"
#: users/templates/users/reset_password.html:107
-#: users/templates/users/user_create.html:37
+#: users/templates/users/user_create.html:35
#: users/templates/users/user_password_update.html:101
#: users/templates/users/user_update.html:48
msgid "Normal"
msgstr "正常"
#: users/templates/users/reset_password.html:108
-#: users/templates/users/user_create.html:38
+#: users/templates/users/user_create.html:36
#: users/templates/users/user_password_update.html:102
#: users/templates/users/user_update.html:49
msgid "Medium"
msgstr "一般"
#: users/templates/users/reset_password.html:109
-#: users/templates/users/user_create.html:39
+#: users/templates/users/user_create.html:37
#: users/templates/users/user_password_update.html:103
#: users/templates/users/user_update.html:50
msgid "Strong"
msgstr "强"
#: users/templates/users/reset_password.html:110
-#: users/templates/users/user_create.html:40
+#: users/templates/users/user_create.html:38
#: users/templates/users/user_password_update.html:104
#: users/templates/users/user_update.html:51
msgid "Very strong"
@@ -4885,7 +4878,7 @@ msgstr "重置用户MFA成功"
#: users/templates/users/user_group_detail.html:22
#: users/templates/users/user_group_granted_asset.html:18
-#: users/views/group.py:80
+#: users/views/group.py:82
msgid "User group detail"
msgstr "用户组详情"
@@ -5227,7 +5220,7 @@ msgstr "密码或密钥不合法"
msgid "User group list"
msgstr "用户组列表"
-#: users/views/group.py:97
+#: users/views/group.py:99
msgid "User group granted asset"
msgstr "用户组授权资产"
@@ -5313,25 +5306,28 @@ msgid "Password length"
msgstr "密码长度"
#: xpack/plugins/change_auth_plan/forms.py:45
-msgid "* For security, please do not change root user's password"
-msgstr "* 为了安全,请不要更改root用户的密码"
+#: xpack/plugins/change_auth_plan/models.py:213
+#, fuzzy
+#| msgid "For security, do not change {} user's password"
+msgid "* For security, do not change {} user's password"
+msgstr "* 为了安全,禁止更改 {} 用户的密码"
-#: xpack/plugins/change_auth_plan/forms.py:54
+#: xpack/plugins/change_auth_plan/forms.py:55
msgid "* Please enter custom password"
msgstr "* 请输入自定义密码"
-#: xpack/plugins/change_auth_plan/forms.py:63
+#: xpack/plugins/change_auth_plan/forms.py:64
msgid "* Please enter a valid crontab expression"
msgstr "* 请输入有效的 crontab 表达式"
-#: xpack/plugins/change_auth_plan/forms.py:116
+#: xpack/plugins/change_auth_plan/forms.py:117
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:60
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:81
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:17
msgid "Periodic perform"
msgstr "定时执行"
-#: xpack/plugins/change_auth_plan/forms.py:120
+#: xpack/plugins/change_auth_plan/forms.py:121
msgid ""
"Tips: The username of the user on the asset to be modified. if the user "
"exists, change the password; If the user does not exist, create the user."
@@ -5339,11 +5335,11 @@ msgstr ""
"提示:用户名为将要修改的资产上的用户的用户名。如果用户存在,则修改密码;如果"
"用户不存在,则创建用户。"
-#: xpack/plugins/change_auth_plan/forms.py:124
+#: xpack/plugins/change_auth_plan/forms.py:125
msgid "Tips: (Units: hour)"
msgstr "提示:(单位: 时)"
-#: xpack/plugins/change_auth_plan/forms.py:125
+#: xpack/plugins/change_auth_plan/forms.py:126
msgid ""
"eg: Every Sunday 03:05 run <5 3 * * 0>