From b18ca8c94f5155f101dd47fcb1576fe9f5d905bf Mon Sep 17 00:00:00 2001 From: BaiJiangJie <32935519+BaiJiangJie@users.noreply.github.com> Date: Wed, 22 May 2019 12:35:14 +0800 Subject: [PATCH 1/7] =?UTF-8?q?[Update]=20=E6=A0=A1=E9=AA=8C=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=AF=B9RemoteApp=E6=9D=83=E9=99=90API=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=9D=83=E9=99=90=E6=8E=A7=E5=88=B6=20(#2715)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/perms/api/user_permission.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/perms/api/user_permission.py b/apps/perms/api/user_permission.py index 7c934340e..377bd735c 100644 --- a/apps/perms/api/user_permission.py +++ b/apps/perms/api/user_permission.py @@ -512,6 +512,7 @@ class UserGrantedRemoteAppsAsTreeApi(ListAPIView): class ValidateUserRemoteAppPermissionApi(APIView): + permission_classes = (IsOrgAdminOrAppUser,) def get(self, request, *args, **kwargs): user_id = request.query_params.get('user_id', '') From 4cd3dd367099a40d8f18ae8e17da96ff6644034d Mon Sep 17 00:00:00 2001 From: BaiJiangJie <32935519+BaiJiangJie@users.noreply.github.com> Date: Wed, 22 May 2019 18:56:34 +0800 Subject: [PATCH 2/7] =?UTF-8?q?[Update]=20=E6=9B=B4=E6=96=B0RemoteApp=20(#?= =?UTF-8?q?2720)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Update] RemoteAppForm添加RemoteApp各类型参数保存逻辑 * [Update] RemoteApp添加默认应用路径 --- apps/applications/forms/remote_app.py | 21 ++++++++ .../remote_app_create_update.html | 48 +++++++++++++++---- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/apps/applications/forms/remote_app.py b/apps/applications/forms/remote_app.py index 88f1912e0..b5317fa1c 100644 --- a/apps/applications/forms/remote_app.py +++ b/apps/applications/forms/remote_app.py @@ -8,6 +8,7 @@ from orgs.mixins import OrgModelForm from assets.models import Asset, SystemUser from ..models import RemoteApp +from .. import const __all__ = [ @@ -109,3 +110,23 @@ class RemoteAppCreateUpdateForm(RemoteAppTypeForms, OrgModelForm): }) } + def _clean_params(self): + app_type = self.data.get('type') + fields = const.REMOTE_APP_TYPE_MAP_FIELDS.get(app_type, []) + params = {} + for field in fields: + name = field['name'] + value = self.cleaned_data[name] + params.update({name: value}) + return params + + def _save_params(self, instance): + params = self._clean_params() + instance.params = params + instance.save() + return instance + + def save(self, commit=True): + instance = super().save(commit=commit) + instance = self._save_params(instance) + return instance diff --git a/apps/applications/templates/applications/remote_app_create_update.html b/apps/applications/templates/applications/remote_app_create_update.html index e64b8994c..4a616fc49 100644 --- a/apps/applications/templates/applications/remote_app_create_update.html +++ b/apps/applications/templates/applications/remote_app_create_update.html @@ -64,28 +64,60 @@ {% block custom_foot_js %} {% endblock %} \ No newline at end of file From 2df1dd2bb1aa37527351212fdab861d1d5ffa643 Mon Sep 17 00:00:00 2001 From: BaiJiangJie <32935519+BaiJiangJie@users.noreply.github.com> Date: Thu, 23 May 2019 18:52:19 +0800 Subject: [PATCH 3/7] =?UTF-8?q?[Bugfix]=20LDAP=E5=90=8C=E6=AD=A5=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=88=97=E8=A1=A8=E4=B8=AD=E5=A6=82=E6=9E=9CAPI?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=88=B0=E7=9A=84=E7=94=A8=E6=88=B7=E5=90=8D?= =?UTF-8?q?=E4=B8=AD=E6=9C=89=E7=A9=BA=E6=A0=BC=EF=BC=8C=E5=9C=A8=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E4=B8=BAid=E7=9A=84=E6=97=B6=E5=80=99=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E4=BC=9A=E5=8F=96=E7=AC=AC=E4=B8=80=E4=B8=AA=E7=A9=BA?= =?UTF-8?q?=E6=A0=BC=E5=89=8D=E7=9A=84=E5=AD=97=E7=AC=A6=E4=B8=B2=E4=BD=9C?= =?UTF-8?q?=E4=B8=BA=E7=94=A8=E6=88=B7=E5=90=8D=EF=BC=8C=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E4=B8=8D=E4=BC=9A=E5=AF=BC=E5=85=A5=E7=94=A8=E6=88=B7=20(#2726?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/settings/templates/settings/_ldap_list_users_modal.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/settings/templates/settings/_ldap_list_users_modal.html b/apps/settings/templates/settings/_ldap_list_users_modal.html index 2009e9b58..9609d80ce 100644 --- a/apps/settings/templates/settings/_ldap_list_users_modal.html +++ b/apps/settings/templates/settings/_ldap_list_users_modal.html @@ -58,6 +58,9 @@ function initLdapUsersTable() { ele: $('#ldap_list_users_table'), ajax_url: '{% url "api-settings:ldap-user-list" %}', columnDefs: [ + {targets: 0, createdCell: function (td, cellData, rowData) { + $(td).html("".replace("ID_USERNAME", cellData)) + }}, {targets: 4, createdCell: function (td, cellData, rowData) { if(cellData){ $(td).html('') From 45cb39e9719691b7f4b15c0144ea3072bbc82211 Mon Sep 17 00:00:00 2001 From: BaiJiangJie <32935519+BaiJiangJie@users.noreply.github.com> Date: Thu, 23 May 2019 18:52:39 +0800 Subject: [PATCH 4/7] =?UTF-8?q?[Update]=20RemoteApp=E8=AE=BE=E7=BD=AEtype?= =?UTF-8?q?=20vSphere=20Client=E7=9A=84=E9=BB=98=E8=AE=A4=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=20(#2725)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/applications/const.py | 2 +- .../templates/applications/remote_app_create_update.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/applications/const.py b/apps/applications/const.py index b64b1a14b..a5b6da895 100644 --- a/apps/applications/const.py +++ b/apps/applications/const.py @@ -28,7 +28,7 @@ REMOTE_APP_TYPE_CHOICES = ( ( _('Virtualization tools'), ( - (REMOTE_APP_TYPE_VMWARE_CLIENT, 'VMware Client'), + (REMOTE_APP_TYPE_VMWARE_CLIENT, 'vSphere Client'), ) ), (REMOTE_APP_TYPE_CUSTOM, _('Custom')), diff --git a/apps/applications/templates/applications/remote_app_create_update.html b/apps/applications/templates/applications/remote_app_create_update.html index 4a616fc49..ecd7254a1 100644 --- a/apps/applications/templates/applications/remote_app_create_update.html +++ b/apps/applications/templates/applications/remote_app_create_update.html @@ -80,7 +80,7 @@ var app_type_map_default_fields_value = { 'app_path': 'C:\\Program Files\\MySQL\\MySQL Workbench 8.0 CE\\MySQLWorkbench.exe' }, 'vmware_client': { - 'app_path': '' + 'app_path': 'C:\\Program Files (x86)\\VMware\\Infrastructure\\Virtual Infrastructure Client\\Launcher\\VpxClient.exe' }, 'custom': {'app_path': ''} }; From b79107380226f14324918794ac8832f001e6e766 Mon Sep 17 00:00:00 2001 From: xiaomao Date: Thu, 23 May 2019 18:55:28 +0800 Subject: [PATCH 5/7] =?UTF-8?q?[Update]=20=E8=A7=A3=E5=86=B3ldap=E6=98=A0?= =?UTF-8?q?=E5=B0=84is=5Factive=E7=AD=89=E5=AD=97=E6=AE=B5=E4=B8=BAbool?= =?UTF-8?q?=E5=80=BC=E7=9A=84=E9=97=AE=E9=A2=98=20(#2716)=20(#2721)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/backends/ldap.py | 14 ++++++++++++-- apps/settings/utils.py | 9 +++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/authentication/backends/ldap.py b/apps/authentication/backends/ldap.py index b35903420..2b202847b 100644 --- a/apps/authentication/backends/ldap.py +++ b/apps/authentication/backends/ldap.py @@ -86,7 +86,18 @@ class LDAPUser(_LDAPUser): return user_dn def _populate_user_from_attributes(self): - super()._populate_user_from_attributes() + for field, attr in self.settings.USER_ATTR_MAP.items(): + try: + value = self.attrs[attr][0] + except LookupError: + logger.warning("{} does not have a value for the attribute {}".format(self.dn, attr)) + else: + if not hasattr(self._user, field): + continue + if isinstance(getattr(self._user, field), bool): + value = bool(int(value == 'true')) + setattr(self._user, field, value) + if not hasattr(self._user, 'email') or '@' not in self._user.email: if '@' not in self._user.username: email = '{}@{}'.format(self._user.username, settings.EMAIL_SUFFIX) @@ -95,4 +106,3 @@ class LDAPUser(_LDAPUser): setattr(self._user, 'email', email) - diff --git a/apps/settings/utils.py b/apps/settings/utils.py index 6893974f7..56a7812e8 100644 --- a/apps/settings/utils.py +++ b/apps/settings/utils.py @@ -60,6 +60,8 @@ class LDAPUtil: for field, value in user_item.items(): if not hasattr(user, field): continue + if isinstance(getattr(user, field), bool): + value = bool(int(value == 'true')) setattr(user, field, value) user.save() @@ -82,6 +84,13 @@ class LDAPUtil: @staticmethod def create_user(user_item): + user = User() + for field, value in user_item.items(): + if not hasattr(user, field): + continue + if isinstance(getattr(user, field), bool): + value = bool(int(value == 'true')) + user_item[field] = value user_item['source'] = User.SOURCE_LDAP try: User.objects.create(**user_item) From 217bb8172255de4acf9805e4cf202806730c223a Mon Sep 17 00:00:00 2001 From: BaiJiangJie <32935519+BaiJiangJie@users.noreply.github.com> Date: Fri, 24 May 2019 11:11:50 +0800 Subject: [PATCH 6/7] =?UTF-8?q?[Update]=20=E4=BC=98=E5=8C=96LDAPUtil?= =?UTF-8?q?=E9=80=BB=E8=BE=91=20(#2728)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/backends/ldap.py | 15 +- apps/settings/api.py | 8 +- .../templates/settings/ldap_setting.html | 10 +- apps/settings/utils.py | 172 ++++++++---------- apps/users/utils.py | 10 + 5 files changed, 105 insertions(+), 110 deletions(-) diff --git a/apps/authentication/backends/ldap.py b/apps/authentication/backends/ldap.py index 2b202847b..3e58e08fa 100644 --- a/apps/authentication/backends/ldap.py +++ b/apps/authentication/backends/ldap.py @@ -7,6 +7,8 @@ from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django_auth_ldap.backend import _LDAPUser, LDAPBackend from django_auth_ldap.config import _LDAPConfig, LDAPSearch, LDAPSearchUnion +from users.utils import construct_user_email + logger = _LDAPConfig.get_logger() @@ -95,14 +97,9 @@ class LDAPUser(_LDAPUser): if not hasattr(self._user, field): continue if isinstance(getattr(self._user, field), bool): - value = bool(int(value == 'true')) + value = value.lower() in ['true', '1'] setattr(self._user, field, value) - if not hasattr(self._user, 'email') or '@' not in self._user.email: - if '@' not in self._user.username: - email = '{}@{}'.format(self._user.username, settings.EMAIL_SUFFIX) - else: - email = self._user.username - setattr(self._user, 'email', email) - - + email = getattr(self._user, 'email', '') + email = construct_user_email(email, self._user.username) + setattr(self._user, 'email', email) diff --git a/apps/settings/api.py b/apps/settings/api.py index a65df113d..f2b3eb558 100644 --- a/apps/settings/api.py +++ b/apps/settings/api.py @@ -79,7 +79,7 @@ class LDAPTestingAPI(APIView): util = self.get_ldap_util(serializer) try: - users = util.get_search_user_items() + users = util.search_user_items() except Exception as e: return Response({"error": str(e)}, status=401) @@ -95,7 +95,7 @@ class LDAPUserListApi(APIView): def get(self, request): util = LDAPUtil() try: - users = util.get_search_user_items() + users = util.search_user_items() except Exception as e: users = [] logger.error(e, exc_info=True) @@ -108,11 +108,11 @@ class LDAPUserSyncAPI(APIView): permission_classes = (IsOrgAdmin,) def post(self, request): - user_names = request.data.get('user_names', '') + username_list = request.data.get('username_list', []) util = LDAPUtil() try: - result = util.sync_users(username_set=user_names) + result = util.sync_users(username_list) except Exception as e: logger.error(e, exc_info=True) return Response({'error': str(e)}, status=401) diff --git a/apps/settings/templates/settings/ldap_setting.html b/apps/settings/templates/settings/ldap_setting.html index 63d56cea0..7eb8167ef 100644 --- a/apps/settings/templates/settings/ldap_setting.html +++ b/apps/settings/templates/settings/ldap_setting.html @@ -107,13 +107,13 @@ $(document).ready(function () { }); }) .on("click","#btn_ldap_modal_confirm",function () { - var user_names=[]; + var username_list=[]; $("tbody input[type='checkbox']:checked").each(function () { - user_names.push($(this).attr('id')); + username_list.push($(this).attr('id')); }); - if (user_names.length === 0){ - var msg = "{% trans 'User is not currently selected, please check the user you want to import'%}" + if (username_list.length === 0){ + var msg = "{% trans 'User is not currently selected, please check the user you want to import'%}"; toastr.error(msg); return } @@ -129,7 +129,7 @@ $(document).ready(function () { } APIUpdateAttr({ url: the_url, - body: JSON.stringify({'user_names':user_names}), + body: JSON.stringify({'username_list':username_list}), method: "POST", flash_message: false, success: success, diff --git a/apps/settings/utils.py b/apps/settings/utils.py index 56a7812e8..563f5fc3a 100644 --- a/apps/settings/utils.py +++ b/apps/settings/utils.py @@ -5,7 +5,9 @@ from ldap3 import Server, Connection from django.utils.translation import ugettext_lazy as _ from users.models import User +from users.utils import construct_user_email from common.utils import get_logger + from .models import settings @@ -17,11 +19,11 @@ class LDAPOUGroupException(Exception): class LDAPUtil: + _conn = None def __init__(self, use_settings_config=True, server_uri=None, bind_dn=None, password=None, use_ssl=None, search_ougroup=None, search_filter=None, attr_map=None, auth_ldap=None): - # config if use_settings_config: self._load_config_from_settings() @@ -45,6 +47,15 @@ class LDAPUtil: self.attr_map = settings.AUTH_LDAP_USER_ATTR_MAP self.auth_ldap = settings.AUTH_LDAP + @property + def connection(self): + if self._conn is None: + server = Server(self.server_uri, use_ssl=self.use_ssl) + conn = Connection(server, self.bind_dn, self.password) + conn.bind() + self._conn = conn + return self._conn + @staticmethod def get_user_by_username(username): try: @@ -55,79 +66,6 @@ class LDAPUtil: else: return user - @staticmethod - def _update_user(user, user_item): - for field, value in user_item.items(): - if not hasattr(user, field): - continue - if isinstance(getattr(user, field), bool): - value = bool(int(value == 'true')) - setattr(user, field, value) - user.save() - - def update_user(self, user_item): - user = self.get_user_by_username(user_item['username']) - if not user: - msg = _('User does not exist') - return False, msg - if user.source != User.SOURCE_LDAP: - msg = _('The user source is not LDAP') - return False, msg - - try: - self._update_user(user, user_item) - except Exception as e: - logger.error(e, exc_info=True) - return False, str(e) - else: - return True, None - - @staticmethod - def create_user(user_item): - user = User() - for field, value in user_item.items(): - if not hasattr(user, field): - continue - if isinstance(getattr(user, field), bool): - value = bool(int(value == 'true')) - user_item[field] = value - user_item['source'] = User.SOURCE_LDAP - try: - User.objects.create(**user_item) - except Exception as e: - logger.error(e, exc_info=True) - return False, str(e) - else: - return True, None - - @staticmethod - def get_or_construct_email(user_item): - if not user_item.get('email', None): - if '@' in user_item['username']: - email = user_item['username'] - else: - email = '{}@{}'.format( - user_item['username'], settings.EMAIL_SUFFIX) - else: - email = user_item['email'] - return email - - def create_or_update_users(self, user_items, force_update=True): - succeed = failed = 0 - for user_item in user_items: - user_item['email'] = self.get_or_construct_email(user_item) - exist = user_item.pop('existing', None) - if exist: - ok, error = self.update_user(user_item) - else: - ok, error = self.create_user(user_item) - if not ok: - failed += 1 - else: - succeed += 1 - result = {'total': len(user_items), 'succeed': succeed, 'failed': failed} - return result - def _ldap_entry_to_user_item(self, entry): user_item = {} for attr, mapping in self.attr_map.items(): @@ -136,36 +74,86 @@ class LDAPUtil: user_item[attr] = getattr(entry, mapping).value or '' return user_item - def get_connection(self): - server = Server(self.server_uri, use_ssl=self.use_ssl) - conn = Connection(server, self.bind_dn, self.password) - conn.bind() - return conn - - def get_search_user_items(self): - conn = self.get_connection() + def search_user_items(self): user_items = [] - search_ougroup = str(self.search_ougroup).split("|") - for search_ou in search_ougroup: - ok = conn.search( + for search_ou in str(self.search_ougroup).split("|"): + ok = self.connection.search( search_ou, self.search_filter % ({"user": "*"}), attributes=list(self.attr_map.values()) ) if not ok: error = _("Search no entry matched in ou {}".format(search_ou)) raise LDAPOUGroupException(error) - - for entry in conn.entries: + for entry in self.connection.entries: user_item = self._ldap_entry_to_user_item(entry) user = self.get_user_by_username(user_item['username']) user_item['existing'] = bool(user) user_items.append(user_item) - return user_items - def sync_users(self, username_set): - user_items = self.get_search_user_items() - if username_set: - user_items = [u for u in user_items if u['username'] in username_set] + def search_filter_user_items(self, username_list): + user_items = self.search_user_items() + if username_list: + user_items = [u for u in user_items if u['username'] in username_list] + return user_items + + @staticmethod + def save_user(user, user_item): + for field, value in user_item.items(): + if not hasattr(user, field): + continue + if isinstance(getattr(user, field), bool): + value = value.lower() in ['true', 1] + setattr(user, field, value) + user.save() + + def update_user(self, user_item): + user = self.get_user_by_username(user_item['username']) + if user.source != User.SOURCE_LDAP: + msg = _('The user source is not LDAP') + return False, msg + try: + self.save_user(user, user_item) + except Exception as e: + logger.error(e, exc_info=True) + return False, str(e) + else: + return True, None + + def create_user(self, user_item): + user = User(source=User.SOURCE_LDAP) + try: + self.save_user(user, user_item) + except Exception as e: + logger.error(e, exc_info=True) + return False, str(e) + else: + return True, None + + @staticmethod + def construct_user_email(user_item): + username = user_item['username'] + email = user_item.get('email', '') + email = construct_user_email(username, email) + return email + + def create_or_update_users(self, user_items, force_update=True): + succeed = failed = 0 + for user_item in user_items: + exist = user_item.pop('existing', False) + user_item['email'] = self.construct_user_email(user_item) + if not exist: + ok, error = self.create_user(user_item) + else: + ok, error = self.update_user(user_item) + if not ok: + failed += 1 + else: + succeed += 1 + result = {'total': len(user_items), 'succeed': succeed, 'failed': failed} + return result + + def sync_users(self, username_list): + user_items = self.search_filter_user_items(username_list) result = self.create_or_update_users(user_items) return result diff --git a/apps/users/utils.py b/apps/users/utils.py index e8f361ffa..8e461bf54 100644 --- a/apps/users/utils.py +++ b/apps/users/utils.py @@ -313,3 +313,13 @@ def is_need_unblock(key_block): if not cache.get(key_block): return False return True + + +def construct_user_email(username, email): + if '@' not in email: + if '@' in username: + email = username + else: + email = '{}@{}'.format(username, settings.EMAIL_SUFFIX) + return email + From b7eac837f75bf75c947b763a110c585b007a72a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AB=E5=8D=83=E6=B5=81?= <40739051+jym503558564@users.noreply.github.com> Date: Fri, 24 May 2019 18:12:58 +0800 Subject: [PATCH 7/7] =?UTF-8?q?[Update]=20=E5=88=9B=E5=BB=BA=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E8=87=AA=E5=AE=9A=E4=B9=89=E9=82=AE=E4=BB=B6=E5=86=85?= =?UTF-8?q?=E5=AE=B9=20(#2703)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Update] 增加创建用户自定义邮件内容功能 * [Update] 优化自定义创建用户邮件功能 * [Update] 修改自定义邮件内容的小图标icon * [Update] 发送邮件引入样式,避免不同浏览器不显示邮件格式问题 * [Update] 优化创建用户自定义邮件内容 * [Update] 修改翻译 * [Update] 优化邮件内容的变量名 * [Update]优化自定义邮件内容 * [Update] 修改小问题 --- apps/jumpserver/settings.py | 6 + apps/locale/zh/LC_MESSAGES/django.mo | Bin 75055 -> 76566 bytes apps/locale/zh/LC_MESSAGES/django.po | 422 +++++++++++------- apps/settings/forms.py | 23 + .../templates/settings/basic_setting.html | 3 + .../settings/email_content_setting.html | 72 +++ .../templates/settings/email_setting.html | 3 + .../templates/settings/ldap_setting.html | 3 + .../templates/settings/security_setting.html | 3 + .../templates/settings/terminal_setting.html | 3 + apps/settings/urls/view_urls.py | 1 + apps/settings/views.py | 28 +- apps/users/utils.py | 67 ++- 13 files changed, 450 insertions(+), 184 deletions(-) create mode 100644 apps/settings/templates/settings/email_content_setting.html diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py index bdc71ae3c..97859ec6d 100644 --- a/apps/jumpserver/settings.py +++ b/apps/jumpserver/settings.py @@ -357,6 +357,12 @@ EMAIL_USE_SSL = False EMAIL_USE_TLS = False EMAIL_SUBJECT_PREFIX = '[JMS] ' +#Email custom content +EMAIL_CUSTOM_USER_CREATED_SUBJECT = '' +EMAIL_CUSTOM_USER_CREATED_HONORIFIC = '' +EMAIL_CUSTOM_USER_CREATED_BODY = '' +EMAIL_CUSTOM_USER_CREATED_SIGNATURE = '' + REST_FRAMEWORK = { # Use Django's standard `django.contrib.auth` permissions, # or allow read-only access for unauthenticated users. diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 58ec179b83bd35b8c88e98ab8aefe011277ccf4c..cc3a0249dbb06b08f685868c4acd68f3b30d198b 100644 GIT binary patch delta 24137 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 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 823a3b07c..875e91c25 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-05-21 21:09+0800\n" +"POT-Creation-Date: 2019-05-24 12:02+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -33,45 +33,45 @@ msgstr "虚拟化工具" msgid "Custom" msgstr "自定义" -#: applications/forms/remote_app.py:20 +#: applications/forms/remote_app.py:21 msgid "Target URL" msgstr "目标URL" -#: applications/forms/remote_app.py:23 applications/forms/remote_app.py:52 -#: applications/forms/remote_app.py:68 +#: applications/forms/remote_app.py:24 applications/forms/remote_app.py:53 +#: applications/forms/remote_app.py:69 msgid "Login username" msgstr "登录账号" -#: applications/forms/remote_app.py:27 applications/forms/remote_app.py:56 -#: applications/forms/remote_app.py:72 +#: applications/forms/remote_app.py:28 applications/forms/remote_app.py:57 +#: applications/forms/remote_app.py:73 msgid "Login password" msgstr "登录密码" -#: applications/forms/remote_app.py:33 +#: applications/forms/remote_app.py:34 msgid "Database IP" msgstr "数据库IP" -#: applications/forms/remote_app.py:36 +#: applications/forms/remote_app.py:37 msgid "Database name" msgstr "数据库名" -#: applications/forms/remote_app.py:39 +#: applications/forms/remote_app.py:40 msgid "Database username" msgstr "数据库账号" -#: applications/forms/remote_app.py:43 +#: applications/forms/remote_app.py:44 msgid "Database password" msgstr "数据库密码" -#: applications/forms/remote_app.py:49 applications/forms/remote_app.py:65 +#: applications/forms/remote_app.py:50 applications/forms/remote_app.py:66 msgid "Target address" msgstr "目标地址" -#: applications/forms/remote_app.py:62 +#: applications/forms/remote_app.py:63 msgid "Operating parameter" msgstr "运行参数" -#: applications/forms/remote_app.py:105 applications/models/remote_app.py:23 +#: applications/forms/remote_app.py:106 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 @@ -101,12 +101,12 @@ msgstr "运行参数" #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:13 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:14 #: xpack/plugins/cloud/models.py:187 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:63 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:65 #: xpack/plugins/orgs/templates/orgs/org_list.html:16 msgid "Asset" msgstr "资产" -#: applications/forms/remote_app.py:108 applications/models/remote_app.py:27 +#: applications/forms/remote_app.py:109 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 @@ -161,8 +161,8 @@ msgstr "系统用户" #: settings/templates/settings/_ldap_list_users_modal.html:38 #: settings/templates/settings/command_storage_create.html:41 #: settings/templates/settings/replay_storage_create.html:44 -#: settings/templates/settings/terminal_setting.html:80 -#: settings/templates/settings/terminal_setting.html:102 terminal/models.py:22 +#: settings/templates/settings/terminal_setting.html:83 +#: settings/templates/settings/terminal_setting.html:105 terminal/models.py:22 #: terminal/models.py:241 terminal/templates/terminal/terminal_detail.html:43 #: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 #: users/models/user.py:61 users/templates/users/_select_user_modal.html:13 @@ -177,9 +177,9 @@ msgstr "系统用户" #: 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 #: xpack/plugins/cloud/models.py:49 xpack/plugins/cloud/models.py:119 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:50 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:52 #: xpack/plugins/cloud/templates/cloud/account_list.html:12 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:53 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:55 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:12 #: xpack/plugins/orgs/templates/orgs/org_detail.html:52 #: xpack/plugins/orgs/templates/orgs/org_list.html:12 @@ -224,6 +224,8 @@ msgstr "参数" msgid "Created by" msgstr "创建者" +# msgid "Created by" +# msgstr "创建者" #: applications/models/remote_app.py:46 #: applications/templates/applications/remote_app_detail.html:73 #: assets/models/asset.py:110 assets/models/cluster.py:26 @@ -242,12 +244,14 @@ msgstr "创建者" #: users/templates/users/user_group_detail.html:63 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:105 #: xpack/plugins/cloud/models.py:56 xpack/plugins/cloud/models.py:128 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:66 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:77 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:68 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:79 #: xpack/plugins/orgs/templates/orgs/org_detail.html:60 msgid "Date created" msgstr "创建日期" +# msgid "Date created" +# msgstr "创建日期" #: applications/models/remote_app.py:49 #: applications/templates/applications/remote_app_detail.html:81 #: applications/templates/applications/remote_app_list.html:24 @@ -282,9 +286,9 @@ msgstr "创建日期" #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:117 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:19 #: xpack/plugins/cloud/models.py:54 xpack/plugins/cloud/models.py:125 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:70 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:72 #: xpack/plugins/cloud/templates/cloud/account_list.html:15 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:69 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:71 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:16 #: xpack/plugins/orgs/templates/orgs/org_detail.html:64 #: xpack/plugins/orgs/templates/orgs/org_list.html:22 @@ -315,13 +319,14 @@ msgstr "远程应用" #: assets/templates/assets/label_create_update.html:18 #: perms/templates/perms/asset_permission_create_update.html:83 #: perms/templates/perms/remote_app_permission_create_update.html:83 -#: settings/templates/settings/basic_setting.html:61 +#: settings/templates/settings/basic_setting.html:64 #: settings/templates/settings/command_storage_create.html:79 -#: settings/templates/settings/email_setting.html:62 -#: settings/templates/settings/ldap_setting.html:61 +#: settings/templates/settings/email_content_setting.html:54 +#: settings/templates/settings/email_setting.html:65 +#: settings/templates/settings/ldap_setting.html:64 #: settings/templates/settings/replay_storage_create.html:152 -#: settings/templates/settings/security_setting.html:70 -#: settings/templates/settings/terminal_setting.html:68 +#: settings/templates/settings/security_setting.html:73 +#: settings/templates/settings/terminal_setting.html:71 #: terminal/templates/terminal/terminal_update.html:45 #: users/templates/users/_user.html:50 #: users/templates/users/user_bulk_update.html:23 @@ -353,13 +358,14 @@ msgstr "重置" #: audits/templates/audits/login_log_list.html:89 #: perms/templates/perms/asset_permission_create_update.html:84 #: perms/templates/perms/remote_app_permission_create_update.html:84 -#: settings/templates/settings/basic_setting.html:62 +#: settings/templates/settings/basic_setting.html:65 #: settings/templates/settings/command_storage_create.html:80 -#: settings/templates/settings/email_setting.html:63 -#: settings/templates/settings/ldap_setting.html:64 +#: settings/templates/settings/email_content_setting.html:55 +#: settings/templates/settings/email_setting.html:66 +#: settings/templates/settings/ldap_setting.html:67 #: settings/templates/settings/replay_storage_create.html:153 -#: settings/templates/settings/security_setting.html:71 -#: settings/templates/settings/terminal_setting.html:70 +#: settings/templates/settings/security_setting.html:74 +#: settings/templates/settings/terminal_setting.html:73 #: terminal/templates/terminal/command_list.html:103 #: terminal/templates/terminal/session_list.html:126 #: terminal/templates/terminal/terminal_update.html:46 @@ -437,11 +443,11 @@ msgstr "详情" #: users/templates/users/user_profile.html:187 #: users/templates/users/user_profile.html:196 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:29 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:55 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:23 -#: xpack/plugins/cloud/templates/cloud/account_list.html:39 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:54 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:25 +#: xpack/plugins/cloud/templates/cloud/account_list.html:38 #: xpack/plugins/orgs/templates/orgs/org_detail.html:25 -#: xpack/plugins/orgs/templates/orgs/org_list.html:87 +#: xpack/plugins/orgs/templates/orgs/org_list.html:85 msgid "Update" msgstr "更新" @@ -466,8 +472,8 @@ msgstr "更新" #: perms/templates/perms/asset_permission_list.html:182 #: perms/templates/perms/remote_app_permission_detail.html:34 #: perms/templates/perms/remote_app_permission_list.html:60 -#: settings/templates/settings/terminal_setting.html:90 -#: settings/templates/settings/terminal_setting.html:112 +#: settings/templates/settings/terminal_setting.html:93 +#: settings/templates/settings/terminal_setting.html:115 #: terminal/templates/terminal/terminal_list.html:74 #: users/templates/users/user_detail.html:30 #: users/templates/users/user_group_detail.html:32 @@ -475,13 +481,13 @@ msgstr "更新" #: users/templates/users/user_list.html:104 #: users/templates/users/user_list.html:108 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:33 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:57 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:27 -#: xpack/plugins/cloud/templates/cloud/account_list.html:41 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:30 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:55 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:56 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:29 +#: xpack/plugins/cloud/templates/cloud/account_list.html:40 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:32 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:54 #: xpack/plugins/orgs/templates/orgs/org_detail.html:29 -#: xpack/plugins/orgs/templates/orgs/org_list.html:89 +#: xpack/plugins/orgs/templates/orgs/org_list.html:87 msgid "Delete" msgstr "删除" @@ -528,8 +534,8 @@ msgstr "创建远程应用" #: perms/templates/perms/asset_permission_list.html:60 #: perms/templates/perms/asset_permission_list.html:134 #: perms/templates/perms/remote_app_permission_list.html:19 -#: settings/templates/settings/terminal_setting.html:82 -#: settings/templates/settings/terminal_setting.html:104 +#: settings/templates/settings/terminal_setting.html:85 +#: settings/templates/settings/terminal_setting.html:107 #: terminal/templates/terminal/session_list.html:81 #: terminal/templates/terminal/terminal_list.html:36 #: users/templates/users/user_group_list.html:38 @@ -618,7 +624,7 @@ msgstr "节点管理" #: assets/models/cluster.py:19 assets/models/user.py:91 #: assets/templates/assets/asset_detail.html:80 templates/_nav.html:24 #: xpack/plugins/cloud/models.py:124 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:65 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:67 #: xpack/plugins/orgs/templates/orgs/org_list.html:18 msgid "Admin user" msgstr "管理用户" @@ -655,8 +661,8 @@ msgstr "网域" #: 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 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:61 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:64 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:63 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:66 msgid "Node" msgstr "节点" @@ -1069,8 +1075,8 @@ msgstr "过滤器" #: perms/templates/perms/remote_app_permission_remote_app.html:54 #: settings/templates/settings/command_storage_create.html:31 #: settings/templates/settings/replay_storage_create.html:31 -#: settings/templates/settings/terminal_setting.html:81 -#: settings/templates/settings/terminal_setting.html:103 +#: settings/templates/settings/terminal_setting.html:84 +#: settings/templates/settings/terminal_setting.html:106 msgid "Type" msgstr "类型" @@ -1382,7 +1388,7 @@ msgstr "需要二次认证来查看账号信息" #: assets/templates/assets/system_user_asset.html:112 #: assets/templates/assets/system_user_detail.html:182 #: assets/templates/assets/system_user_list.html:168 -#: settings/templates/settings/terminal_setting.html:165 +#: settings/templates/settings/terminal_setting.html:168 #: templates/_modal.html:23 terminal/templates/terminal/session_detail.html:108 #: users/templates/users/user_detail.html:388 #: users/templates/users/user_detail.html:414 @@ -1409,7 +1415,7 @@ msgstr "获取认证信息错误" #: assets/templates/assets/_asset_user_view_auth_modal.html:139 #: assets/templates/assets/_user_asset_detail_modal.html:23 -#: settings/templates/settings/_ldap_list_users_modal.html:96 +#: settings/templates/settings/_ldap_list_users_modal.html:99 #: templates/_modal.html:22 msgid "Close" msgstr "关闭" @@ -1578,7 +1584,7 @@ msgstr "导出" #: assets/templates/assets/admin_user_list.html:24 #: assets/templates/assets/asset_list.html:81 #: assets/templates/assets/system_user_list.html:28 -#: settings/templates/settings/_ldap_list_users_modal.html:97 +#: settings/templates/settings/_ldap_list_users_modal.html:100 #: users/templates/users/user_group_list.html:15 #: users/templates/users/user_list.html:15 #: xpack/plugins/license/templates/license/license_detail.html:110 @@ -1799,7 +1805,7 @@ msgstr "删除选择资产" #: assets/templates/assets/asset_list.html:698 #: assets/templates/assets/system_user_list.html:166 -#: settings/templates/settings/terminal_setting.html:163 +#: settings/templates/settings/terminal_setting.html:166 #: users/templates/users/user_detail.html:386 #: users/templates/users/user_detail.html:412 #: users/templates/users/user_detail.html:480 @@ -1903,8 +1909,8 @@ msgstr "创建网关" #: assets/templates/assets/domain_gateway_list.html:99 #: assets/templates/assets/domain_gateway_list.html:101 -#: settings/templates/settings/email_setting.html:61 -#: settings/templates/settings/ldap_setting.html:62 +#: settings/templates/settings/email_setting.html:64 +#: settings/templates/settings/ldap_setting.html:65 msgid "Test connection" msgstr "测试连接" @@ -2227,7 +2233,7 @@ msgstr "原因" #: audits/models.py:101 audits/templates/audits/login_log_list.html:58 #: xpack/plugins/cloud/models.py:171 xpack/plugins/cloud/models.py:188 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:70 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:65 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:67 msgid "Status" msgstr "状态" @@ -2267,7 +2273,7 @@ msgstr "选择用户" #: terminal/templates/terminal/command_list.html:60 #: terminal/templates/terminal/session_list.html:61 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:52 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:48 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:50 msgid "Search" msgstr "搜索" @@ -2277,7 +2283,7 @@ msgstr "搜索" #: ops/templates/ops/task_detail.html:56 #: terminal/templates/terminal/session_list.html:70 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:64 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:60 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:62 msgid "ID" msgstr "ID" @@ -2679,7 +2685,7 @@ msgid "Become" msgstr "Become" #: ops/models/adhoc.py:166 users/templates/users/user_group_detail.html:59 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:62 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:64 #: xpack/plugins/orgs/templates/orgs/org_detail.html:56 msgid "Create by" msgstr "创建者" @@ -2925,8 +2931,8 @@ msgstr "版本" #: ops/templates/ops/task_list.html:63 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:137 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:53 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:53 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:52 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:52 msgid "Run" msgstr "执行" @@ -3050,8 +3056,8 @@ msgstr "添加资产" #: perms/templates/perms/remote_app_permission_remote_app.html:96 #: perms/templates/perms/remote_app_permission_user.html:96 #: perms/templates/perms/remote_app_permission_user.html:124 -#: settings/templates/settings/terminal_setting.html:95 -#: settings/templates/settings/terminal_setting.html:117 +#: settings/templates/settings/terminal_setting.html:98 +#: settings/templates/settings/terminal_setting.html:120 #: users/templates/users/user_group_detail.html:95 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:93 #: xpack/plugins/orgs/templates/orgs/org_detail.html:93 @@ -3111,7 +3117,7 @@ msgstr "创建授权规则" #: perms/templates/perms/asset_permission_list.html:73 #: perms/templates/perms/remote_app_permission_list.html:18 #: users/templates/users/user_list.html:40 xpack/plugins/cloud/models.py:53 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:58 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:60 #: xpack/plugins/cloud/templates/cloud/account_list.html:14 msgid "Validity" msgstr "有效" @@ -3246,7 +3252,7 @@ msgid "Create succeed" msgstr "创建成功" #: settings/api.py:166 settings/api.py:204 -#: settings/templates/settings/terminal_setting.html:151 +#: settings/templates/settings/terminal_setting.html:154 msgid "Delete succeed" msgstr "删除成功" @@ -3484,6 +3490,40 @@ msgid "" "characters" msgstr "开启后,用户密码修改、重置必须包含特殊字符" +#: settings/forms.py:248 +msgid "Create user email subject" +msgstr "创建用户邮件的主题" + +#: settings/forms.py:249 +msgid "" +"Tips: When creating a user, send the subject of the email (eg:Create account " +"successfully)" +msgstr "提示: 创建用户时,发送设置密码邮件的主题 (例如: 创建用户成功)" + +#: settings/forms.py:253 +msgid "Create user honorific" +msgstr "创建用户邮件的敬语" + +#: settings/forms.py:254 +msgid "Tips: When creating a user, send the honorific of the email (eg:Hello)" +msgstr "提示: 创建用户时,发送设置密码邮件的敬语 (例如: 您好)" + +#: settings/forms.py:259 +msgid "Create user email content" +msgstr "创建用户邮件的内容" + +#: settings/forms.py:260 +msgid "Tips:When creating a user, send the content of the email" +msgstr "提示: 创建用户时,发送设置密码邮件的内容" + +#: settings/forms.py:263 +msgid "Signature" +msgstr "署名" + +#: settings/forms.py:264 +msgid "Tips: Email signature (eg:jumpserver)" +msgstr "提示: 邮件的署名 (例如: jumpserver)" + #: settings/models.py:128 users/templates/users/reset_password.html:68 #: users/templates/users/user_profile.html:20 msgid "Setting" @@ -3508,15 +3548,17 @@ msgid "Existing" msgstr "已存在" #: settings/templates/settings/basic_setting.html:15 +#: settings/templates/settings/email_content_setting.html:15 #: settings/templates/settings/email_setting.html:15 #: settings/templates/settings/ldap_setting.html:15 #: settings/templates/settings/security_setting.html:15 #: settings/templates/settings/terminal_setting.html:16 -#: settings/templates/settings/terminal_setting.html:46 settings/views.py:19 +#: settings/templates/settings/terminal_setting.html:49 settings/views.py:19 msgid "Basic setting" msgstr "基本设置" #: settings/templates/settings/basic_setting.html:18 +#: settings/templates/settings/email_content_setting.html:18 #: settings/templates/settings/email_setting.html:18 #: settings/templates/settings/ldap_setting.html:18 #: settings/templates/settings/security_setting.html:18 @@ -3525,27 +3567,39 @@ msgid "Email setting" msgstr "邮件设置" #: settings/templates/settings/basic_setting.html:21 +#: settings/templates/settings/email_content_setting.html:21 #: settings/templates/settings/email_setting.html:21 #: settings/templates/settings/ldap_setting.html:21 #: settings/templates/settings/security_setting.html:21 -#: settings/templates/settings/terminal_setting.html:24 settings/views.py:71 -msgid "LDAP setting" -msgstr "LDAP设置" +#: settings/templates/settings/terminal_setting.html:23 settings/views.py:178 +msgid "Email content setting" +msgstr "邮件内容设置" #: settings/templates/settings/basic_setting.html:24 +#: settings/templates/settings/email_content_setting.html:24 #: settings/templates/settings/email_setting.html:24 #: settings/templates/settings/ldap_setting.html:24 #: settings/templates/settings/security_setting.html:24 -#: settings/templates/settings/terminal_setting.html:28 settings/views.py:100 -msgid "Terminal setting" -msgstr "终端设置" +#: settings/templates/settings/terminal_setting.html:27 settings/views.py:71 +msgid "LDAP setting" +msgstr "LDAP设置" #: settings/templates/settings/basic_setting.html:27 +#: settings/templates/settings/email_content_setting.html:27 #: settings/templates/settings/email_setting.html:27 #: settings/templates/settings/ldap_setting.html:27 #: settings/templates/settings/security_setting.html:27 -#: settings/templates/settings/security_setting.html:42 -#: settings/templates/settings/terminal_setting.html:31 settings/views.py:152 +#: settings/templates/settings/terminal_setting.html:31 settings/views.py:100 +msgid "Terminal setting" +msgstr "终端设置" + +#: settings/templates/settings/basic_setting.html:30 +#: settings/templates/settings/email_content_setting.html:30 +#: settings/templates/settings/email_setting.html:30 +#: settings/templates/settings/ldap_setting.html:30 +#: settings/templates/settings/security_setting.html:30 +#: settings/templates/settings/security_setting.html:45 +#: settings/templates/settings/terminal_setting.html:34 settings/views.py:152 msgid "Security setting" msgstr "安全设置" @@ -3561,11 +3615,15 @@ msgstr "索引" msgid "Doc type" msgstr "文档类型" -#: settings/templates/settings/ldap_setting.html:65 +#: settings/templates/settings/email_content_setting.html:45 +msgid "Create User setting" +msgstr "创建用户设置" + +#: settings/templates/settings/ldap_setting.html:68 msgid "Bulk import" msgstr "一键导入" -#: settings/templates/settings/ldap_setting.html:116 +#: settings/templates/settings/ldap_setting.html:119 msgid "" "User is not currently selected, please check the user you want to import" msgstr "当前无勾选用户,请勾选你想要导入的用户" @@ -3627,8 +3685,8 @@ msgstr "端点后缀" #: settings/templates/settings/replay_storage_create.html:136 #: xpack/plugins/cloud/models.py:186 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:81 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:62 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:83 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:64 msgid "Region" msgstr "地域" @@ -3652,48 +3710,48 @@ msgstr "提交中" msgid "Endpoint need contain protocol, ex: http" msgstr "端点需要包含协议,如 http" -#: settings/templates/settings/security_setting.html:46 +#: settings/templates/settings/security_setting.html:49 msgid "Password check rule" msgstr "密码校验规则" -#: settings/templates/settings/terminal_setting.html:76 terminal/forms.py:27 +#: settings/templates/settings/terminal_setting.html:79 terminal/forms.py:27 #: terminal/models.py:26 msgid "Command storage" msgstr "命令存储" -#: settings/templates/settings/terminal_setting.html:98 terminal/forms.py:32 +#: settings/templates/settings/terminal_setting.html:101 terminal/forms.py:32 #: terminal/models.py:27 msgid "Replay storage" msgstr "录像存储" -#: settings/templates/settings/terminal_setting.html:154 +#: settings/templates/settings/terminal_setting.html:157 msgid "Delete failed" msgstr "删除失败" -#: settings/templates/settings/terminal_setting.html:159 +#: settings/templates/settings/terminal_setting.html:162 msgid "Are you sure about deleting it?" msgstr "您确定删除吗?" -#: settings/utils.py:69 +#: settings/utils.py:71 msgid "User does not exist" msgstr "用户不存在" -#: settings/utils.py:72 +#: settings/utils.py:74 msgid "The user source is not LDAP" msgstr "用户来源不是LDAP" -#: settings/utils.py:146 +#: settings/utils.py:155 msgid "Search no entry matched in ou {}" msgstr "在ou:{}中没有匹配条目" #: settings/views.py:18 settings/views.py:44 settings/views.py:70 #: settings/views.py:99 settings/views.py:126 settings/views.py:138 -#: settings/views.py:151 templates/_nav.html:118 +#: settings/views.py:151 settings/views.py:177 templates/_nav.html:118 msgid "Settings" msgstr "系统设置" #: settings/views.py:29 settings/views.py:55 settings/views.py:81 -#: settings/views.py:112 settings/views.py:162 +#: settings/views.py:112 settings/views.py:162 settings/views.py:188 msgid "Update setting successfully" msgstr "更新设置成功" @@ -4464,7 +4522,7 @@ msgstr "安全令牌验证" #: users/templates/users/_base_otp.html:44 users/templates/users/_user.html:13 #: users/templates/users/user_profile_update.html:51 #: xpack/plugins/cloud/models.py:120 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:57 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:59 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:13 msgid "Account" msgstr "账户" @@ -4572,7 +4630,7 @@ msgid "Always young, always with tears in my eyes. Stay foolish Stay hungry" msgstr "永远年轻,永远热泪盈眶 stay foolish stay hungry" #: users/templates/users/reset_password.html:46 -#: users/templates/users/user_detail.html:373 users/utils.py:77 +#: users/templates/users/user_detail.html:373 users/utils.py:98 msgid "Reset password" msgstr "重置密码" @@ -4893,55 +4951,60 @@ msgid "" msgstr "新的公钥已设置成功,请下载对应的私钥" #: users/utils.py:38 -msgid "Create account successfully" -msgstr "创建账户成功" - -#: users/utils.py:40 #, python-format msgid "" "\n" -" Hello %(name)s:\n" -"
\n" -" Your account has been created successfully\n" -"
\n" -" Username: %(username)s\n" -"
\n" -" click " -"here to set your password\n" -"
\n" -" This link is valid for 1 hour. After it expires, \n" +"

\n" +" \n" +" Username: %(username)s.\n" +" \n" +" \n" +" click here to set your password\n" +" \n" +" \n" +" This link is valid for 1 hour. After it expires, request new one\n" -"\n" -"
\n" -" ---\n" -"\n" -"
\n" -" Login direct\n" -"\n" -"
\n" -" " +"
\n" +" \n" +" Login direct\n" +" \n" +"

\n" +" " msgstr "" "\n" -" 你好 %(name)s:\n" -"
\n" -" 恭喜您,您的账号已经创建成功
\n" -" 用户名: %(username)s\n" -"
\n" -" 请点击这" -"里设置密码
\n" -" 这个链接有效期1小时, 超过时间您可以 重新申请\n" -"\n" -"
\n" -" ---\n" -"\n" -"
\n" -" Login direct\n" -"\n" -"
\n" +" \n" +"

\n" +" \n" +" 用户名: %(username)s.\n" +" \n" +" \n" +" " +"请点击这里设置密码\n" +" \n" +" \n" +" 这个链接有效期1小时, 超过时间您可以 重新申请\n" +" \n" +" \n" +" ---登录页面\n" +" \n" +"

\n" " " -#: users/utils.py:79 +#: users/utils.py:73 +msgid "Create account successfully" +msgstr "创建账户成功" + +#: users/utils.py:77 +#, python-format +msgid "Hello %(name)s" +msgstr "您好 %(name)s" + +#: users/utils.py:100 #, python-format msgid "" "\n" @@ -4985,11 +5048,11 @@ msgstr "" "
\n" " " -#: users/utils.py:110 +#: users/utils.py:131 msgid "Security notice" msgstr "安全通知" -#: users/utils.py:112 +#: users/utils.py:133 #, python-format msgid "" "\n" @@ -5038,11 +5101,11 @@ msgstr "" "
\n" " " -#: users/utils.py:148 +#: users/utils.py:169 msgid "SSH Key Reset" msgstr "重置ssh密钥" -#: users/utils.py:150 +#: users/utils.py:171 #, python-format msgid "" "\n" @@ -5067,15 +5130,15 @@ msgstr "" "
\n" " " -#: users/utils.py:183 +#: users/utils.py:204 msgid "User not exist" msgstr "用户不存在" -#: users/utils.py:185 +#: users/utils.py:206 msgid "Disabled or expired" msgstr "禁用或失效" -#: users/utils.py:198 +#: users/utils.py:219 msgid "Password or SSH public key invalid" msgstr "密码或密钥不合法" @@ -5341,7 +5404,7 @@ msgid "Run plan manually" msgstr "手动执行计划" #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:179 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:102 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:101 msgid "Execute failed" msgstr "执行失败" @@ -5427,7 +5490,7 @@ msgid "Unavailable" msgstr "无效" #: xpack/plugins/cloud/models.py:50 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:54 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:56 #: xpack/plugins/cloud/templates/cloud/account_list.html:13 msgid "Provider" msgstr "云服务商" @@ -5453,7 +5516,7 @@ msgid "Instances" msgstr "实例" #: xpack/plugins/cloud/models.py:126 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:73 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:75 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:17 msgid "Date last sync" msgstr "最后同步日期" @@ -5472,7 +5535,7 @@ msgstr "" #: xpack/plugins/cloud/models.py:173 xpack/plugins/cloud/models.py:189 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:71 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:66 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:68 msgid "Date sync" msgstr "同步日期" @@ -5489,8 +5552,8 @@ msgid "Sync instance task history" msgstr "同步实例任务历史" #: xpack/plugins/cloud/models.py:185 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:89 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:61 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:91 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:63 msgid "Instance" msgstr "实例" @@ -5510,7 +5573,7 @@ msgstr "AWS (国际)" msgid "Qcloud" msgstr "腾讯云" -#: xpack/plugins/cloud/templates/cloud/account_detail.html:20 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:22 #: xpack/plugins/cloud/views.py:72 msgid "Account detail" msgstr "账户详情" @@ -5528,23 +5591,23 @@ msgstr "加载中..." msgid "Load failed" msgstr "加载失败" -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:20 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:22 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:25 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:21 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:23 #: xpack/plugins/cloud/views.py:122 msgid "Sync task detail" msgstr "同步任务详情" -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:23 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:25 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:28 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:24 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:26 #: xpack/plugins/cloud/views.py:137 msgid "Sync task history" msgstr "同步历史列表" -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:26 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:28 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:31 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:27 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:29 #: xpack/plugins/cloud/views.py:188 msgid "Sync instance list" msgstr "同步实例列表" @@ -5577,7 +5640,7 @@ msgstr "执行次数" msgid "Instance count" msgstr "实例个数" -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:93 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:92 msgid "Sync success" msgstr "同步成功" @@ -5661,7 +5724,6 @@ msgid "This will restore default Settings of the interface !!!" msgstr "您确定要恢复默认初始化吗?" #: xpack/plugins/interface/templates/interface/interface.html:107 -#: xpack/plugins/interface/views.py:53 msgid "Restore default successfully." msgstr "恢复默认成功!" @@ -5674,9 +5736,13 @@ msgid "Interface" msgstr "界面" #: xpack/plugins/interface/views.py:49 -msgid "It is already in the default setting state!" +msgid "It is already in the default setting state!" msgstr "当前已经是初始化状态!" +#: xpack/plugins/interface/views.py:53 +msgid "Restore default successfully!" +msgstr "恢复默认成功!" + #: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:94 #: xpack/plugins/license/templates/license/license_detail.html:50 #: xpack/plugins/license/templates/license/license_detail.html:55 @@ -5817,6 +5883,45 @@ msgstr "更新组织" #~ msgid "Update user groups" #~ msgstr "更新用户组" +# msgid "Update user" +# msgstr "更新用户" +#~ msgid "" +#~ "\n" +#~ " \n" +#~ "

\n" +#~ " \n" +#~ " click here to set your password\n" +#~ " \n" +#~ " \n" +#~ " This link is valid for 1 hour. After it expires, request new one\n" +#~ " \n" +#~ " \n" +#~ " Login direct\n" +#~ " \n" +#~ "

\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ " \n" +#~ "

\n" +#~ " \n" +#~ " 请点击这里设置密码\n" +#~ " \n" +#~ " \n" +#~ " 这个链接有效期1小时, 超过时间您可以, 重新申请\n" +#~ " \n" +#~ " \n" +#~ " Login direct\n" +#~ " \n" +#~ "

\n" +#~ " " + #~ msgid "Template" #~ msgstr "模板" @@ -5851,9 +5956,6 @@ msgstr "更新组织" #~ msgid "Select host" #~ msgstr "选择资产" -#~ msgid "Restore default successfully!" -#~ msgstr "恢复默认成功!" - #~ msgid "Beijing Duizhan Tech, Inc." #~ msgstr "北京堆栈科技有限公司" diff --git a/apps/settings/forms.py b/apps/settings/forms.py index d87845ea9..0ca565434 100644 --- a/apps/settings/forms.py +++ b/apps/settings/forms.py @@ -242,3 +242,26 @@ class SecuritySettingForm(BaseForm): 'and resets must contain special characters') ) + +class EmailContentSettingForm(BaseForm): + EMAIL_CUSTOM_USER_CREATED_SUBJECT = forms.CharField( + max_length=1024, required=False, label=_("Create user email subject"), + help_text=_("Tips: When creating a user, send the subject of the email" + " (eg:Create account successfully)") + ) + EMAIL_CUSTOM_USER_CREATED_HONORIFIC = forms.CharField( + max_length=1024, required=False, label=_("Create user honorific"), + help_text=_("Tips: When creating a user, send the honorific of the " + "email (eg:Hello)") + ) + EMAIL_CUSTOM_USER_CREATED_BODY = forms.CharField( + max_length=4096, required=False, widget=forms.Textarea(), + label=_('Create user email content'), + help_text=_('Tips:When creating a user, send the content of the email') + ) + EMAIL_CUSTOM_USER_CREATED_SIGNATURE = forms.CharField( + max_length=512, required=False, label=_("Signature"), + help_text=_("Tips: Email signature (eg:jumpserver)") + ) + + diff --git a/apps/settings/templates/settings/basic_setting.html b/apps/settings/templates/settings/basic_setting.html index 17c8057bc..4c26e8bb3 100644 --- a/apps/settings/templates/settings/basic_setting.html +++ b/apps/settings/templates/settings/basic_setting.html @@ -17,6 +17,9 @@
  • {% trans 'Email setting' %}
  • +
  • + {% trans 'Email content setting' %} +
  • {% trans 'LDAP setting' %}
  • diff --git a/apps/settings/templates/settings/email_content_setting.html b/apps/settings/templates/settings/email_content_setting.html new file mode 100644 index 000000000..16cac426e --- /dev/null +++ b/apps/settings/templates/settings/email_content_setting.html @@ -0,0 +1,72 @@ +{% extends 'base.html' %} +{% load static %} +{% load bootstrap3 %} +{% load i18n %} +{% load common_tags %} + +{% block content %} +
    +
    +
    +
    + +
    +
    +
    +
    + {% if form.non_field_errors %} +
    + {{ form.non_field_errors }} +
    + {% endif %} + {% csrf_token %} + +

    {% trans "Create User setting" %}

    + {% bootstrap_field form.EMAIL_CUSTOM_USER_CREATED_SUBJECT layout="horizontal" %} + {% bootstrap_field form.EMAIL_CUSTOM_USER_CREATED_HONORIFIC layout="horizontal" %} + {% bootstrap_field form.EMAIL_CUSTOM_USER_CREATED_BODY layout="horizontal" %} + {% bootstrap_field form.EMAIL_CUSTOM_USER_CREATED_SIGNATURE layout="horizontal" %} +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/settings/templates/settings/email_setting.html b/apps/settings/templates/settings/email_setting.html index 46846d7dc..46c4f5dac 100644 --- a/apps/settings/templates/settings/email_setting.html +++ b/apps/settings/templates/settings/email_setting.html @@ -17,6 +17,9 @@
  • {% trans 'Email setting' %}
  • +
  • + {% trans 'Email content setting' %} +
  • {% trans 'LDAP setting' %}
  • diff --git a/apps/settings/templates/settings/ldap_setting.html b/apps/settings/templates/settings/ldap_setting.html index 7eb8167ef..d19a84292 100644 --- a/apps/settings/templates/settings/ldap_setting.html +++ b/apps/settings/templates/settings/ldap_setting.html @@ -17,6 +17,9 @@
  • {% trans 'Email setting' %}
  • +
  • + {% trans 'Email content setting' %} +
  • {% trans 'LDAP setting' %}
  • diff --git a/apps/settings/templates/settings/security_setting.html b/apps/settings/templates/settings/security_setting.html index adc00191f..f13410cdf 100644 --- a/apps/settings/templates/settings/security_setting.html +++ b/apps/settings/templates/settings/security_setting.html @@ -16,6 +16,9 @@
  • {% trans 'Email setting' %} +
  • +
  • + {% trans 'Email content setting' %}
  • {% trans 'LDAP setting' %} diff --git a/apps/settings/templates/settings/terminal_setting.html b/apps/settings/templates/settings/terminal_setting.html index e6eb72982..3a9a4973d 100644 --- a/apps/settings/templates/settings/terminal_setting.html +++ b/apps/settings/templates/settings/terminal_setting.html @@ -18,6 +18,9 @@
  • {% trans 'Email setting' %} +
  • +
  • + {% trans 'Email content setting' %}
  • - Your account has been created successfully -
    - Username: %(username)s -
    -
    click here to set your password -
    - This link is valid for 1 hour. After it expires, request new one - -
    - --- - -
    - Login direct - -
    - """) % { - 'name': user.name, +def construct_user_created_email_body(user): + default_body = _(""" + +

    + + Username: %(username)s. + + + click here to set your password + + + This link is valid for 1 hour. After it expires, request new one + + + Login direct + +

    + """) % { 'username': user.username, 'rest_password_url': reverse('users:reset-password', external=True), 'rest_password_token': user.generate_reset_token(), @@ -64,6 +59,32 @@ def send_user_created_mail(user): 'email': user.email, 'login_url': reverse('authentication:login', external=True), } + + if settings.EMAIL_CUSTOM_USER_CREATED_BODY: + custom_body = '

    ' + settings.EMAIL_CUSTOM_USER_CREATED_BODY + '

    ' + else: + custom_body = '' + body = custom_body + default_body + return body + + +def send_user_created_mail(user): + recipient_list = [user.email] + subject = _('Create account successfully') + if settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT: + subject = settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT + + honorific = '

    ' + _('Hello %(name)s') % {'name': user.name} + ':

    ' + if settings.EMAIL_CUSTOM_USER_CREATED_HONORIFIC: + honorific = '

    ' + settings.EMAIL_CUSTOM_USER_CREATED_HONORIFIC + ':

    ' + + body = construct_user_created_email_body(user) + + signature = '

    jumpserver

    ' + if settings.EMAIL_CUSTOM_USER_CREATED_SIGNATURE: + signature = '

    ' + settings.EMAIL_CUSTOM_USER_CREATED_SIGNATURE + '

    ' + + message = honorific + body + signature if settings.DEBUG: try: print(message)