From bf5acf7ef11535dc44a808dee6bf2d88d46c1553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E5=B9=BF?= Date: Mon, 8 Jul 2019 15:35:20 +0800 Subject: [PATCH] =?UTF-8?q?[Update]=20=E4=BF=AE=E5=A4=8D=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=AE=A1=E7=90=86=E7=94=A8=E6=88=B7=E6=8F=90?= =?UTF-8?q?=E5=8F=8A=E9=87=8D=E7=BD=AE=E5=AF=86=E7=A0=81=E7=9A=84bug=20(#2?= =?UTF-8?q?899)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Update] 修复系统用户管理用户提及重置密码的bug * [Update] 去掉forms * [Update] 修改翻译 * [Update] 去掉debug信息 --- apps/assets/forms/user.py | 58 +-- apps/assets/models/base.py | 11 + apps/assets/serializers/admin_user.py | 4 +- apps/assets/serializers/asset_user.py | 12 +- apps/assets/serializers/base.py | 38 +- apps/assets/serializers/system_user.py | 65 ++- .../assets/templates/assets/_system_user.html | 25 ++ .../assets/admin_user_create_update.html | 39 +- .../templates/assets/system_user_update.html | 6 + apps/assets/views/admin_user.py | 4 +- apps/locale/zh/LC_MESSAGES/django.mo | Bin 77337 -> 77611 bytes apps/locale/zh/LC_MESSAGES/django.po | 405 +++++++++--------- apps/static/js/jumpserver.js | 20 +- 13 files changed, 411 insertions(+), 276 deletions(-) diff --git a/apps/assets/forms/user.py b/apps/assets/forms/user.py index 5c7d3c770..34a9e3c52 100644 --- a/apps/assets/forms/user.py +++ b/apps/assets/forms/user.py @@ -65,17 +65,7 @@ class PasswordAndKeyAuthForm(forms.ModelForm): class AdminUserForm(PasswordAndKeyAuthForm): def save(self, commit=True): - # Because we define custom field, so we need rewrite :method: `save` - admin_user = super().save(commit=commit) - password = self.cleaned_data.get('password', '') or None - private_key, public_key = super().gen_keys() - admin_user.set_auth(password=password, public_key=public_key, private_key=private_key) - return admin_user - - def clean(self): - super().clean() - if not self.instance: - super().validate_password_key() + raise forms.ValidationError("Use api to save") class Meta: model = AdminUser @@ -91,51 +81,7 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm): auto_generate_key = forms.BooleanField(initial=True, required=False) def save(self, commit=True): - # Because we define custom field, so we need rewrite :method: `save` - system_user = super().save() - password = self.cleaned_data.get('password', '') or None - login_mode = self.cleaned_data.get('login_mode', '') or None - protocol = self.cleaned_data.get('protocol') or None - auto_generate_key = self.cleaned_data.get('auto_generate_key', False) - private_key, public_key = super().gen_keys() - - if login_mode == SystemUser.LOGIN_MANUAL or \ - protocol in [SystemUser.PROTOCOL_TELNET, - SystemUser.PROTOCOL_VNC]: - system_user.auto_push = 0 - system_user.save() - auto_generate_key = False - - if auto_generate_key: - logger.info('Auto generate key and set system user auth') - if protocol == SystemUser.PROTOCOL_SSH: - system_user.auto_gen_auth() - elif protocol == SystemUser.PROTOCOL_RDP: - system_user.auto_gen_auth_password() - else: - system_user.set_auth(password=password, private_key=private_key, - public_key=public_key) - - return system_user - - def clean(self): - super().clean() - auto_generate = self.cleaned_data.get('auto_generate_key') - if not self.instance and not auto_generate: - super().validate_password_key() - - def clean_username(self): - username = self.data.get('username') - login_mode = self.data.get('login_mode') - protocol = self.data.get('protocol') - - if username: - return username - if login_mode == SystemUser.LOGIN_AUTO and \ - protocol != SystemUser.PROTOCOL_VNC: - msg = _('* Automatic login mode must fill in the username.') - raise forms.ValidationError(msg) - return username + raise forms.ValidationError("Use api to save") class Meta: model = SystemUser diff --git a/apps/assets/models/base.py b/apps/assets/models/base.py index bd85d144e..b372bc9fd 100644 --- a/apps/assets/models/base.py +++ b/apps/assets/models/base.py @@ -197,6 +197,17 @@ class AssetUser(OrgModelMixin): self.public_key = '' self.save() + @staticmethod + def gen_password(): + return str(uuid.uuid4()) + + @staticmethod + def gen_key(username): + private_key, public_key = ssh_key_gen( + username=username + ) + return private_key, public_key + def auto_gen_auth(self): password = str(uuid.uuid4()) private_key, public_key = ssh_key_gen( diff --git a/apps/assets/serializers/admin_user.py b/apps/assets/serializers/admin_user.py index dbbb16406..b05de01f6 100644 --- a/apps/assets/serializers/admin_user.py +++ b/apps/assets/serializers/admin_user.py @@ -8,10 +8,10 @@ from common.serializers import AdaptedBulkListSerializer from ..models import Node, AdminUser from orgs.mixins import BulkOrgResourceModelSerializer -from .base import AuthSerializer +from .base import AuthSerializer, AuthSerializerMixin -class AdminUserSerializer(BulkOrgResourceModelSerializer): +class AdminUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): """ 管理用户 """ diff --git a/apps/assets/serializers/asset_user.py b/apps/assets/serializers/asset_user.py index a111f1993..99497c593 100644 --- a/apps/assets/serializers/asset_user.py +++ b/apps/assets/serializers/asset_user.py @@ -4,12 +4,11 @@ from django.utils.translation import ugettext as _ from rest_framework import serializers -from common.utils import validate_ssh_private_key from common.serializers import AdaptedBulkListSerializer from orgs.mixins import BulkOrgResourceModelSerializer from ..models import AuthBook, Asset from ..backends import AssetUserManager -from .base import ConnectivitySerializer +from .base import ConnectivitySerializer, AuthSerializerMixin __all__ = [ @@ -24,7 +23,7 @@ class BasicAssetSerializer(serializers.ModelSerializer): fields = ['hostname', 'ip'] -class AssetUserSerializer(BulkOrgResourceModelSerializer): +class AssetUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): hostname = serializers.CharField(read_only=True, label=_("Hostname")) ip = serializers.CharField(read_only=True, label=_("IP")) connectivity = ConnectivitySerializer(read_only=True, label=_("Connectivity")) @@ -50,13 +49,6 @@ class AssetUserSerializer(BulkOrgResourceModelSerializer): 'public_key': {'write_only': True}, } - def validate_private_key(self, key): - password = self.initial_data.get("password") - valid = validate_ssh_private_key(key, password) - if not valid: - raise serializers.ValidationError(_("private key invalid")) - return key - def create(self, validated_data): if not validated_data.get("name") and validated_data.get("username"): validated_data["name"] = validated_data["username"] diff --git a/apps/assets/serializers/base.py b/apps/assets/serializers/base.py index 3d0fcd58b..ca4aa7502 100644 --- a/apps/assets/serializers/base.py +++ b/apps/assets/serializers/base.py @@ -2,7 +2,7 @@ # from rest_framework import serializers -from common.utils import ssh_pubkey_gen +from common.utils import ssh_pubkey_gen, validate_ssh_private_key class AuthSerializer(serializers.ModelSerializer): @@ -28,4 +28,38 @@ class AuthSerializer(serializers.ModelSerializer): class ConnectivitySerializer(serializers.Serializer): status = serializers.IntegerField() - datetime = serializers.DateTimeField() \ No newline at end of file + datetime = serializers.DateTimeField() + + +class AuthSerializerMixin: + def validate_password(self, password): + return password + + def validate_private_key(self, private_key): + if not private_key: + return + password = self.initial_data.get("password") + valid = validate_ssh_private_key(private_key, password) + if not valid: + raise serializers.ValidationError(_("private key invalid")) + return private_key + + def validate_public_key(self, public_key): + return public_key + + @staticmethod + def clean_auth_fields(validated_data): + for field in ('password', 'private_key', 'public_key'): + value = validated_data.get(field) + if not value: + validated_data.pop(field, None) + # print(validated_data) + # raise serializers.ValidationError(">>>>>>") + + def create(self, validated_data): + self.clean_auth_fields(validated_data) + return super().create(validated_data) + + def update(self, instance, validated_data): + self.clean_auth_fields(validated_data) + return super().update(instance, validated_data) diff --git a/apps/assets/serializers/system_user.py b/apps/assets/serializers/system_user.py index 116dcdd36..6f1c5e416 100644 --- a/apps/assets/serializers/system_user.py +++ b/apps/assets/serializers/system_user.py @@ -5,13 +5,14 @@ from django.utils.translation import ugettext_lazy as _ from common.serializers import AdaptedBulkListSerializer from orgs.mixins import BulkOrgResourceModelSerializer from ..models import SystemUser -from .base import AuthSerializer +from .base import AuthSerializer, AuthSerializerMixin -class SystemUserSerializer(BulkOrgResourceModelSerializer): +class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): """ 系统用户 """ + auto_generate_key = serializers.BooleanField(initial=True, required=False, write_only=True) class Meta: model = SystemUser @@ -20,7 +21,7 @@ class SystemUserSerializer(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' + 'assets_amount', 'connectivity_amount', 'auto_generate_key' ] extra_kwargs = { 'password': {"write_only": True}, @@ -32,6 +33,63 @@ class SystemUserSerializer(BulkOrgResourceModelSerializer): 'created_by': {'read_only': True}, } + def validate_auto_push(self, value): + login_mode = self.initial_data.get("login_mode") + protocol = self.initial_data.get("protocol") + + if login_mode == SystemUser.LOGIN_MANUAL or \ + protocol in [SystemUser.PROTOCOL_TELNET, + SystemUser.PROTOCOL_VNC]: + value = False + return value + + def validate_auto_generate_key(self, value): + login_mode = self.initial_data.get("login_mode") + protocol = self.initial_data.get("protocol") + + if self.context["request"].method.lower() != "post": + value = False + elif self.instance: + value = False + elif login_mode == SystemUser.LOGIN_MANUAL: + value = False + elif protocol in [SystemUser.PROTOCOL_TELNET, SystemUser.PROTOCOL_VNC]: + value = False + return value + + def validate_username(self, username): + if username: + return username + login_mode = self.validated_data.get("login_mode") + protocol = self.validated_data.get("protocol") + if login_mode == SystemUser.LOGIN_AUTO and \ + protocol != SystemUser.PROTOCOL_VNC: + msg = _('* Automatic login mode must fill in the username.') + raise serializers.ValidationError(msg) + return username + + def validate_password(self, password): + super().validate_password(password) + auto_gen_key = self.initial_data.get("auto_generate_key", False) + private_key = self.initial_data.get("private_key") + if not self.instance and not auto_gen_key and not password and not private_key: + raise serializers.ValidationError(_("Password or private key required")) + return password + + def validate(self, attrs): + username = attrs.get("username", "manual") + protocol = attrs.get("protocol") + auto_gen_key = attrs.get("auto_generate_key", False) + if auto_gen_key: + password = SystemUser.gen_password() + attrs["password"] = password + if protocol == SystemUser.PROTOCOL_SSH: + private_key, public_key = SystemUser.gen_key(username) + attrs["private_key"] = private_key + attrs["public_key"] = public_key + attrs.pop("auto_generate_key", None) + return attrs + @classmethod def setup_eager_loading(cls, queryset): """ Perform necessary eager loading of data. """ @@ -52,7 +110,6 @@ class SystemUserAuthSerializer(AuthSerializer): ] - class SystemUserSimpleSerializer(serializers.ModelSerializer): """ 系统用户最基本信息的数据结构 diff --git a/apps/assets/templates/assets/_system_user.html b/apps/assets/templates/assets/_system_user.html index 71c3420d0..ef78187b5 100644 --- a/apps/assets/templates/assets/_system_user.html +++ b/apps/assets/templates/assets/_system_user.html @@ -218,6 +218,31 @@ $(document).ready(function () { }) .on('change', protocol_id, function(){ fieldDisplay(); +}).on("submit", "form", function (evt) { + evt.preventDefault(); + {% block formUrl %} + var the_url = '{% url 'api-assets:system-user-list' %}'; + var redirect_to = '{% url "assets:system-user-list" %}'; + var method = "POST"; + {% endblock %} + var form = $("form"); + var data = form.serializeObject(); + + objectAttrsIsBool(data, ["auto_generate_key", "auto_push"]); + data["private_key"] = $("#id_private_key_file").data('file'); + + 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) + }) }) diff --git a/apps/assets/templates/assets/admin_user_create_update.html b/apps/assets/templates/assets/admin_user_create_update.html index 4ec2780ea..8d32d16ab 100644 --- a/apps/assets/templates/assets/admin_user_create_update.html +++ b/apps/assets/templates/assets/admin_user_create_update.html @@ -54,9 +54,38 @@ {% endblock %} {% block custom_foot_js %} - + {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/system_user_update.html b/apps/assets/templates/assets/system_user_update.html index 977c3ac31..4414d3dcf 100644 --- a/apps/assets/templates/assets/system_user_update.html +++ b/apps/assets/templates/assets/system_user_update.html @@ -14,3 +14,9 @@ {% endblock %} +{% block formUrl %} + var the_url = '{% url 'api-assets:system-user-detail' pk=object.pk %}'; + var redirect_to = '{% url "assets:system-user-list" %}'; + var method = "PUT"; +{% endblock %} + diff --git a/apps/assets/views/admin_user.py b/apps/assets/views/admin_user.py index 455ca4a9d..1ded61cb2 100644 --- a/apps/assets/views/admin_user.py +++ b/apps/assets/views/admin_user.py @@ -47,7 +47,8 @@ class AdminUserCreateView(PermissionsMixin, def get_context_data(self, **kwargs): context = { 'app': _('Assets'), - 'action': _('Create admin user') + 'action': _('Create admin user'), + "type": "create" } kwargs.update(context) return super().get_context_data(**kwargs) @@ -65,6 +66,7 @@ class AdminUserUpdateView(PermissionsMixin, SuccessMessageMixin, UpdateView): context = { 'app': _('Assets'), 'action': _('Update admin user'), + "type": "update" } kwargs.update(context) return super().get_context_data(**kwargs) diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 1e5e6a70ea69f759ce4d2927d59ac891cba9cbc4..3ca6363f6c9f3b416456724baed6bdf13bd30737 100644 GIT binary patch delta 22588 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 Y?%=z#265hvErV`sSswS>`^I_y50EuhPyhe` delta 22433 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 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 725d56bc6..6dde35429 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-04 17:13+0800\n" +"POT-Creation-Date: 2019-07-08 15:32+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -71,14 +71,14 @@ msgstr "目标地址" msgid "Operating parameter" msgstr "运行参数" -#: applications/forms/remote_app.py:106 applications/models/remote_app.py:23 +#: applications/forms/remote_app.py:104 applications/models/remote_app.py:23 #: applications/templates/applications/remote_app_detail.html:57 #: 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:292 assets/models/authbook.py:24 -#: assets/serializers/admin_user.py:35 assets/serializers/asset_user.py:89 -#: assets/serializers/system_user.py:29 +#: assets/models/asset.py:286 assets/models/authbook.py:24 +#: assets/serializers/admin_user.py:35 assets/serializers/asset_user.py:81 +#: assets/serializers/system_user.py:30 #: assets/templates/assets/admin_user_list.html:49 #: assets/templates/assets/domain_detail.html:60 #: assets/templates/assets/domain_list.html:26 @@ -86,7 +86,7 @@ msgstr "运行参数" #: 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:68 +#: perms/forms/asset_permission.py:68 perms/models/asset_permission.py:76 #: 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:115 +#: xpack/plugins/change_auth_plan/forms.py:114 #: 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 @@ -108,15 +108,15 @@ msgstr "运行参数" msgid "Asset" msgstr "资产" -#: applications/forms/remote_app.py:109 applications/models/remote_app.py:27 +#: applications/forms/remote_app.py:107 applications/models/remote_app.py:27 #: 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 #: 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:70 -#: perms/models/asset_permission.py:95 +#: perms/forms/asset_permission.py:74 perms/models/asset_permission.py:78 +#: perms/models/asset_permission.py:103 #: perms/templates/perms/asset_permission_detail.html:140 #: perms/templates/perms/asset_permission_list.html:50 #: perms/templates/perms/asset_permission_list.html:71 @@ -134,11 +134,11 @@ msgstr "系统用户" #: applications/templates/applications/remote_app_detail.html:53 #: applications/templates/applications/remote_app_list.html:20 #: applications/templates/applications/user_remote_app_list.html:16 -#: assets/forms/domain.py:73 assets/forms/user.py:84 assets/forms/user.py:148 -#: assets/models/asset.py:64 assets/models/base.py:28 -#: assets/models/cluster.py:18 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/forms/asset.py:20 assets/forms/domain.py:73 assets/forms/user.py:74 +#: assets/forms/user.py:94 assets/models/base.py:28 assets/models/cluster.py:18 +#: 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/cmd_filter_detail.html:61 #: assets/templates/assets/cmd_filter_list.html:24 @@ -173,7 +173,7 @@ msgstr "系统用户" #: 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:98 +#: xpack/plugins/change_auth_plan/forms.py:97 #: 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,16 +205,16 @@ msgstr "参数" #: applications/models/remote_app.py:43 #: applications/templates/applications/remote_app_detail.html:77 -#: assets/models/asset.py:124 assets/models/base.py:36 +#: assets/models/asset.py:151 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 -#: assets/templates/assets/asset_detail.html:128 +#: assets/templates/assets/asset_detail.html:124 #: assets/templates/assets/cmd_filter_detail.html:77 #: 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:98 perms/models/base.py:41 +#: perms/models/asset_permission.py:106 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 @@ -229,7 +229,7 @@ msgstr "创建者" # msgstr "创建者" #: applications/models/remote_app.py:46 #: applications/templates/applications/remote_app_detail.html:73 -#: assets/models/asset.py:125 assets/models/base.py:34 +#: assets/models/asset.py:152 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 +237,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:99 +#: orgs/models.py:15 perms/models/asset_permission.py:107 #: perms/models/base.py:42 #: perms/templates/perms/asset_permission_detail.html:94 #: perms/templates/perms/remote_app_permission_detail.html:86 @@ -257,13 +257,13 @@ 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:126 assets/models/base.py:33 +#: assets/models/asset.py:153 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/asset_detail.html:136 +#: assets/templates/assets/asset_detail.html:132 #: assets/templates/assets/cmd_filter_detail.html:65 #: assets/templates/assets/cmd_filter_list.html:27 #: assets/templates/assets/cmd_filter_rule_list.html:62 @@ -273,7 +273,7 @@ msgstr "创建日期" #: 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:100 +#: orgs/models.py:16 perms/models/asset_permission.py:108 #: perms/models/base.py:43 #: perms/templates/perms/asset_permission_detail.html:102 #: perms/templates/perms/remote_app_permission_detail.html:94 @@ -550,7 +550,7 @@ msgstr "动作" #: applications/templates/applications/user_remote_app_list.html:57 #: assets/templates/assets/user_asset_list.html:100 -#: perms/models/asset_permission.py:27 +#: perms/models/asset_permission.py:28 msgid "Connect" msgstr "连接" @@ -612,29 +612,37 @@ msgid "Reachable" msgstr "可连接" #: assets/const.py:79 assets/models/utils.py:45 authentication/utils.py:9 -#: xpack/plugins/license/models.py:78 +#: xpack/plugins/license/models.py:79 msgid "Unknown" msgstr "未知" -#: assets/forms/asset.py:51 assets/models/asset.py:95 assets/models/user.py:107 -#: assets/templates/assets/asset_detail.html:194 -#: assets/templates/assets/asset_detail.html:202 +#: assets/forms/asset.py:24 assets/models/asset.py:117 +#: 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/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:69 +#: perms/models/asset_permission.py:77 #: xpack/plugins/change_auth_plan/models.py:72 msgid "Nodes" msgstr "节点" -#: assets/forms/asset.py:54 assets/forms/asset.py:89 assets/models/asset.py:99 +#: assets/forms/asset.py:48 assets/forms/asset.py:83 assets/models/asset.py:126 #: assets/models/cluster.py:19 assets/models/user.py:65 -#: assets/templates/assets/asset_detail.html:80 templates/_nav.html:24 +#: assets/templates/assets/asset_detail.html:76 templates/_nav.html:24 #: xpack/plugins/cloud/models.py:124 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:65 #: xpack/plugins/orgs/templates/orgs/org_list.html:18 msgid "Admin user" msgstr "管理用户" -#: assets/forms/asset.py:57 assets/forms/asset.py:92 assets/forms/asset.py:131 +#: assets/forms/asset.py:51 assets/forms/asset.py:86 assets/forms/asset.py:125 #: assets/templates/assets/asset_create.html:48 #: assets/templates/assets/asset_create.html:50 #: assets/templates/assets/asset_list.html:85 @@ -643,23 +651,23 @@ msgstr "管理用户" msgid "Label" msgstr "标签" -#: assets/forms/asset.py:60 assets/forms/asset.py:95 assets/models/asset.py:94 +#: assets/forms/asset.py:54 assets/forms/asset.py:89 assets/models/asset.py:121 #: assets/models/domain.py:26 assets/models/domain.py:52 -#: assets/templates/assets/asset_detail.html:84 +#: assets/templates/assets/asset_detail.html:80 #: assets/templates/assets/user_asset_list.html:173 #: xpack/plugins/orgs/templates/orgs/org_list.html:17 msgid "Domain" msgstr "网域" -#: assets/forms/asset.py:64 assets/forms/asset.py:86 assets/forms/asset.py:99 -#: assets/forms/asset.py:134 assets/models/node.py:249 +#: 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/templates/assets/asset_create.html:42 -#: perms/forms/asset_permission.py:71 perms/forms/asset_permission.py:79 -#: perms/models/asset_permission.py:93 +#: perms/forms/asset_permission.py:71 perms/forms/asset_permission.py:78 +#: perms/models/asset_permission.py:101 #: 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:116 +#: xpack/plugins/change_auth_plan/forms.py:115 #: 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 @@ -668,7 +676,7 @@ msgstr "网域" msgid "Node" msgstr "节点" -#: assets/forms/asset.py:68 assets/forms/asset.py:103 +#: assets/forms/asset.py:62 assets/forms/asset.py:97 msgid "" "root or other NOPASSWD sudo privilege user existed in asset,If asset is " "windows or other set any one, more see admin user left menu" @@ -676,19 +684,19 @@ msgstr "" "root或其他拥有NOPASSWD: ALL权限的用户, 如果是windows或其它硬件可以随意设置一" "个, 更多信息查看左侧 `管理用户` 菜单" -#: assets/forms/asset.py:71 assets/forms/asset.py:106 +#: assets/forms/asset.py:65 assets/forms/asset.py:100 msgid "Windows 2016 RDP protocol is different, If is window 2016, set it" msgstr "Windows 2016的RDP协议与之前不同,如果是请设置" -#: assets/forms/asset.py:72 assets/forms/asset.py:107 +#: assets/forms/asset.py:66 assets/forms/asset.py:101 msgid "" "If your have some network not connect with each other, you can set domain" msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,使用网域网关跳转登录" -#: assets/forms/asset.py:114 assets/forms/asset.py:118 +#: 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:106 +#: xpack/plugins/change_auth_plan/forms.py:105 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:84 msgid "Select assets" msgstr "选择资产" @@ -705,7 +713,7 @@ msgstr "不能包含特殊字符" msgid "SSH gateway support proxy SSH,RDP,VNC" msgstr "SSH网关,支持代理SSH,RDP和VNC" -#: assets/forms/domain.py:74 assets/forms/user.py:85 assets/forms/user.py:149 +#: assets/forms/domain.py:74 assets/forms/user.py:75 assets/forms/user.py:95 #: assets/models/base.py:29 #: assets/templates/assets/_asset_user_auth_update_modal.html:15 #: assets/templates/assets/_asset_user_auth_view_modal.html:21 @@ -726,7 +734,7 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC" #: 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:100 +#: xpack/plugins/change_auth_plan/forms.py:99 #: 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 @@ -741,7 +749,7 @@ msgid "Password or private key passphrase" msgstr "密码或密钥密码" #: assets/forms/user.py:26 assets/models/base.py:30 -#: assets/serializers/asset_user.py:70 +#: assets/serializers/asset_user.py:62 #: assets/templates/assets/_asset_user_auth_update_modal.html:21 #: assets/templates/assets/_asset_user_auth_view_modal.html:27 #: authentication/forms.py:13 @@ -759,7 +767,7 @@ msgstr "密码或密钥密码" msgid "Password" msgstr "密码" -#: assets/forms/user.py:29 assets/serializers/asset_user.py:78 +#: 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 msgid "Private key" @@ -773,21 +781,17 @@ msgstr "不合法的密钥,仅支持RSA/DSA格式的密钥" msgid "Password and private key file must be input one" msgstr "密码和私钥, 必须输入一个" -#: assets/forms/user.py:136 -msgid "* Automatic login mode must fill in the username." -msgstr "自动登录模式,必须填写用户名" - -#: assets/forms/user.py:151 assets/models/cmd_filter.py:31 +#: assets/forms/user.py:97 assets/models/cmd_filter.py:31 #: assets/models/user.py:115 assets/templates/assets/_system_user.html:66 #: assets/templates/assets/system_user_detail.html:165 msgid "Command filter" msgstr "命令过滤器" -#: assets/forms/user.py:155 +#: assets/forms/user.py:101 msgid "Auto push system user to asset" msgstr "自动推送系统用户到资产" -#: assets/forms/user.py:156 +#: assets/forms/user.py:102 msgid "" "1-100, High level will be using login asset as default, if user was granted " "more than 2 system user" @@ -795,26 +799,18 @@ msgstr "" "1-100, 1最低优先级,100最高优先级。授权多个用户时,高优先级的系统用户将会作为" "默认登录用户" -#: assets/forms/user.py:158 +#: assets/forms/user.py:104 msgid "" "If you choose manual login mode, you do not need to fill in the username and " "password." msgstr "如果选择手动登录模式,用户名和密码可以不填写" -#: assets/forms/user.py:160 +#: assets/forms/user.py:106 msgid "Use comma split multi command, ex: /bin/whoami,/bin/ifconfig" msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig" -#: assets/models/asset.py:65 assets/models/asset.py:90 -#: 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/models/asset.py:85 assets/models/domain.py:49 -#: assets/serializers/asset_user.py:29 +#: assets/models/asset.py:112 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 @@ -830,7 +826,7 @@ msgstr "端口" msgid "IP" msgstr "IP" -#: assets/models/asset.py:86 assets/serializers/asset_user.py:28 +#: assets/models/asset.py:113 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 @@ -847,9 +843,8 @@ msgstr "IP" msgid "Hostname" msgstr "主机名" -#: assets/models/asset.py:89 assets/models/asset.py:92 -#: assets/models/domain.py:51 assets/models/user.py:110 -#: assets/templates/assets/asset_detail.html:72 +#: assets/models/asset.py:116 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 @@ -859,86 +854,91 @@ msgstr "主机名" msgid "Protocol" msgstr "协议" -#: assets/models/asset.py:93 assets/templates/assets/asset_detail.html:108 +#: assets/models/asset.py:119 assets/serializers/asset.py:63 +#: assets/templates/assets/asset_create.html:24 +msgid "Protocols" +msgstr "协议组" + +#: assets/models/asset.py:120 assets/templates/assets/asset_detail.html:104 #: assets/templates/assets/user_asset_list.html:170 msgid "Platform" msgstr "系统平台" -#: assets/models/asset.py:96 assets/models/cmd_filter.py:21 +#: assets/models/asset.py:123 assets/models/cmd_filter.py:21 #: assets/models/domain.py:54 assets/models/label.py:22 -#: assets/templates/assets/asset_detail.html:116 +#: assets/templates/assets/asset_detail.html:112 #: assets/templates/assets/user_asset_list.html:174 msgid "Is active" msgstr "激活" -#: assets/models/asset.py:102 assets/templates/assets/asset_detail.html:68 +#: assets/models/asset.py:129 assets/templates/assets/asset_detail.html:68 msgid "Public IP" msgstr "公网IP" -#: assets/models/asset.py:103 assets/templates/assets/asset_detail.html:124 +#: assets/models/asset.py:130 assets/templates/assets/asset_detail.html:120 msgid "Asset number" msgstr "资产编号" -#: assets/models/asset.py:106 assets/templates/assets/asset_detail.html:88 +#: assets/models/asset.py:133 assets/templates/assets/asset_detail.html:84 msgid "Vendor" msgstr "制造商" -#: assets/models/asset.py:107 assets/templates/assets/asset_detail.html:92 +#: assets/models/asset.py:134 assets/templates/assets/asset_detail.html:88 msgid "Model" msgstr "型号" -#: assets/models/asset.py:108 assets/templates/assets/asset_detail.html:120 +#: assets/models/asset.py:135 assets/templates/assets/asset_detail.html:116 msgid "Serial number" msgstr "序列号" -#: assets/models/asset.py:110 +#: assets/models/asset.py:137 msgid "CPU model" msgstr "CPU型号" -#: assets/models/asset.py:111 +#: assets/models/asset.py:138 #: xpack/plugins/license/templates/license/license_detail.html:80 msgid "CPU count" msgstr "CPU数量" -#: assets/models/asset.py:112 +#: assets/models/asset.py:139 msgid "CPU cores" msgstr "CPU核数" -#: assets/models/asset.py:113 +#: assets/models/asset.py:140 msgid "CPU vcpus" msgstr "CPU总数" -#: assets/models/asset.py:114 assets/templates/assets/asset_detail.html:100 +#: assets/models/asset.py:141 assets/templates/assets/asset_detail.html:96 msgid "Memory" msgstr "内存" -#: assets/models/asset.py:115 +#: assets/models/asset.py:142 msgid "Disk total" msgstr "硬盘大小" -#: assets/models/asset.py:116 +#: assets/models/asset.py:143 msgid "Disk info" msgstr "硬盘信息" -#: assets/models/asset.py:118 assets/templates/assets/asset_detail.html:112 +#: assets/models/asset.py:145 assets/templates/assets/asset_detail.html:108 #: assets/templates/assets/user_asset_list.html:171 msgid "OS" msgstr "操作系统" -#: assets/models/asset.py:119 +#: assets/models/asset.py:146 msgid "OS version" msgstr "系统版本" -#: assets/models/asset.py:120 +#: assets/models/asset.py:147 msgid "OS arch" msgstr "系统架构" -#: assets/models/asset.py:121 +#: assets/models/asset.py:148 msgid "Hostname raw" msgstr "主机名原始" -#: assets/models/asset.py:123 assets/templates/assets/asset_create.html:46 -#: assets/templates/assets/asset_detail.html:231 templates/_nav.html:26 +#: assets/models/asset.py:150 assets/templates/assets/asset_create.html:46 +#: assets/templates/assets/asset_detail.html:227 templates/_nav.html:26 msgid "Labels" msgstr "标签管理" @@ -1008,7 +1008,7 @@ msgid "Default" msgstr "默认" #: assets/models/cluster.py:36 assets/models/label.py:14 -#: users/models/user.py:443 +#: users/models/user.py:453 msgid "System" msgstr "系统" @@ -1127,7 +1127,7 @@ 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:431 users/serializers/v1.py:105 +#: users/models/user.py:38 users/models/user.py:441 users/serializers/v1.py:105 #: 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 @@ -1136,7 +1136,7 @@ msgstr "默认资产组" msgid "User" msgstr "用户" -#: assets/models/label.py:19 assets/models/node.py:241 +#: assets/models/label.py:19 assets/models/node.py:246 #: assets/templates/assets/label_list.html:15 settings/models.py:30 msgid "Value" msgstr "值" @@ -1145,11 +1145,11 @@ msgstr "值" msgid "Category" msgstr "分类" -#: assets/models/node.py:240 +#: assets/models/node.py:245 msgid "Key" msgstr "键" -#: assets/models/node.py:297 +#: assets/models/node.py:303 msgid "New node" msgstr "新节点" @@ -1166,10 +1166,10 @@ msgstr "手动登录" #: assets/templates/assets/system_user_assets.html:22 #: assets/templates/assets/system_user_detail.html:22 #: assets/views/admin_user.py:30 assets/views/admin_user.py:49 -#: assets/views/admin_user.py:66 assets/views/admin_user.py:82 -#: assets/views/admin_user.py:107 assets/views/asset.py:52 -#: assets/views/asset.py:69 assets/views/asset.py:128 assets/views/asset.py:171 -#: assets/views/asset.py:199 assets/views/asset.py:231 +#: assets/views/admin_user.py:67 assets/views/admin_user.py:84 +#: assets/views/admin_user.py:109 assets/views/asset.py:40 +#: 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 @@ -1208,37 +1208,33 @@ 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:46 -#: assets/serializers/asset_user.py:30 assets/serializers/system_user.py:30 +#: 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:44 assets/templates/assets/asset_create.html:24 -msgid "Protocols" -msgstr "协议组" +#: assets/serializers/asset.py:21 +msgid "Protocol format should {}/{}" +msgstr "" -#: assets/serializers/asset.py:72 -msgid "Hardware info" -msgstr "硬件信息" - -#: assets/serializers/asset.py:73 orgs/mixins/serializers.py:26 -msgid "Org name" -msgstr "组织名称" - -#: assets/serializers/asset.py:91 +#: assets/serializers/asset.py:38 msgid "Protocol duplicate: {}" msgstr "协议重复: {}" -#: assets/serializers/asset_user.py:32 +#: assets/serializers/asset.py:90 +msgid "Hardware info" +msgstr "硬件信息" + +#: assets/serializers/asset.py:91 orgs/mixins/serializers.py:26 +msgid "Org name" +msgstr "组织名称" + +#: assets/serializers/asset_user.py:31 msgid "Backend" msgstr "后端" -#: assets/serializers/asset_user.py:57 -msgid "private key invalid" -msgstr "密钥不合法" - -#: assets/serializers/asset_user.py:74 users/forms.py:263 +#: assets/serializers/asset_user.py:66 users/forms.py:263 #: users/models/user.py:94 users/templates/users/first_login.html:42 #: users/templates/users/user_password_update.html:46 #: users/templates/users/user_profile.html:68 @@ -1247,14 +1243,26 @@ msgstr "密钥不合法" msgid "Public key" msgstr "ssh公钥" +#: assets/serializers/base.py:44 +msgid "private key invalid" +msgstr "密钥不合法" + #: assets/serializers/node.py:33 msgid "The same level node name cannot be the same" msgstr "同级别节点名字不能重复" -#: assets/serializers/system_user.py:31 +#: assets/serializers/system_user.py:32 msgid "Login mode display" msgstr "登录模式显示" +#: assets/serializers/system_user.py:67 +msgid "* Automatic login mode must fill in the username." +msgstr "自动登录模式,必须填写用户名" + +#: assets/serializers/system_user.py:76 +msgid "Password or private key required" +msgstr "密码或密钥密码需要一个" + #: assets/tasks.py:33 msgid "Asset has been disabled, skipped: {}" msgstr "资产或许不支持ansible, 跳过: {}" @@ -1334,7 +1342,7 @@ msgstr "推送系统用户到入资产: {}" msgid "Push system users to asset: {} => {}" msgstr "推送系统用户到入资产: {} => {}" -#: assets/tasks.py:602 +#: assets/tasks.py:603 msgid "Test asset user connectivity: {}" msgstr "测试资产用户可连接性: {}" @@ -1343,7 +1351,7 @@ msgid "Import admin user" msgstr "导入管理用户" #: assets/templates/assets/_admin_user_update_modal.html:4 -#: assets/views/admin_user.py:67 +#: assets/views/admin_user.py:68 msgid "Update admin user" msgstr "更新管理用户" @@ -1379,7 +1387,7 @@ msgstr "启用MFA" msgid "Import assets" msgstr "导入资产" -#: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:53 +#: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:41 #: templates/_nav.html:22 xpack/plugins/change_auth_plan/views.py:116 msgid "Asset list" msgstr "资产列表" @@ -1393,12 +1401,12 @@ msgid "Update asset user auth" msgstr "更新资产用户认证信息" #: assets/templates/assets/_asset_user_auth_update_modal.html:23 -#: xpack/plugins/change_auth_plan/forms.py:102 +#: xpack/plugins/change_auth_plan/forms.py:101 msgid "Please input password" msgstr "请输入密码" #: assets/templates/assets/_asset_user_auth_update_modal.html:68 -#: assets/templates/assets/asset_detail.html:311 +#: assets/templates/assets/asset_detail.html:307 #: users/templates/users/user_detail.html:307 #: users/templates/users/user_detail.html:334 #: xpack/plugins/interface/views.py:35 @@ -1446,7 +1454,7 @@ msgstr "查看" #: assets/templates/assets/_asset_user_list.html:71 #: assets/templates/assets/admin_user_assets.html:61 #: assets/templates/assets/asset_asset_user_list.html:57 -#: assets/templates/assets/asset_detail.html:182 +#: assets/templates/assets/asset_detail.html:178 #: assets/templates/assets/system_user_assets.html:63 #: assets/templates/assets/system_user_detail.html:151 msgid "Test" @@ -1539,7 +1547,7 @@ msgstr "更新系统用户" #: assets/templates/assets/_user_asset_detail_modal.html:11 #: assets/templates/assets/asset_asset_user_list.html:13 -#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:232 +#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:204 msgid "Asset detail" msgstr "资产详情" @@ -1564,7 +1572,7 @@ msgstr "快速更新" #: assets/templates/assets/admin_user_assets.html:58 #: assets/templates/assets/asset_asset_user_list.html:54 -#: assets/templates/assets/asset_detail.html:179 +#: assets/templates/assets/asset_detail.html:175 msgid "Test connective" msgstr "测试可连接性" @@ -1574,13 +1582,13 @@ msgstr "替换资产的管理员" #: assets/templates/assets/admin_user_detail.html:91 #: perms/templates/perms/asset_permission_asset.html:116 -#: xpack/plugins/change_auth_plan/forms.py:110 +#: xpack/plugins/change_auth_plan/forms.py:109 #: 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:211 +#: assets/templates/assets/asset_detail.html:207 #: assets/templates/assets/asset_list.html:396 #: assets/templates/assets/cmd_filter_detail.html:106 #: assets/templates/assets/system_user_assets.html:100 @@ -1663,12 +1671,12 @@ msgstr "比例" #: users/templates/users/user_group_list.html:194 #: users/templates/users/user_list.html:158 #: users/templates/users/user_list.html:190 -#: xpack/plugins/vault/templates/vault/vault.html:223 +#: xpack/plugins/vault/templates/vault/vault.html:224 msgid "Please select file" msgstr "选择文件" #: assets/templates/assets/asset_asset_user_list.html:16 -#: assets/templates/assets/asset_detail.html:23 assets/views/asset.py:70 +#: assets/templates/assets/asset_detail.html:23 assets/views/asset.py:58 msgid "Asset user list" msgstr "资产用户列表" @@ -1677,7 +1685,7 @@ msgid "Asset users of" msgstr "资产用户" #: assets/templates/assets/asset_asset_user_list.html:47 -#: assets/templates/assets/asset_detail.html:148 +#: assets/templates/assets/asset_detail.html:144 #: terminal/templates/terminal/session_detail.html:81 #: users/templates/users/user_detail.html:138 #: users/templates/users/user_profile.html:146 @@ -1696,23 +1704,23 @@ msgstr "选择需要修改属性" msgid "Select all" msgstr "全选" -#: assets/templates/assets/asset_detail.html:96 +#: assets/templates/assets/asset_detail.html:92 msgid "CPU" msgstr "CPU" -#: assets/templates/assets/asset_detail.html:104 +#: assets/templates/assets/asset_detail.html:100 msgid "Disk" msgstr "硬盘" -#: assets/templates/assets/asset_detail.html:132 +#: assets/templates/assets/asset_detail.html:128 #: users/templates/users/user_detail.html:115 #: users/templates/users/user_profile.html:104 msgid "Date joined" msgstr "创建日期" -#: assets/templates/assets/asset_detail.html:154 +#: assets/templates/assets/asset_detail.html:150 #: assets/templates/assets/user_asset_list.html:46 -#: perms/models/asset_permission.py:96 perms/models/base.py:38 +#: perms/models/asset_permission.py:104 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 @@ -1726,11 +1734,11 @@ msgstr "创建日期" msgid "Active" msgstr "激活中" -#: assets/templates/assets/asset_detail.html:171 +#: assets/templates/assets/asset_detail.html:167 msgid "Refresh hardware" msgstr "更新硬件信息" -#: assets/templates/assets/asset_detail.html:174 +#: assets/templates/assets/asset_detail.html:170 msgid "Refresh" msgstr "刷新" @@ -1743,7 +1751,7 @@ msgstr "" "左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的," "右侧是属于该节点下的资产" -#: assets/templates/assets/asset_list.html:61 assets/views/asset.py:129 +#: assets/templates/assets/asset_list.html:61 assets/views/asset.py:107 msgid "Create asset" msgstr "创建资产" @@ -2038,26 +2046,26 @@ msgstr "系统用户删除失败" msgid "Admin user list" msgstr "管理用户列表" -#: assets/views/admin_user.py:83 assets/views/admin_user.py:108 +#: assets/views/admin_user.py:85 assets/views/admin_user.py:110 msgid "Admin user detail" msgstr "管理用户详情" -#: assets/views/asset.py:82 templates/_nav_user.html:4 +#: assets/views/asset.py:70 templates/_nav_user.html:4 msgid "My assets" msgstr "我的资产" -#: assets/views/asset.py:144 +#: assets/views/asset.py:134 +msgid "Update asset" +msgstr "更新资产" + +#: assets/views/asset.py:146 msgid "Bulk update asset success" msgstr "批量更新资产成功" -#: assets/views/asset.py:172 +#: assets/views/asset.py:174 msgid "Bulk update asset" msgstr "批量更新资产" -#: assets/views/asset.py:200 -msgid "Update asset" -msgstr "更新资产" - #: assets/views/cmd_filter.py:32 msgid "Command filter list" msgstr "命令过滤器列表" @@ -2437,7 +2445,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:36 +#: xpack/plugins/interface/models.py:39 msgid "Welcome to the Jumpserver open source fortress" msgstr "欢迎使用Jumpserver开源堡垒机" @@ -2973,7 +2981,7 @@ msgstr "更新任务内容: {}" #: ops/views/adhoc.py:45 ops/views/adhoc.py:71 ops/views/adhoc.py:85 #: ops/views/adhoc.py:99 ops/views/adhoc.py:113 ops/views/adhoc.py:127 -#: ops/views/adhoc.py:141 ops/views/command.py:47 ops/views/command.py:72 +#: ops/views/adhoc.py:141 ops/views/command.py:47 ops/views/command.py:77 msgid "Ops" msgstr "作业中心" @@ -2989,7 +2997,7 @@ msgstr "执行历史" msgid "Command execution list" msgstr "命令执行列表" -#: ops/views/command.py:73 templates/_nav_user.html:26 +#: ops/views/command.py:78 templates/_nav_user.html:26 msgid "Command execution" msgstr "命令执行" @@ -2998,7 +3006,7 @@ msgid "Organization" msgstr "组织" #: perms/forms/asset_permission.py:65 perms/forms/remote_app_permission.py:34 -#: perms/models/asset_permission.py:94 perms/models/base.py:37 +#: perms/models/asset_permission.py:102 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 @@ -3011,46 +3019,46 @@ msgstr "组织" msgid "User group" msgstr "用户组" -#: perms/forms/asset_permission.py:82 +#: perms/forms/asset_permission.py:81 msgid "" "Tips: The RDP protocol does not support separate controls for uploading or " "downloading files" msgstr "提示:RDP 协议不支持单独控制上传或下载文件" -#: perms/forms/asset_permission.py:92 perms/forms/remote_app_permission.py:47 +#: perms/forms/asset_permission.py:91 perms/forms/remote_app_permission.py:47 msgid "User or group at least one required" msgstr "用户和用户组至少选一个" -#: perms/forms/asset_permission.py:101 +#: perms/forms/asset_permission.py:100 msgid "Asset or group at least one required" msgstr "资产和节点至少选一个" -#: perms/models/asset_permission.py:26 settings/forms.py:143 +#: perms/models/asset_permission.py:27 settings/forms.py:143 msgid "All" msgstr "全部" -#: perms/models/asset_permission.py:28 +#: perms/models/asset_permission.py:29 msgid "Upload file" msgstr "上传文件" -#: perms/models/asset_permission.py:29 +#: perms/models/asset_permission.py:30 msgid "Download file" msgstr "下载文件" -#: perms/models/asset_permission.py:30 +#: perms/models/asset_permission.py:31 msgid "Upload download" msgstr "上传下载" -#: perms/models/asset_permission.py:72 +#: perms/models/asset_permission.py:80 msgid "Actions" msgstr "动作" -#: perms/models/asset_permission.py:76 perms/models/asset_permission.py:106 +#: perms/models/asset_permission.py:84 perms/models/asset_permission.py:114 #: templates/_nav.html:44 msgid "Asset permission" msgstr "资产授权" -#: perms/models/asset_permission.py:97 perms/models/base.py:40 +#: perms/models/asset_permission.py:105 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 @@ -4373,11 +4381,11 @@ msgid "" "You should use your ssh client tools connect terminal: {}

{}" msgstr "你可以使用ssh客户端工具连接终端" -#: users/api/user.py:93 +#: users/api/user.py:97 msgid "You do not have permission." msgstr "你没有权限" -#: users/api/user.py:186 +#: users/api/user.py:190 msgid "Could not reset self otp, use profile reset instead" msgstr "不能再该页面重置MFA, 请去个人信息页面重置" @@ -4494,7 +4502,7 @@ msgstr "复制你的公钥到这里" msgid "Select users" msgstr "选择用户" -#: users/models/user.py:37 users/models/user.py:439 +#: users/models/user.py:37 users/models/user.py:449 msgid "Administrator" msgstr "管理员" @@ -4544,7 +4552,7 @@ msgstr "最后更新密码日期" msgid "User auth from {}, go there change password" msgstr "用户认证源来自 {}, 请去相应系统修改密码" -#: users/models/user.py:442 +#: users/models/user.py:452 msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员" @@ -5305,26 +5313,25 @@ msgid "Password length" msgstr "密码长度" #: xpack/plugins/change_auth_plan/forms.py:45 -#: xpack/plugins/change_auth_plan/models.py:213 -msgid "* For security, do not change {} user's password" -msgstr "* 为了安全,禁止更改 {} 用户的密码" +msgid "* For security, please do not change root user's password" +msgstr "* 为了安全,请不要更改root用户的密码" -#: xpack/plugins/change_auth_plan/forms.py:55 +#: xpack/plugins/change_auth_plan/forms.py:54 msgid "* Please enter custom password" msgstr "* 请输入自定义密码" -#: xpack/plugins/change_auth_plan/forms.py:64 +#: xpack/plugins/change_auth_plan/forms.py:63 msgid "* Please enter a valid crontab expression" msgstr "* 请输入有效的 crontab 表达式" -#: xpack/plugins/change_auth_plan/forms.py:117 +#: xpack/plugins/change_auth_plan/forms.py:116 #: 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:121 +#: xpack/plugins/change_auth_plan/forms.py:120 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." @@ -5332,11 +5339,11 @@ msgstr "" "提示:用户名为将要修改的资产上的用户的用户名。如果用户存在,则修改密码;如果" "用户不存在,则创建用户。" -#: xpack/plugins/change_auth_plan/forms.py:125 +#: xpack/plugins/change_auth_plan/forms.py:124 msgid "Tips: (Units: hour)" msgstr "提示:(单位: 时)" -#: xpack/plugins/change_auth_plan/forms.py:126 +#: xpack/plugins/change_auth_plan/forms.py:125 msgid "" "eg: Every Sunday 03:05 run <5 3 * * 0>
Tips: Using 5 digits linux " "crontab expressions ( 0; + if (hasFile) { + var reader = new FileReader();//新建一个FileReader + console.log(typeof files[0]); + reader.readAsText(files[0], "UTF-8");//读取文件 + reader.onload = function(evt){ //读取完文件之后会回来这里 + ref.trigger("onload", evt.target.result); + }; + } else { + ref.trigger("onload", null); + } + + return ref +} +