mirror of https://github.com/jumpserver/jumpserver
pref: 修改使用的消息内容 (#7061)
* perf: 再次优化通知 * pref: 修改使用的消息内容 * perf: 修复url地址 Co-authored-by: ibuler <ibuler@qq.com>pull/7063/head
parent
a0db2f6ef8
commit
c244cf5f43
|
@ -12,7 +12,5 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<small>
|
{% trans 'If you suspect that the login behavior is abnormal, please modify the account password in time.' %}
|
||||||
{% trans 'If you suspect that the login behavior is abnormal, please modify the account password in time.' %}
|
|
||||||
</small>
|
|
||||||
</p>
|
</p>
|
|
@ -1,15 +1,17 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% trans 'Hello' %} {{ user.name }},
|
<p>
|
||||||
<br>
|
{% trans 'Hello' %} {{ user.name }},
|
||||||
{% trans 'Please click the link below to reset your password, if not your request, concern your account security' %}
|
</p>
|
||||||
<br>
|
<p>
|
||||||
<br>
|
{% trans 'Please click the link below to reset your password, if not your request, concern your account security' %}
|
||||||
<a href="{{ rest_password_url }}?token={{ rest_password_token}}" class='showLink'>{% trans 'Click here reset password' %}</a>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<a href="{{ rest_password_url }}?token={{ rest_password_token}}" class='showLink'>{% trans 'Click here reset password' %}</a>
|
||||||
{% trans 'This link is valid for 1 hour. After it expires,' %} <a href="{{ forget_password_url }}?email={{ user.email }}">{% trans 'request new one' %}</a>
|
</p>
|
||||||
<br>
|
|
||||||
---
|
<p>
|
||||||
<br>
|
{% trans 'This link is valid for 1 hour. After it expires' %}
|
||||||
<a href="{{ login_url }}">{% trans 'Login direct' %}</a>
|
<a href="{{ forget_password_url }}?email={{ user.email }}">
|
||||||
<br>
|
{% trans 'request new one' %}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
|
@ -1,18 +1,14 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
<p>{% trans 'Hello' %} {{ name }},</p>
|
||||||
<p>{% trans 'Hello' %}: {{ name }},</p>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
{% trans 'Your password has just been successfully updated.' %}
|
{% trans 'Your password has just been successfully updated' %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{% trans 'IP' %}: {{ ip_address }} <br />
|
<b>{% trans 'IP' %}:</b> {{ ip_address }} <br />
|
||||||
{% trans 'Browser' %}: {{ browser }}
|
<b>{% trans 'Browser' %}:</b> {{ browser }}
|
||||||
</p>
|
</p>
|
||||||
<p>---</p>
|
|
||||||
<p>
|
<p>
|
||||||
<small>
|
{% trans 'If the password update was not initiated by you, your account may have security issues' %} <br />
|
||||||
{% trans 'If the password update was not initiated by you, your account may have security issues.' %} <br />
|
{% trans 'If you have any questions, you can contact the administrator' %}
|
||||||
{% trans 'If you have any questions, you can contact the administrator.' %}
|
|
||||||
</small>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -28,6 +28,10 @@ def local_now():
|
||||||
return as_current_tz(utc_now())
|
return as_current_tz(utc_now())
|
||||||
|
|
||||||
|
|
||||||
|
def local_now_display(fmt='%Y-%m-%d %H:%M:%S'):
|
||||||
|
return local_now().strftime(fmt)
|
||||||
|
|
||||||
|
|
||||||
_rest_dt_field = DateTimeField()
|
_rest_dt_field = DateTimeField()
|
||||||
dt_parser = _rest_dt_field.to_internal_value
|
dt_parser = _rest_dt_field.to_internal_value
|
||||||
dt_formatter = _rest_dt_field.to_representation
|
dt_formatter = _rest_dt_field.to_representation
|
||||||
|
|
|
@ -8,7 +8,6 @@ from django.http.response import JsonResponse, HttpResponse
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import AllowAny
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from django.conf import settings
|
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from users.models import User
|
from users.models import User
|
||||||
|
|
|
@ -4,27 +4,39 @@ from django.templatetags.static import static
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
default_context = {
|
||||||
|
'DEFAULT_PK': '00000000-0000-0000-0000-000000000000',
|
||||||
|
'LOGO_URL': static('img/logo.png'),
|
||||||
|
'LOGO_TEXT_URL': static('img/logo_text.png'),
|
||||||
|
'LOGIN_IMAGE_URL': static('img/login_image.jpg'),
|
||||||
|
'FAVICON_URL': static('img/facio.ico'),
|
||||||
|
'LOGIN_CAS_LOGO_URL': static('img/login_cas_logo.png'),
|
||||||
|
'LOGIN_WECOM_LOGO_URL': static('img/login_wecom_logo.png'),
|
||||||
|
'LOGIN_DINGTALK_LOGO_URL': static('img/login_dingtalk_logo.png'),
|
||||||
|
'LOGIN_FEISHU_LOGO_URL': static('img/login_feishu_logo.png'),
|
||||||
|
'JMS_TITLE': _('JumpServer Open Source Bastion Host'),
|
||||||
|
}
|
||||||
|
|
||||||
|
default_interface = {
|
||||||
|
'login_title': default_context['JMS_TITLE'],
|
||||||
|
'logo_logout': default_context['LOGO_URL'],
|
||||||
|
'logo_index': default_context['LOGO_TEXT_URL'],
|
||||||
|
'login_image': default_context['LOGIN_IMAGE_URL'],
|
||||||
|
'favicon': default_context['FAVICON_URL'],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def jumpserver_processor(request):
|
def jumpserver_processor(request):
|
||||||
# Setting default pk
|
# Setting default pk
|
||||||
context = {
|
context = default_context
|
||||||
'DEFAULT_PK': '00000000-0000-0000-0000-000000000000',
|
context.update({
|
||||||
'LOGO_URL': static('img/logo.png'),
|
|
||||||
'LOGO_TEXT_URL': static('img/logo_text.png'),
|
|
||||||
'LOGIN_IMAGE_URL': static('img/login_image.jpg'),
|
|
||||||
'FAVICON_URL': static('img/facio.ico'),
|
|
||||||
'LOGIN_CAS_LOGO_URL': static('img/login_cas_logo.png'),
|
|
||||||
'LOGIN_WECOM_LOGO_URL': static('img/login_wecom_logo.png'),
|
|
||||||
'LOGIN_DINGTALK_LOGO_URL': static('img/login_dingtalk_logo.png'),
|
|
||||||
'LOGIN_FEISHU_LOGO_URL': static('img/login_feishu_logo.png'),
|
|
||||||
'JMS_TITLE': _('JumpServer Open Source Bastion Host'),
|
|
||||||
'VERSION': settings.VERSION,
|
'VERSION': settings.VERSION,
|
||||||
'COPYRIGHT': 'FIT2CLOUD 飞致云' + ' © 2014-2021',
|
'COPYRIGHT': 'FIT2CLOUD 飞致云' + ' © 2014-2021',
|
||||||
'SECURITY_COMMAND_EXECUTION': settings.SECURITY_COMMAND_EXECUTION,
|
'SECURITY_COMMAND_EXECUTION': settings.SECURITY_COMMAND_EXECUTION,
|
||||||
'SECURITY_MFA_VERIFY_TTL': settings.SECURITY_MFA_VERIFY_TTL,
|
'SECURITY_MFA_VERIFY_TTL': settings.SECURITY_MFA_VERIFY_TTL,
|
||||||
'FORCE_SCRIPT_NAME': settings.FORCE_SCRIPT_NAME,
|
'FORCE_SCRIPT_NAME': settings.FORCE_SCRIPT_NAME,
|
||||||
'SECURITY_VIEW_AUTH_NEED_MFA': settings.SECURITY_VIEW_AUTH_NEED_MFA,
|
'SECURITY_VIEW_AUTH_NEED_MFA': settings.SECURITY_VIEW_AUTH_NEED_MFA,
|
||||||
}
|
})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:b5a90a96a51ef2f38d4530f3e5b79cd59b07dbca39f60bc35cde5ee0e364b210
|
oid sha256:b2663d90ceadd419c40abd472a3b5030b007b1e1db1fcaeda9893ff90cd7cdd6
|
||||||
size 91089
|
size 89955
|
||||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-10-21 18:50+0800\n"
|
"POT-Creation-Date: 2021-10-22 19:15+0800\n"
|
||||||
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
|
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
|
||||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||||
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
||||||
|
@ -85,8 +85,7 @@ msgstr "登录复核"
|
||||||
#: orgs/models.py:19 orgs/models.py:433 perms/models/base.py:45
|
#: orgs/models.py:19 orgs/models.py:433 perms/models/base.py:45
|
||||||
#: templates/index.html:78 terminal/backends/command/models.py:18
|
#: templates/index.html:78 terminal/backends/command/models.py:18
|
||||||
#: terminal/backends/command/serializers.py:12 terminal/models/session.py:38
|
#: terminal/backends/command/serializers.py:12 terminal/models/session.py:38
|
||||||
#: terminal/templates/terminal/_msg_command_alert.html:10
|
#: terminal/notifications.py:91 terminal/notifications.py:136
|
||||||
#: terminal/templates/terminal/_msg_command_execute_alert.html:4
|
|
||||||
#: tickets/models/comment.py:17 users/const.py:14 users/models/user.py:173
|
#: tickets/models/comment.py:17 users/const.py:14 users/models/user.py:173
|
||||||
#: users/models/user.py:801 users/models/user.py:827
|
#: users/models/user.py:801 users/models/user.py:827
|
||||||
#: users/serializers/group.py:19
|
#: users/serializers/group.py:19
|
||||||
|
@ -128,7 +127,7 @@ msgstr "系统用户"
|
||||||
#: audits/models.py:38 perms/models/asset_permission.py:99
|
#: audits/models.py:38 perms/models/asset_permission.py:99
|
||||||
#: templates/index.html:82 terminal/backends/command/models.py:19
|
#: templates/index.html:82 terminal/backends/command/models.py:19
|
||||||
#: terminal/backends/command/serializers.py:13 terminal/models/session.py:40
|
#: terminal/backends/command/serializers.py:13 terminal/models/session.py:40
|
||||||
#: terminal/templates/terminal/_msg_command_alert.html:7
|
#: terminal/notifications.py:90
|
||||||
#: users/templates/users/user_asset_permission.html:40
|
#: users/templates/users/user_asset_permission.html:40
|
||||||
#: users/templates/users/user_asset_permission.html:70
|
#: users/templates/users/user_asset_permission.html:70
|
||||||
#: xpack/plugins/change_auth_plan/models/asset.py:195
|
#: xpack/plugins/change_auth_plan/models/asset.py:195
|
||||||
|
@ -154,6 +153,7 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. "
|
||||||
#: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17
|
#: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17
|
||||||
#: authentication/templates/authentication/_msg_different_city.html:9
|
#: authentication/templates/authentication/_msg_different_city.html:9
|
||||||
#: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:595
|
#: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:595
|
||||||
|
#: users/templates/users/_msg_user_created.html:10
|
||||||
#: users/templates/users/_select_user_modal.html:14
|
#: users/templates/users/_select_user_modal.html:14
|
||||||
#: xpack/plugins/change_auth_plan/models/asset.py:35
|
#: xpack/plugins/change_auth_plan/models/asset.py:35
|
||||||
#: xpack/plugins/change_auth_plan/models/asset.py:191
|
#: xpack/plugins/change_auth_plan/models/asset.py:191
|
||||||
|
@ -174,7 +174,7 @@ msgstr ""
|
||||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:18
|
#: applications/serializers/attrs/application_type/mysql_workbench.py:18
|
||||||
#: assets/models/asset.py:180 assets/models/domain.py:61
|
#: assets/models/asset.py:180 assets/models/domain.py:61
|
||||||
#: assets/serializers/account.py:12
|
#: assets/serializers/account.py:12
|
||||||
#: authentication/templates/authentication/_msg_rest_password_success.html:9
|
#: authentication/templates/authentication/_msg_rest_password_success.html:8
|
||||||
#: settings/serializers/terminal.py:8
|
#: settings/serializers/terminal.py:8
|
||||||
#: users/templates/users/_granted_assets.html:26
|
#: users/templates/users/_granted_assets.html:26
|
||||||
#: users/templates/users/user_asset_permission.html:156
|
#: users/templates/users/user_asset_permission.html:156
|
||||||
|
@ -384,6 +384,7 @@ msgstr "目标URL"
|
||||||
#: authentication/forms.py:22
|
#: authentication/forms.py:22
|
||||||
#: authentication/templates/authentication/login.html:151
|
#: authentication/templates/authentication/login.html:151
|
||||||
#: settings/serializers/auth/ldap.py:44 users/forms/profile.py:21
|
#: settings/serializers/auth/ldap.py:44 users/forms/profile.py:21
|
||||||
|
#: users/templates/users/_msg_user_created.html:11
|
||||||
#: users/templates/users/user_otp_check_password.html:13
|
#: users/templates/users/user_otp_check_password.html:13
|
||||||
#: users/templates/users/user_password_update.html:43
|
#: users/templates/users/user_password_update.html:43
|
||||||
#: users/templates/users/user_password_verify.html:18
|
#: users/templates/users/user_password_verify.html:18
|
||||||
|
@ -647,7 +648,7 @@ msgstr "正则表达式"
|
||||||
|
|
||||||
#: assets/models/cmd_filter.py:41 ops/models/command.py:25
|
#: assets/models/cmd_filter.py:41 ops/models/command.py:25
|
||||||
#: terminal/backends/command/serializers.py:15 terminal/models/session.py:49
|
#: terminal/backends/command/serializers.py:15 terminal/models/session.py:49
|
||||||
#: terminal/templates/terminal/_msg_command_alert.html:4
|
#: terminal/templates/terminal/_msg_command_alert.html:12
|
||||||
#: terminal/templates/terminal/_msg_command_execute_alert.html:10
|
#: terminal/templates/terminal/_msg_command_execute_alert.html:10
|
||||||
msgid "Command"
|
msgid "Command"
|
||||||
msgstr "命令"
|
msgstr "命令"
|
||||||
|
@ -1445,7 +1446,7 @@ msgstr "{ApplicationPermission} 添加 {SystemUser}"
|
||||||
msgid "{ApplicationPermission} REMOVE {SystemUser}"
|
msgid "{ApplicationPermission} REMOVE {SystemUser}"
|
||||||
msgstr "{ApplicationPermission} 移除 {SystemUser}"
|
msgstr "{ApplicationPermission} 移除 {SystemUser}"
|
||||||
|
|
||||||
#: authentication/api/connection_token.py:235
|
#: authentication/api/connection_token.py:239
|
||||||
msgid "Invalid token"
|
msgid "Invalid token"
|
||||||
msgstr "无效的令牌"
|
msgstr "无效的令牌"
|
||||||
|
|
||||||
|
@ -1731,6 +1732,7 @@ msgid "Secret"
|
||||||
msgstr "密钥"
|
msgstr "密钥"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_access_key_modal.html:33
|
#: authentication/templates/authentication/_access_key_modal.html:33
|
||||||
|
#: terminal/notifications.py:93 terminal/notifications.py:138
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "日期"
|
msgstr "日期"
|
||||||
|
|
||||||
|
@ -1788,8 +1790,8 @@ msgid "Code error"
|
||||||
msgstr "代码错误"
|
msgstr "代码错误"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_msg_different_city.html:3
|
#: authentication/templates/authentication/_msg_different_city.html:3
|
||||||
#: authentication/templates/authentication/_msg_reset_password.html:2
|
#: authentication/templates/authentication/_msg_reset_password.html:3
|
||||||
#: authentication/templates/authentication/_msg_rest_password_success.html:3
|
#: authentication/templates/authentication/_msg_rest_password_success.html:2
|
||||||
#: perms/templates/perms/_msg_item_permissions_expire.html:3
|
#: perms/templates/perms/_msg_item_permissions_expire.html:3
|
||||||
#: perms/templates/perms/_msg_permed_items_expire.html:3
|
#: perms/templates/perms/_msg_permed_items_expire.html:3
|
||||||
#: users/templates/users/_msg_account_expire_reminder.html:4
|
#: users/templates/users/_msg_account_expire_reminder.html:4
|
||||||
|
@ -1807,53 +1809,48 @@ msgstr "你的账号存在异地登录行为,请关注。"
|
||||||
msgid "Login time"
|
msgid "Login time"
|
||||||
msgstr "登录日期"
|
msgstr "登录日期"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_msg_different_city.html:16
|
#: authentication/templates/authentication/_msg_different_city.html:15
|
||||||
msgid ""
|
msgid ""
|
||||||
"If you suspect that the login behavior is abnormal, please modify the "
|
"If you suspect that the login behavior is abnormal, please modify the "
|
||||||
"account password in time."
|
"account password in time."
|
||||||
msgstr "若怀疑此次登录行为异常,请及时修改账号密码"
|
msgstr "若怀疑此次登录行为异常,请及时修改账号密码"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_msg_reset_password.html:4
|
#: authentication/templates/authentication/_msg_reset_password.html:6
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please click the link below to reset your password, if not your request, "
|
"Please click the link below to reset your password, if not your request, "
|
||||||
"concern your account security"
|
"concern your account security"
|
||||||
msgstr "请点击下面链接重置密码, 如果不是您申请的,请关注账号安全"
|
msgstr "请点击下面链接重置密码, 如果不是您申请的,请关注账号安全"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_msg_reset_password.html:7
|
#: authentication/templates/authentication/_msg_reset_password.html:9
|
||||||
msgid "Click here reset password"
|
msgid "Click here reset password"
|
||||||
msgstr "点击这里重置密码"
|
msgstr "点击这里重置密码"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_msg_reset_password.html:10
|
#: authentication/templates/authentication/_msg_reset_password.html:13
|
||||||
msgid "This link is valid for 1 hour. After it expires,"
|
#: users/templates/users/_msg_user_created.html:17
|
||||||
|
msgid "This link is valid for 1 hour. After it expires"
|
||||||
msgstr "这个链接有效期1小时, 超过时间您可以"
|
msgstr "这个链接有效期1小时, 超过时间您可以"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_msg_reset_password.html:10
|
#: authentication/templates/authentication/_msg_reset_password.html:15
|
||||||
|
#: users/templates/users/_msg_user_created.html:18
|
||||||
msgid "request new one"
|
msgid "request new one"
|
||||||
msgstr "重新申请"
|
msgstr "重新申请"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_msg_reset_password.html:14
|
#: authentication/templates/authentication/_msg_rest_password_success.html:5
|
||||||
#: users/templates/users/_msg_password_expire_reminder.html:22
|
msgid "Your password has just been successfully updated"
|
||||||
#: users/templates/users/_msg_reset_mfa.html:11
|
msgstr "你的密码刚刚成功更新"
|
||||||
#: users/templates/users/_msg_reset_ssh_key.html:11
|
|
||||||
msgid "Login direct"
|
|
||||||
msgstr "直接登录"
|
|
||||||
|
|
||||||
#: authentication/templates/authentication/_msg_rest_password_success.html:6
|
#: authentication/templates/authentication/_msg_rest_password_success.html:9
|
||||||
msgid "Your password has just been successfully updated."
|
|
||||||
msgstr "你的密码刚刚已经成功更新。"
|
|
||||||
|
|
||||||
#: authentication/templates/authentication/_msg_rest_password_success.html:10
|
|
||||||
msgid "Browser"
|
msgid "Browser"
|
||||||
msgstr "浏览器"
|
msgstr "浏览器"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_msg_rest_password_success.html:15
|
#: authentication/templates/authentication/_msg_rest_password_success.html:12
|
||||||
msgid ""
|
msgid ""
|
||||||
"If the password update was not initiated by you, your account may have "
|
"If the password update was not initiated by you, your account may have "
|
||||||
"security issues."
|
"security issues"
|
||||||
msgstr "如果这次密码更新不是由你发起的,那么你的账号可能存在安全问题。"
|
msgstr "如果这次密码更新不是由你发起的,那么你的账号可能存在安全问题"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_msg_rest_password_success.html:16
|
#: authentication/templates/authentication/_msg_rest_password_success.html:13
|
||||||
msgid "If you have any questions, you can contact the administrator."
|
msgid "If you have any questions, you can contact the administrator"
|
||||||
msgstr "如果有疑问或需求,请联系系统管理员"
|
msgstr "如果有疑问或需求,请联系系统管理员"
|
||||||
|
|
||||||
#: authentication/templates/authentication/login.html:143
|
#: authentication/templates/authentication/login.html:143
|
||||||
|
@ -2206,7 +2203,7 @@ msgstr "不能包含特殊字符"
|
||||||
msgid "The mobile phone number format is incorrect"
|
msgid "The mobile phone number format is incorrect"
|
||||||
msgstr "手机号格式不正确"
|
msgstr "手机号格式不正确"
|
||||||
|
|
||||||
#: jumpserver/context_processor.py:20
|
#: jumpserver/context_processor.py:17
|
||||||
msgid "JumpServer Open Source Bastion Host"
|
msgid "JumpServer Open Source Bastion Host"
|
||||||
msgstr "JumpServer 开源堡垒机"
|
msgstr "JumpServer 开源堡垒机"
|
||||||
|
|
||||||
|
@ -2246,7 +2243,7 @@ msgstr "邮件"
|
||||||
msgid "Site message"
|
msgid "Site message"
|
||||||
msgstr "站内信"
|
msgstr "站内信"
|
||||||
|
|
||||||
#: notifications/notifications.py:148 ops/models/adhoc.py:246
|
#: notifications/notifications.py:167 ops/models/adhoc.py:246
|
||||||
#: xpack/plugins/change_auth_plan/models/base.py:108
|
#: xpack/plugins/change_auth_plan/models/base.py:108
|
||||||
#: xpack/plugins/change_auth_plan/models/base.py:190
|
#: xpack/plugins/change_auth_plan/models/base.py:190
|
||||||
#: xpack/plugins/gathered_user/models.py:79
|
#: xpack/plugins/gathered_user/models.py:79
|
||||||
|
@ -2261,7 +2258,7 @@ msgstr "等待任务开始"
|
||||||
msgid "Not has host {} permission"
|
msgid "Not has host {} permission"
|
||||||
msgstr "没有该主机 {} 权限"
|
msgstr "没有该主机 {} 权限"
|
||||||
|
|
||||||
#: ops/apps.py:9 ops/notifications.py:14
|
#: ops/apps.py:9 ops/notifications.py:15
|
||||||
msgid "Operations"
|
msgid "Operations"
|
||||||
msgstr "运维"
|
msgstr "运维"
|
||||||
|
|
||||||
|
@ -2383,29 +2380,33 @@ msgstr "命令 `{}` 不允许被执行 ......."
|
||||||
msgid "Task end"
|
msgid "Task end"
|
||||||
msgstr "任务结束"
|
msgstr "任务结束"
|
||||||
|
|
||||||
#: ops/notifications.py:15
|
#: ops/notifications.py:16
|
||||||
msgid "Server performance"
|
msgid "Server performance"
|
||||||
msgstr "监控告警"
|
msgstr "监控告警"
|
||||||
|
|
||||||
#: ops/notifications.py:54
|
#: ops/notifications.py:22
|
||||||
|
msgid "Terminal health check warning"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ops/notifications.py:63
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "The terminal is offline: {name}"
|
msgid "The terminal is offline: {name}"
|
||||||
msgstr "终端已离线: {name}"
|
msgstr "终端已离线: {name}"
|
||||||
|
|
||||||
#: ops/notifications.py:60
|
#: ops/notifications.py:68
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Disk used more than {max_threshold}%: => {value} ({name})"
|
msgid "Disk used more than {max_threshold}%: => {value}"
|
||||||
msgstr "硬盘使用率超过 {max_threshold}%: => {value} ({name})"
|
msgstr "硬盘使用率超过 {max_threshold}%: => {value}"
|
||||||
|
|
||||||
#: ops/notifications.py:67
|
#: ops/notifications.py:73
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Memory used more than {max_threshold}%: => {value} ({name})"
|
msgid "Memory used more than {max_threshold}%: => {value}"
|
||||||
msgstr "内存使用率超过 {max_threshold}%: => {value} ({name})"
|
msgstr "内存使用率超过 {max_threshold}%: => {value}"
|
||||||
|
|
||||||
#: ops/notifications.py:74
|
#: ops/notifications.py:78
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "CPU load more than {max_threshold}: => {value} ({name})"
|
msgid "CPU load more than {max_threshold}: => {value}"
|
||||||
msgstr "CPU 使用率超过 {max_threshold}: => {value} ({name})"
|
msgstr "CPU 使用率超过 {max_threshold}: => {value}"
|
||||||
|
|
||||||
#: ops/tasks.py:71
|
#: ops/tasks.py:71
|
||||||
msgid "Clean task history period"
|
msgid "Clean task history period"
|
||||||
|
@ -2533,35 +2534,35 @@ msgstr "失效日期"
|
||||||
msgid "From ticket"
|
msgid "From ticket"
|
||||||
msgstr "来自工单"
|
msgstr "来自工单"
|
||||||
|
|
||||||
#: perms/notifications.py:19
|
#: perms/notifications.py:15
|
||||||
msgid "You permed assets is about to expire"
|
msgid "You permed assets is about to expire"
|
||||||
msgstr "你授权的资产即将到期"
|
msgstr "你授权的资产即将到期"
|
||||||
|
|
||||||
#: perms/notifications.py:23
|
#: perms/notifications.py:19
|
||||||
msgid "permed assets"
|
msgid "permed assets"
|
||||||
msgstr "授权的资产"
|
msgstr "授权的资产"
|
||||||
|
|
||||||
#: perms/notifications.py:61
|
#: perms/notifications.py:57
|
||||||
msgid "Asset permissions is about to expire"
|
msgid "Asset permissions is about to expire"
|
||||||
msgstr "资产授权规则将要过期"
|
msgstr "资产授权规则将要过期"
|
||||||
|
|
||||||
#: perms/notifications.py:65
|
#: perms/notifications.py:61
|
||||||
msgid "asset permissions of organization {}"
|
msgid "asset permissions of organization {}"
|
||||||
msgstr "组织 ({}) 的资产授权"
|
msgstr "组织 ({}) 的资产授权"
|
||||||
|
|
||||||
#: perms/notifications.py:91
|
#: perms/notifications.py:87
|
||||||
msgid "Your permed applications is about to expire"
|
msgid "Your permed applications is about to expire"
|
||||||
msgstr "你授权的应用即将过期"
|
msgstr "你授权的应用即将过期"
|
||||||
|
|
||||||
#: perms/notifications.py:94
|
#: perms/notifications.py:90
|
||||||
msgid "permed applications"
|
msgid "permed applications"
|
||||||
msgstr "授权的应用"
|
msgstr "授权的应用"
|
||||||
|
|
||||||
#: perms/notifications.py:132
|
#: perms/notifications.py:128
|
||||||
msgid "Application permissions is about to expire"
|
msgid "Application permissions is about to expire"
|
||||||
msgstr "应用授权规则即将过期"
|
msgstr "应用授权规则即将过期"
|
||||||
|
|
||||||
#: perms/notifications.py:135
|
#: perms/notifications.py:131
|
||||||
msgid "application permissions of organization {}"
|
msgid "application permissions of organization {}"
|
||||||
msgstr "组织 ({}) 的应用授权"
|
msgstr "组织 ({}) 的应用授权"
|
||||||
|
|
||||||
|
@ -2633,7 +2634,7 @@ msgstr ""
|
||||||
" 以下 %(item_type)s 即将在 3 天后过期\n"
|
" 以下 %(item_type)s 即将在 3 天后过期\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: perms/templates/perms/_msg_permed_items_expire.html:22
|
#: perms/templates/perms/_msg_permed_items_expire.html:20
|
||||||
msgid "If you have any question, please contact the administrator"
|
msgid "If you have any question, please contact the administrator"
|
||||||
msgstr "如果有疑问或需求,请联系系统管理员"
|
msgstr "如果有疑问或需求,请联系系统管理员"
|
||||||
|
|
||||||
|
@ -2671,11 +2672,6 @@ msgstr "获取 LDAP 用户为 None"
|
||||||
msgid "Imported {} users successfully (Organization: {})"
|
msgid "Imported {} users successfully (Organization: {})"
|
||||||
msgstr "成功导入 {} 个用户 ( 组织: {} )"
|
msgstr "成功导入 {} 个用户 ( 组织: {} )"
|
||||||
|
|
||||||
#: settings/api/public.py:41 xpack/plugins/interface/api.py:18
|
|
||||||
#: xpack/plugins/interface/models.py:36
|
|
||||||
msgid "Welcome to the JumpServer open source Bastion Host"
|
|
||||||
msgstr "欢迎使用JumpServer开源堡垒机"
|
|
||||||
|
|
||||||
#: settings/models.py:191 users/templates/users/reset_password.html:29
|
#: settings/models.py:191 users/templates/users/reset_password.html:29
|
||||||
msgid "Setting"
|
msgid "Setting"
|
||||||
msgstr "设置"
|
msgstr "设置"
|
||||||
|
@ -3725,7 +3721,7 @@ msgstr "数据库应用"
|
||||||
msgid "Perms"
|
msgid "Perms"
|
||||||
msgstr "权限管理"
|
msgstr "权限管理"
|
||||||
|
|
||||||
#: templates/_nav.html:97 terminal/notifications.py:22
|
#: templates/_nav.html:97 terminal/notifications.py:24
|
||||||
msgid "Sessions"
|
msgid "Sessions"
|
||||||
msgstr "会话管理"
|
msgstr "会话管理"
|
||||||
|
|
||||||
|
@ -4068,7 +4064,7 @@ msgstr "输出"
|
||||||
|
|
||||||
#: terminal/backends/command/models.py:23 terminal/models/sharing.py:15
|
#: terminal/backends/command/models.py:23 terminal/models/sharing.py:15
|
||||||
#: terminal/models/sharing.py:58
|
#: terminal/models/sharing.py:58
|
||||||
#: terminal/templates/terminal/_msg_command_alert.html:16
|
#: terminal/templates/terminal/_msg_command_alert.html:10
|
||||||
msgid "Session"
|
msgid "Session"
|
||||||
msgstr "会话"
|
msgstr "会话"
|
||||||
|
|
||||||
|
@ -4235,11 +4231,15 @@ msgstr "命令存储"
|
||||||
msgid "Replay storage"
|
msgid "Replay storage"
|
||||||
msgstr "录像存储"
|
msgstr "录像存储"
|
||||||
|
|
||||||
#: terminal/notifications.py:68
|
#: terminal/notifications.py:70
|
||||||
msgid "Danger command alert"
|
msgid "Danger command alert"
|
||||||
msgstr "危险命令告警"
|
msgstr "危险命令告警"
|
||||||
|
|
||||||
#: terminal/notifications.py:106
|
#: terminal/notifications.py:92 terminal/notifications.py:137
|
||||||
|
msgid "Level"
|
||||||
|
msgstr "级别"
|
||||||
|
|
||||||
|
#: terminal/notifications.py:110
|
||||||
msgid "Batch danger command alert"
|
msgid "Batch danger command alert"
|
||||||
msgstr "批量危险命令告警"
|
msgstr "批量危险命令告警"
|
||||||
|
|
||||||
|
@ -4348,12 +4348,7 @@ msgstr ""
|
||||||
msgid "Not found"
|
msgid "Not found"
|
||||||
msgstr "没有发现"
|
msgstr "没有发现"
|
||||||
|
|
||||||
#: terminal/templates/terminal/_msg_command_alert.html:13
|
#: terminal/templates/terminal/_msg_command_alert.html:10
|
||||||
#: terminal/templates/terminal/_msg_command_execute_alert.html:7
|
|
||||||
msgid "Level"
|
|
||||||
msgstr "级别"
|
|
||||||
|
|
||||||
#: terminal/templates/terminal/_msg_command_alert.html:16
|
|
||||||
msgid "view"
|
msgid "view"
|
||||||
msgstr "查看"
|
msgstr "查看"
|
||||||
|
|
||||||
|
@ -4445,7 +4440,7 @@ msgstr "申请的开始日期"
|
||||||
msgid "Applied date expired"
|
msgid "Applied date expired"
|
||||||
msgstr "申请的失效日期"
|
msgstr "申请的失效日期"
|
||||||
|
|
||||||
#: tickets/handler/apply_application.py:79 tickets/handler/apply_asset.py:72
|
#: tickets/handler/apply_application.py:79
|
||||||
msgid ""
|
msgid ""
|
||||||
"Created by the ticket, ticket title: {}, ticket applicant: {}, ticket "
|
"Created by the ticket, ticket title: {}, ticket applicant: {}, ticket "
|
||||||
"processor: {}, ticket ID: {}"
|
"processor: {}, ticket ID: {}"
|
||||||
|
@ -4460,87 +4455,94 @@ msgstr "申请的主机名组"
|
||||||
msgid "Applied actions"
|
msgid "Applied actions"
|
||||||
msgstr "申请的动作"
|
msgstr "申请的动作"
|
||||||
|
|
||||||
|
#: tickets/handler/apply_asset.py:72
|
||||||
|
msgid ""
|
||||||
|
"Created by the ticket ticket title: {} ticket applicant: {} ticket "
|
||||||
|
"processor: {} ticket ID: {}"
|
||||||
|
msgstr ""
|
||||||
|
"通过工单创建, 工单标题: {}, 工单申请人: {}, 工单处理人: {}, 工单 ID: {}"
|
||||||
|
|
||||||
#: tickets/handler/base.py:86
|
#: tickets/handler/base.py:86
|
||||||
msgid "{} {} the ticket"
|
msgid "{} {} the ticket"
|
||||||
msgstr "{} {}工单"
|
msgstr "{} {} 工单"
|
||||||
|
|
||||||
#: tickets/handler/base.py:113
|
#: tickets/handler/base.py:114
|
||||||
msgid "Ticket title"
|
msgid "Ticket title"
|
||||||
msgstr "工单标题"
|
msgstr "工单标题"
|
||||||
|
|
||||||
#: tickets/handler/base.py:114
|
#: tickets/handler/base.py:115
|
||||||
msgid "Ticket type"
|
msgid "Ticket type"
|
||||||
msgstr "工单类型"
|
msgstr "工单类型"
|
||||||
|
|
||||||
#: tickets/handler/base.py:115
|
#: tickets/handler/base.py:116
|
||||||
msgid "Ticket status"
|
msgid "Ticket status"
|
||||||
msgstr "工单状态"
|
msgstr "工单状态"
|
||||||
|
|
||||||
#: tickets/handler/base.py:116
|
#: tickets/handler/base.py:117
|
||||||
msgid "Ticket applicant"
|
msgid "Ticket applicant"
|
||||||
msgstr "工单申请人"
|
msgstr "工单申请人"
|
||||||
|
|
||||||
#: tickets/handler/base.py:118
|
#: tickets/handler/base.py:119
|
||||||
msgid "Ticket basic info"
|
msgid "Ticket basic info"
|
||||||
msgstr "工单基本信息"
|
msgstr "工单基本信息"
|
||||||
|
|
||||||
#: tickets/handler/base.py:129
|
#: tickets/handler/base.py:130
|
||||||
msgid "No content"
|
msgid "No content"
|
||||||
msgstr "无内容"
|
msgstr "无内容"
|
||||||
|
|
||||||
#: tickets/handler/base.py:131
|
#: tickets/handler/base.py:132
|
||||||
msgid "Ticket applied info"
|
msgid "Ticket applied info"
|
||||||
msgstr "工单申请信息"
|
msgstr "工单申请信息"
|
||||||
|
|
||||||
#: tickets/handler/command_confirm.py:24
|
#: tickets/handler/command_confirm.py:25
|
||||||
msgid "Applied run user"
|
msgid "Applied run user"
|
||||||
msgstr "申请运行的用户"
|
msgstr "申请运行的用户"
|
||||||
|
|
||||||
#: tickets/handler/command_confirm.py:25
|
#: tickets/handler/command_confirm.py:26
|
||||||
msgid "Applied run asset"
|
msgid "Applied run asset"
|
||||||
msgstr "申请运行的资产"
|
msgstr "申请运行的资产"
|
||||||
|
|
||||||
#: tickets/handler/command_confirm.py:26
|
#: tickets/handler/command_confirm.py:27
|
||||||
msgid "Applied run system user"
|
msgid "Applied run system user"
|
||||||
msgstr "申请运行的系统用户"
|
msgstr "申请运行的系统用户"
|
||||||
|
|
||||||
#: tickets/handler/command_confirm.py:27
|
#: tickets/handler/command_confirm.py:28
|
||||||
msgid "Applied run command"
|
msgid "Applied run command"
|
||||||
msgstr "申请运行的命令"
|
msgstr "申请运行的命令"
|
||||||
|
|
||||||
#: tickets/handler/command_confirm.py:28
|
#: tickets/handler/command_confirm.py:29
|
||||||
msgid "Applied from session"
|
msgid "Applied from session"
|
||||||
msgstr "申请来自会话"
|
msgstr "申请来自会话"
|
||||||
|
|
||||||
#: tickets/handler/command_confirm.py:29
|
#: tickets/handler/command_confirm.py:30
|
||||||
msgid "Applied from command filter rules"
|
msgid "Applied from command filter rules"
|
||||||
msgstr "申请来自命令过滤规则"
|
msgstr "申请来自命令过滤规则"
|
||||||
|
|
||||||
#: tickets/handler/command_confirm.py:30
|
#: tickets/handler/command_confirm.py:31
|
||||||
msgid "Applied from command filter"
|
msgid "Applied from command filter"
|
||||||
msgstr "申请来自命令过滤规则"
|
msgstr "申请来自命令过滤规则"
|
||||||
|
|
||||||
#: tickets/handler/login_asset_confirm.py:16
|
#: tickets/handler/login_asset_confirm.py:17
|
||||||
msgid "Applied login user"
|
msgid "Applied login user"
|
||||||
msgstr "申请登录的用户"
|
msgstr "申请登录的用户"
|
||||||
|
|
||||||
#: tickets/handler/login_asset_confirm.py:17
|
#: tickets/handler/login_asset_confirm.py:18
|
||||||
msgid "Applied login asset"
|
msgid "Applied login asset"
|
||||||
msgstr "申请登录的资产"
|
msgstr "申请登录的资产"
|
||||||
|
|
||||||
#: tickets/handler/login_asset_confirm.py:18
|
#: tickets/handler/login_asset_confirm.py:19
|
||||||
msgid "Applied login system user"
|
msgid "Applied login system user"
|
||||||
msgstr "申请登录的系统用户"
|
msgstr "申请登录的系统用户"
|
||||||
|
|
||||||
#: tickets/handler/login_confirm.py:16
|
#: tickets/handler/login_confirm.py:17
|
||||||
msgid "Applied login IP"
|
msgid "Applied login IP"
|
||||||
msgstr "申请登录的IP"
|
msgstr "申请登录的IP"
|
||||||
|
|
||||||
#: tickets/handler/login_confirm.py:17
|
#: tickets/handler/login_confirm.py:18
|
||||||
msgid "Applied login city"
|
msgid "Applied login city"
|
||||||
msgstr "申请登录的城市"
|
msgstr "申请登录的城市"
|
||||||
|
|
||||||
#: tickets/handler/login_confirm.py:18
|
#: tickets/handler/login_confirm.py:19
|
||||||
msgid "Applied login datetime"
|
msgid "Applied login datetime"
|
||||||
msgstr "申请登录的日期"
|
msgstr "申请登录的日期"
|
||||||
|
|
||||||
|
@ -4741,7 +4743,8 @@ msgstr "请选择受理人"
|
||||||
msgid "The current organization type already exists"
|
msgid "The current organization type already exists"
|
||||||
msgstr "当前组织已存在该类型"
|
msgstr "当前组织已存在该类型"
|
||||||
|
|
||||||
#: tickets/templates/tickets/_msg_ticket.html:11
|
#: tickets/templates/tickets/_base_ticket_body.html:17
|
||||||
|
#: tickets/templates/tickets/_msg_ticket.html:12
|
||||||
msgid "Click here to review"
|
msgid "Click here to review"
|
||||||
msgstr "点击查看"
|
msgstr "点击查看"
|
||||||
|
|
||||||
|
@ -4901,30 +4904,38 @@ msgstr "管理员"
|
||||||
msgid "Administrator is the super user of system"
|
msgid "Administrator is the super user of system"
|
||||||
msgstr "Administrator是初始的超级管理员"
|
msgstr "Administrator是初始的超级管理员"
|
||||||
|
|
||||||
#: users/notifications.py:20
|
#: users/notifications.py:15
|
||||||
|
msgid "Create account successfully"
|
||||||
|
msgstr "创建账户成功"
|
||||||
|
|
||||||
|
#: users/notifications.py:19
|
||||||
|
msgid "Hello {}"
|
||||||
|
msgstr "你好"
|
||||||
|
|
||||||
|
#: users/notifications.py:51
|
||||||
#: users/templates/users/_msg_password_expire_reminder.html:17
|
#: users/templates/users/_msg_password_expire_reminder.html:17
|
||||||
#: users/templates/users/reset_password.html:5
|
#: users/templates/users/reset_password.html:5
|
||||||
#: users/templates/users/reset_password.html:6
|
#: users/templates/users/reset_password.html:6
|
||||||
msgid "Reset password"
|
msgid "Reset password"
|
||||||
msgstr "重置密码"
|
msgstr "重置密码"
|
||||||
|
|
||||||
#: users/notifications.py:50 users/views/profile/reset.py:127
|
#: users/notifications.py:81 users/views/profile/reset.py:127
|
||||||
msgid "Reset password success"
|
msgid "Reset password success"
|
||||||
msgstr "重置密码成功"
|
msgstr "重置密码成功"
|
||||||
|
|
||||||
#: users/notifications.py:78
|
#: users/notifications.py:110
|
||||||
msgid "Password is about expire"
|
msgid "Password is about expire"
|
||||||
msgstr "密码即将过期"
|
msgstr "密码即将过期"
|
||||||
|
|
||||||
#: users/notifications.py:105
|
#: users/notifications.py:137
|
||||||
msgid "Account is about expire"
|
msgid "Account is about expire"
|
||||||
msgstr "账号即将过期"
|
msgstr "账号即将过期"
|
||||||
|
|
||||||
#: users/notifications.py:127
|
#: users/notifications.py:161
|
||||||
msgid "Reset SSH Key"
|
msgid "Reset SSH Key"
|
||||||
msgstr "重置 SSH 密钥"
|
msgstr "重置 SSH 密钥"
|
||||||
|
|
||||||
#: users/notifications.py:147
|
#: users/notifications.py:181
|
||||||
msgid "Reset MFA"
|
msgid "Reset MFA"
|
||||||
msgstr "重置 MFA"
|
msgstr "重置 MFA"
|
||||||
|
|
||||||
|
@ -5073,28 +5084,34 @@ msgid "Click here update password"
|
||||||
msgstr "点击这里更新密码"
|
msgstr "点击这里更新密码"
|
||||||
|
|
||||||
#: users/templates/users/_msg_password_expire_reminder.html:16
|
#: users/templates/users/_msg_password_expire_reminder.html:16
|
||||||
msgid "If your password has expired, please click"
|
msgid "If your password has expired, please click the link below to"
|
||||||
msgstr "如果你的密码已过期,先点击"
|
msgstr "如果你的密码已过期,请点击"
|
||||||
|
|
||||||
#: users/templates/users/_msg_password_expire_reminder.html:18
|
|
||||||
msgid "to apply for a password reset email."
|
|
||||||
msgstr "申请重置"
|
|
||||||
|
|
||||||
#: users/templates/users/_msg_reset_mfa.html:7
|
#: users/templates/users/_msg_reset_mfa.html:7
|
||||||
msgid "Your MFA has been reset by site administrator."
|
msgid "Your MFA has been reset by site administrator"
|
||||||
msgstr "你的 MFA 已经被管理员重置。"
|
msgstr "你的 MFA 已经被管理员重置"
|
||||||
|
|
||||||
#: users/templates/users/_msg_reset_mfa.html:8
|
#: users/templates/users/_msg_reset_mfa.html:8
|
||||||
msgid "Please login and reset your MFA."
|
#: users/templates/users/_msg_reset_ssh_key.html:8
|
||||||
msgstr "请登录并重新设置你的 MFA"
|
msgid "Please click the link below to set"
|
||||||
|
msgstr "请点击下面链接设置"
|
||||||
|
|
||||||
|
#: users/templates/users/_msg_reset_mfa.html:11
|
||||||
|
#: users/templates/users/_msg_reset_ssh_key.html:11
|
||||||
|
msgid "Click here set"
|
||||||
|
msgstr "点击这里设置"
|
||||||
|
|
||||||
#: users/templates/users/_msg_reset_ssh_key.html:7
|
#: users/templates/users/_msg_reset_ssh_key.html:7
|
||||||
msgid "Your ssh public key has been reset by site administrator."
|
msgid "Your ssh public key has been reset by site administrator"
|
||||||
msgstr "你的 SSH 密钥已经被管理员重置。"
|
msgstr "你的 SSH 密钥已经被管理员重置"
|
||||||
|
|
||||||
#: users/templates/users/_msg_reset_ssh_key.html:8
|
#: users/templates/users/_msg_user_created.html:8
|
||||||
msgid "Please login and reset your ssh public key."
|
msgid "Your account has been created successfully"
|
||||||
msgstr "请登录并重新设置你的密钥"
|
msgstr "您的账户已创建成功"
|
||||||
|
|
||||||
|
#: users/templates/users/_msg_user_created.html:13
|
||||||
|
msgid "click here to set your password"
|
||||||
|
msgstr "点击这里设置密码"
|
||||||
|
|
||||||
#: users/templates/users/_select_user_modal.html:5
|
#: users/templates/users/_select_user_modal.html:5
|
||||||
msgid "Please Select User"
|
msgid "Please Select User"
|
||||||
|
@ -5279,56 +5296,6 @@ msgstr "账号保护已开启,请根据提示完成以下操作"
|
||||||
msgid "Open MFA Authenticator and enter the 6-bit dynamic code"
|
msgid "Open MFA Authenticator and enter the 6-bit dynamic code"
|
||||||
msgstr "请打开MFA验证器,输入6位动态码"
|
msgstr "请打开MFA验证器,输入6位动态码"
|
||||||
|
|
||||||
# msgid "Update user"
|
|
||||||
# msgstr "更新用户"
|
|
||||||
#: users/utils.py:23
|
|
||||||
#, python-format
|
|
||||||
msgid ""
|
|
||||||
"\n"
|
|
||||||
" <div>\n"
|
|
||||||
" <p>Your account has been created successfully</p>\n"
|
|
||||||
" <div>\n"
|
|
||||||
" Username: %(username)s\n"
|
|
||||||
" <br/>\n"
|
|
||||||
" Password: <a href=\"%(rest_password_url)s?token="
|
|
||||||
"%(rest_password_token)s\">\n"
|
|
||||||
" click here to set your password</a> \n"
|
|
||||||
" (This link is valid for 1 hour. After it expires, <a href="
|
|
||||||
"\"%(forget_password_url)s?email=%(email)s\">request new one</a>)\n"
|
|
||||||
" </div>\n"
|
|
||||||
" <div>\n"
|
|
||||||
" <p>---</p>\n"
|
|
||||||
" <a href=\"%(login_url)s\">Login direct</a>\n"
|
|
||||||
" </div>\n"
|
|
||||||
" </div>\n"
|
|
||||||
" "
|
|
||||||
msgstr ""
|
|
||||||
"\n"
|
|
||||||
" <div>\n"
|
|
||||||
" <p>您的账户已创建成功</p>\n"
|
|
||||||
" <div>\n"
|
|
||||||
" 用户名: %(username)s\n"
|
|
||||||
" <br/>\n"
|
|
||||||
" 密码: <a href=\"%(rest_password_url)s?token="
|
|
||||||
"%(rest_password_token)s\">请点击这里设置密码</a> (这个链接有效期1小时, 超过时"
|
|
||||||
"间您可以 <a href=\"%(forget_password_url)s?email=%(email)s\">重新申请</a>)\n"
|
|
||||||
" </div>\n"
|
|
||||||
" <div>\n"
|
|
||||||
" <p>---</p>\n"
|
|
||||||
" <a href=\"%(login_url)s\">直接登录</a>\n"
|
|
||||||
" </div>\n"
|
|
||||||
" </div>\n"
|
|
||||||
" "
|
|
||||||
|
|
||||||
#: users/utils.py:57
|
|
||||||
msgid "Create account successfully"
|
|
||||||
msgstr "创建账户成功"
|
|
||||||
|
|
||||||
#: users/utils.py:61
|
|
||||||
#, python-format
|
|
||||||
msgid "Hello %(name)s"
|
|
||||||
msgstr "你好 %(name)s"
|
|
||||||
|
|
||||||
#: users/views/profile/otp.py:122 users/views/profile/otp.py:161
|
#: users/views/profile/otp.py:122 users/views/profile/otp.py:161
|
||||||
#: users/views/profile/otp.py:181
|
#: users/views/profile/otp.py:181
|
||||||
msgid "MFA code invalid, or ntp sync server time"
|
msgid "MFA code invalid, or ntp sync server time"
|
||||||
|
@ -5923,11 +5890,11 @@ msgstr "资产为空,请更改节点"
|
||||||
msgid "Executed times"
|
msgid "Executed times"
|
||||||
msgstr "执行次数"
|
msgstr "执行次数"
|
||||||
|
|
||||||
#: xpack/plugins/interface/api.py:68
|
#: xpack/plugins/interface/api.py:43
|
||||||
msgid "It is already in the default setting state!"
|
msgid "It is already in the default setting state!"
|
||||||
msgstr "当前已经是初始化状态!"
|
msgstr "当前已经是初始化状态!"
|
||||||
|
|
||||||
#: xpack/plugins/interface/api.py:72
|
#: xpack/plugins/interface/api.py:46
|
||||||
msgid "Restore default successfully."
|
msgid "Restore default successfully."
|
||||||
msgstr "恢复默认成功!"
|
msgstr "恢复默认成功!"
|
||||||
|
|
||||||
|
@ -5935,23 +5902,23 @@ msgstr "恢复默认成功!"
|
||||||
msgid "Interface settings"
|
msgid "Interface settings"
|
||||||
msgstr "界面设置"
|
msgstr "界面设置"
|
||||||
|
|
||||||
#: xpack/plugins/interface/models.py:15
|
#: xpack/plugins/interface/models.py:16
|
||||||
msgid "Title of login page"
|
msgid "Title of login page"
|
||||||
msgstr "登录页面标题"
|
msgstr "登录页面标题"
|
||||||
|
|
||||||
#: xpack/plugins/interface/models.py:19
|
#: xpack/plugins/interface/models.py:20
|
||||||
msgid "Image of login page"
|
msgid "Image of login page"
|
||||||
msgstr "登录页面图片"
|
msgstr "登录页面图片"
|
||||||
|
|
||||||
#: xpack/plugins/interface/models.py:23
|
#: xpack/plugins/interface/models.py:24
|
||||||
msgid "Website icon"
|
msgid "Website icon"
|
||||||
msgstr "网站图标"
|
msgstr "网站图标"
|
||||||
|
|
||||||
#: xpack/plugins/interface/models.py:27
|
#: xpack/plugins/interface/models.py:28
|
||||||
msgid "Logo of management page"
|
msgid "Logo of management page"
|
||||||
msgstr "管理页面logo"
|
msgstr "管理页面logo"
|
||||||
|
|
||||||
#: xpack/plugins/interface/models.py:31
|
#: xpack/plugins/interface/models.py:32
|
||||||
msgid "Logo of logout page"
|
msgid "Logo of logout page"
|
||||||
msgstr "退出页面logo"
|
msgstr "退出页面logo"
|
||||||
|
|
||||||
|
@ -5983,6 +5950,69 @@ msgstr "旗舰版"
|
||||||
msgid "Community edition"
|
msgid "Community edition"
|
||||||
msgstr "社区版"
|
msgstr "社区版"
|
||||||
|
|
||||||
|
#~ msgid "Login direct"
|
||||||
|
#~ msgstr "直接登录"
|
||||||
|
|
||||||
|
#~ msgid "to apply for a password reset email."
|
||||||
|
#~ msgstr "申请重置"
|
||||||
|
|
||||||
|
#~ msgid "Please login and reset your MFA."
|
||||||
|
#~ msgstr "请登录并重新设置你的 MFA"
|
||||||
|
|
||||||
|
#~ msgid "Please login and reset your ssh public key."
|
||||||
|
#~ msgstr "请登录并重新设置你的密钥"
|
||||||
|
|
||||||
|
# msgid "Update user"
|
||||||
|
# msgstr "更新用户"
|
||||||
|
#, python-format
|
||||||
|
#~ msgid ""
|
||||||
|
#~ "\n"
|
||||||
|
#~ " <div>\n"
|
||||||
|
#~ " <p>Your account has been created successfully</p>\n"
|
||||||
|
#~ " <div>\n"
|
||||||
|
#~ " Username: %(username)s\n"
|
||||||
|
#~ " <br/>\n"
|
||||||
|
#~ " Password: <a href=\"%(rest_password_url)s?token="
|
||||||
|
#~ "%(rest_password_token)s\">\n"
|
||||||
|
#~ " click here to set your password</a> \n"
|
||||||
|
#~ " (This link is valid for 1 hour. After it expires, <a href="
|
||||||
|
#~ "\"%(forget_password_url)s?email=%(email)s\">request new one</a>)\n"
|
||||||
|
#~ " </div>\n"
|
||||||
|
#~ " <div>\n"
|
||||||
|
#~ " <p>---</p>\n"
|
||||||
|
#~ " <a href=\"%(login_url)s\">Login direct</a>\n"
|
||||||
|
#~ " </div>\n"
|
||||||
|
#~ " </div>\n"
|
||||||
|
#~ " "
|
||||||
|
#~ msgstr ""
|
||||||
|
#~ "\n"
|
||||||
|
#~ " <div>\n"
|
||||||
|
#~ " <p>您的账户已创建成功</p>\n"
|
||||||
|
#~ " <div>\n"
|
||||||
|
#~ " 用户名: %(username)s\n"
|
||||||
|
#~ " <br/>\n"
|
||||||
|
#~ " 密码: <a href=\"%(rest_password_url)s?token="
|
||||||
|
#~ "%(rest_password_token)s\">请点击这里设置密码</a> (这个链接有效期1小时, 超"
|
||||||
|
#~ "过时间您可以 <a href=\"%(forget_password_url)s?email=%(email)s\">重新申请"
|
||||||
|
#~ "</a>)\n"
|
||||||
|
#~ " </div>\n"
|
||||||
|
#~ " <div>\n"
|
||||||
|
#~ " <p>---</p>\n"
|
||||||
|
#~ " <a href=\"%(login_url)s\">直接登录</a>\n"
|
||||||
|
#~ " </div>\n"
|
||||||
|
#~ " </div>\n"
|
||||||
|
#~ " "
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
#~ msgid "Hello %(name)s"
|
||||||
|
#~ msgstr "你好 %(name)s"
|
||||||
|
|
||||||
|
#~ msgid "This link is valid for 1 hour. After it expires,"
|
||||||
|
#~ msgstr "这个链接有效期1小时, 超过时间您可以"
|
||||||
|
|
||||||
|
#~ msgid "Welcome to the JumpServer open source Bastion Host"
|
||||||
|
#~ msgstr "欢迎使用JumpServer开源堡垒机"
|
||||||
|
|
||||||
#~ msgid "Login IP"
|
#~ msgid "Login IP"
|
||||||
#~ msgstr "登录IP"
|
#~ msgstr "登录IP"
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,10 @@ from notifications.serializers import (
|
||||||
UserMsgSubscriptionSerializer,
|
UserMsgSubscriptionSerializer,
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = ('BackendListView', 'SystemMsgSubscriptionViewSet', 'UserMsgSubscriptionViewSet')
|
__all__ = (
|
||||||
|
'BackendListView', 'SystemMsgSubscriptionViewSet',
|
||||||
|
'UserMsgSubscriptionViewSet', 'get_all_test_messages'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BackendListView(APIView):
|
class BackendListView(APIView):
|
||||||
|
@ -80,3 +83,43 @@ class UserMsgSubscriptionViewSet(ListModelMixin,
|
||||||
queryset = UserMsgSubscription.objects.all()
|
queryset = UserMsgSubscription.objects.all()
|
||||||
serializer_class = UserMsgSubscriptionSerializer
|
serializer_class = UserMsgSubscriptionSerializer
|
||||||
permission_classes = (IsObjectOwner | IsSuperUser, OnlySuperUserCanList)
|
permission_classes = (IsObjectOwner | IsSuperUser, OnlySuperUserCanList)
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_test_messages(request):
|
||||||
|
import textwrap
|
||||||
|
from ..notifications import Message
|
||||||
|
from django.shortcuts import HttpResponse
|
||||||
|
|
||||||
|
msgs_cls = Message.get_all_sub_messages()
|
||||||
|
html_data = '<h3>HTML 格式 </h3>'
|
||||||
|
text_data = '<h3>Text 格式</h3>'
|
||||||
|
|
||||||
|
for msg_cls in msgs_cls:
|
||||||
|
try:
|
||||||
|
msg = msg_cls.gen_test_msg()
|
||||||
|
if not msg:
|
||||||
|
continue
|
||||||
|
msg_html = msg.html_msg_with_sign['message']
|
||||||
|
msg_text = msg.text_msg_with_sign['message']
|
||||||
|
except NotImplementedError:
|
||||||
|
msg_html = msg_text = '没有实现方法'
|
||||||
|
except Exception as e:
|
||||||
|
msg_html = msg_text = 'Error: ' + str(e)
|
||||||
|
|
||||||
|
html_data += """
|
||||||
|
<h3>{}</h3>
|
||||||
|
{}
|
||||||
|
<hr />
|
||||||
|
""".format(msg_cls.__name__, msg_html)
|
||||||
|
|
||||||
|
text_data += textwrap.dedent("""
|
||||||
|
<h3>{}</h3>
|
||||||
|
<pre>
|
||||||
|
{}
|
||||||
|
</pre>
|
||||||
|
<br/>
|
||||||
|
<hr />
|
||||||
|
""").format(msg_cls.__name__, msg_text)
|
||||||
|
return HttpResponse(html_data + text_data)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,23 @@ import traceback
|
||||||
from html2text import HTML2Text
|
from html2text import HTML2Text
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
import textwrap
|
||||||
|
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from common.utils.timezone import local_now
|
from common.utils.timezone import local_now
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
|
from settings.utils import get_login_title
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from notifications.backends import BACKEND
|
from notifications.backends import BACKEND
|
||||||
from .models import SystemMsgSubscription, UserMsgSubscription
|
from .models import SystemMsgSubscription, UserMsgSubscription
|
||||||
|
|
||||||
__all__ = ('SystemMessage', 'UserMessage', 'system_msgs')
|
__all__ = ('SystemMessage', 'UserMessage', 'system_msgs', 'Message')
|
||||||
|
|
||||||
|
|
||||||
system_msgs = []
|
system_msgs = []
|
||||||
user_msgs = []
|
user_msgs = []
|
||||||
all_msgs = []
|
|
||||||
|
|
||||||
|
|
||||||
class MessageType(type):
|
class MessageType(type):
|
||||||
|
@ -55,7 +56,6 @@ class Message(metaclass=MessageType):
|
||||||
- publish 该方法的实现与消息订阅的表结构有关
|
- publish 该方法的实现与消息订阅的表结构有关
|
||||||
- send_msg
|
- send_msg
|
||||||
"""
|
"""
|
||||||
|
|
||||||
message_type_label: str
|
message_type_label: str
|
||||||
category: str
|
category: str
|
||||||
category_label: str
|
category_label: str
|
||||||
|
@ -84,16 +84,13 @@ class Message(metaclass=MessageType):
|
||||||
backend = BACKEND(backend)
|
backend = BACKEND(backend)
|
||||||
if not backend.is_enable:
|
if not backend.is_enable:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
get_msg_method = getattr(self, f'get_{backend}_msg', self.get_common_msg)
|
get_msg_method = getattr(self, f'get_{backend}_msg', self.get_common_msg)
|
||||||
try:
|
msg = get_msg_method()
|
||||||
msg = get_msg_method()
|
|
||||||
except NotImplementedError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
client = backend.client()
|
client = backend.client()
|
||||||
client.send_msg(users, **msg)
|
client.send_msg(users, **msg)
|
||||||
except Exception:
|
except NotImplementedError:
|
||||||
|
continue
|
||||||
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -111,10 +108,7 @@ class Message(metaclass=MessageType):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_common_msg() -> dict:
|
def get_common_msg() -> dict:
|
||||||
return {
|
return {'subject': '', 'message': ''}
|
||||||
'subject': '',
|
|
||||||
'message': ''
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_html_msg(self) -> dict:
|
def get_html_msg(self) -> dict:
|
||||||
return self.get_common_msg()
|
return self.get_common_msg()
|
||||||
|
@ -133,11 +127,39 @@ class Message(metaclass=MessageType):
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def text_msg(self) -> dict:
|
def text_msg(self) -> dict:
|
||||||
return self.get_text_msg()
|
msg = self.get_text_msg()
|
||||||
|
return msg
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def html_msg(self) -> dict:
|
def html_msg(self) -> dict:
|
||||||
return self.get_html_msg()
|
msg = self.get_html_msg()
|
||||||
|
return msg
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def html_msg_with_sign(self):
|
||||||
|
msg = self.get_html_msg()
|
||||||
|
msg['message'] = textwrap.dedent("""
|
||||||
|
{}
|
||||||
|
<br />
|
||||||
|
—
|
||||||
|
<br />
|
||||||
|
<small>{}</small>
|
||||||
|
""").format(msg['message'], self.signature)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def text_msg_with_sign(self):
|
||||||
|
msg = self.get_text_msg()
|
||||||
|
msg['message'] = textwrap.dedent("""
|
||||||
|
{}
|
||||||
|
—
|
||||||
|
{}
|
||||||
|
""").format(msg['message'], self.signature)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def signature(self):
|
||||||
|
return get_login_title()
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
# --------------------------------------------------------------
|
||||||
# 支持不同发送消息的方式定义自己的消息内容,比如有些支持 html 标签
|
# 支持不同发送消息的方式定义自己的消息内容,比如有些支持 html 标签
|
||||||
|
@ -159,16 +181,16 @@ class Message(metaclass=MessageType):
|
||||||
return self.text_msg
|
return self.text_msg
|
||||||
|
|
||||||
def get_email_msg(self) -> dict:
|
def get_email_msg(self) -> dict:
|
||||||
return self.html_msg
|
return self.html_msg_with_sign
|
||||||
|
|
||||||
def get_site_msg_msg(self) -> dict:
|
def get_site_msg_msg(self) -> dict:
|
||||||
return self.html_msg
|
return self.html_msg
|
||||||
|
|
||||||
def get_sms_msg(self) -> dict:
|
def get_sms_msg(self) -> dict:
|
||||||
return self.text_msg
|
return self.text_msg_with_sign
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def test_all_messages(cls):
|
def get_all_sub_messages(cls):
|
||||||
def get_subclasses(cls):
|
def get_subclasses(cls):
|
||||||
"""returns all subclasses of argument, cls"""
|
"""returns all subclasses of argument, cls"""
|
||||||
if issubclass(cls, type):
|
if issubclass(cls, type):
|
||||||
|
@ -180,6 +202,12 @@ class Message(metaclass=MessageType):
|
||||||
return subclasses
|
return subclasses
|
||||||
|
|
||||||
messages_cls = get_subclasses(cls)
|
messages_cls = get_subclasses(cls)
|
||||||
|
return messages_cls
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def test_all_messages(cls):
|
||||||
|
messages_cls = cls.get_all_sub_messages()
|
||||||
|
|
||||||
for _cls in messages_cls:
|
for _cls in messages_cls:
|
||||||
try:
|
try:
|
||||||
msg = _cls.send_test_msg()
|
msg = _cls.send_test_msg()
|
||||||
|
@ -225,6 +253,11 @@ class UserMessage(Message):
|
||||||
sub = UserMsgSubscription.objects.get(user=self.user)
|
sub = UserMsgSubscription.objects.get(user=self.user)
|
||||||
self.send_msg([self.user], sub.receive_backends)
|
self.send_msg([self.user], sub.receive_backends)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_test_user(cls):
|
||||||
|
from users.models import User
|
||||||
|
return User.objects.all().first()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def gen_test_msg(cls):
|
def gen_test_msg(cls):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
from rest_framework_bulk.routes import BulkRouter
|
from rest_framework_bulk.routes import BulkRouter
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from notifications import api
|
from notifications import api
|
||||||
|
|
||||||
|
@ -14,3 +15,8 @@ router.register('site-message', api.SiteMessageViewSet, 'site-message')
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('backends/', api.BackendListView.as_view(), name='backends')
|
path('backends/', api.BackendListView.as_view(), name='backends')
|
||||||
] + router.urls
|
] + router.urls
|
||||||
|
|
||||||
|
if settings.DEBUG:
|
||||||
|
urlpatterns += [
|
||||||
|
path('debug-msgs/', api.get_all_test_messages, name='debug-all-msgs')
|
||||||
|
]
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.template.loader import render_to_string
|
||||||
|
|
||||||
from notifications.notifications import SystemMessage
|
from notifications.notifications import SystemMessage
|
||||||
from notifications.models import SystemMsgSubscription
|
from notifications.models import SystemMsgSubscription
|
||||||
|
@ -14,14 +15,18 @@ class ServerPerformanceMessage(SystemMessage):
|
||||||
category_label = _('Operations')
|
category_label = _('Operations')
|
||||||
message_type_label = _('Server performance')
|
message_type_label = _('Server performance')
|
||||||
|
|
||||||
def __init__(self, msg):
|
def __init__(self, terms_with_errors):
|
||||||
self._msg = msg
|
self.terms_with_errors = terms_with_errors
|
||||||
|
|
||||||
def get_html_msg(self) -> dict:
|
def get_html_msg(self) -> dict:
|
||||||
subject = self._msg[:80]
|
subject = _("Terminal health check warning")
|
||||||
|
context = {
|
||||||
|
'terms_with_errors': self.terms_with_errors
|
||||||
|
}
|
||||||
|
message = render_to_string('ops/_msg_terminal_performance.html', context)
|
||||||
return {
|
return {
|
||||||
'subject': subject.replace('<br>', '; '),
|
'subject': subject,
|
||||||
'message': self._msg
|
'message': message
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -33,17 +38,21 @@ class ServerPerformanceMessage(SystemMessage):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def gen_test_msg(cls):
|
def gen_test_msg(cls):
|
||||||
alarm_messages = []
|
from terminal.models import Terminal
|
||||||
items_mapper = ServerPerformanceCheckUtil.items_mapper
|
items_mapper = ServerPerformanceCheckUtil.items_mapper
|
||||||
for item, data in items_mapper.items():
|
terms_with_errors = []
|
||||||
msg = data['alarm_msg_format']
|
terms = Terminal.objects.all()[:5]
|
||||||
max_threshold = data['max_threshold']
|
|
||||||
value = 123
|
|
||||||
msg = msg.format(max_threshold=max_threshold, value=value, name='Fake terminal')
|
|
||||||
alarm_messages.append(msg)
|
|
||||||
|
|
||||||
msg = '<br>'.join(alarm_messages)
|
for i, term in enumerate(terms, 1):
|
||||||
return cls(msg)
|
errors = []
|
||||||
|
for item, data in items_mapper.items():
|
||||||
|
msg = data['alarm_msg_format']
|
||||||
|
max_threshold = data['max_threshold']
|
||||||
|
value = 123 // i+1
|
||||||
|
msg = msg.format(max_threshold=max_threshold, value=value, name=term.name)
|
||||||
|
errors.append(msg)
|
||||||
|
terms_with_errors.append([term, errors])
|
||||||
|
return cls(terms_with_errors)
|
||||||
|
|
||||||
|
|
||||||
class ServerPerformanceCheckUtil(object):
|
class ServerPerformanceCheckUtil(object):
|
||||||
|
@ -56,59 +65,65 @@ class ServerPerformanceCheckUtil(object):
|
||||||
'disk_used': {
|
'disk_used': {
|
||||||
'default': 0,
|
'default': 0,
|
||||||
'max_threshold': 80,
|
'max_threshold': 80,
|
||||||
'alarm_msg_format': _(
|
'alarm_msg_format': _('Disk used more than {max_threshold}%: => {value}')
|
||||||
'Disk used more than {max_threshold}%: => {value} ({name})'
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
'memory_used': {
|
'memory_used': {
|
||||||
'default': 0,
|
'default': 0,
|
||||||
'max_threshold': 85,
|
'max_threshold': 85,
|
||||||
'alarm_msg_format': _(
|
'alarm_msg_format': _('Memory used more than {max_threshold}%: => {value}'),
|
||||||
'Memory used more than {max_threshold}%: => {value} ({name})'
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
'cpu_load': {
|
'cpu_load': {
|
||||||
'default': 0,
|
'default': 0,
|
||||||
'max_threshold': 5,
|
'max_threshold': 5,
|
||||||
'alarm_msg_format': _(
|
'alarm_msg_format': _('CPU load more than {max_threshold}: => {value}'),
|
||||||
'CPU load more than {max_threshold}: => {value} ({name})'
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.alarm_messages = []
|
self.terms_with_errors = []
|
||||||
self._terminals = []
|
self._terminals = []
|
||||||
self._terminal = None
|
|
||||||
|
|
||||||
def check_and_publish(self):
|
def check_and_publish(self):
|
||||||
self.check()
|
self.check()
|
||||||
self.publish()
|
self.publish()
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
self.alarm_messages = []
|
self.terms_with_errors = []
|
||||||
self.initial_terminals()
|
self.initial_terminals()
|
||||||
for item, data in self.items_mapper.items():
|
|
||||||
for self._terminal in self._terminals:
|
|
||||||
self.check_item(item, data)
|
|
||||||
|
|
||||||
def check_item(self, item, data):
|
for term in self._terminals:
|
||||||
|
errors = self.check_terminal(term)
|
||||||
|
if not errors:
|
||||||
|
continue
|
||||||
|
self.terms_with_errors.append((term, errors))
|
||||||
|
|
||||||
|
def check_terminal(self, term):
|
||||||
|
errors = []
|
||||||
|
for item, data in self.items_mapper.items():
|
||||||
|
error = self.check_item(term, item, data)
|
||||||
|
if not error:
|
||||||
|
continue
|
||||||
|
errors.append(error)
|
||||||
|
return errors
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_item(term, item, data):
|
||||||
default = data['default']
|
default = data['default']
|
||||||
max_threshold = data['max_threshold']
|
max_threshold = data['max_threshold']
|
||||||
value = getattr(self._terminal.stat, item, default)
|
value = getattr(term.stat, item, default)
|
||||||
|
|
||||||
if isinstance(value, bool) and value != max_threshold:
|
if isinstance(value, bool) and value != max_threshold:
|
||||||
return
|
return
|
||||||
elif isinstance(value, (int, float)) and value < max_threshold:
|
elif isinstance(value, (int, float)) and value < max_threshold:
|
||||||
return
|
return
|
||||||
msg = data['alarm_msg_format']
|
msg = data['alarm_msg_format']
|
||||||
msg = msg.format(max_threshold=max_threshold, value=value, name=self._terminal.name)
|
error = msg.format(max_threshold=max_threshold, value=value, name=term.name)
|
||||||
self.alarm_messages.append(msg)
|
return error
|
||||||
|
|
||||||
def publish(self):
|
def publish(self):
|
||||||
if not self.alarm_messages:
|
if not self.terms_with_errors:
|
||||||
return
|
return
|
||||||
msg = '<br>'.join(self.alarm_messages)
|
ServerPerformanceMessage(self.terms_with_errors).publish()
|
||||||
ServerPerformanceMessage(msg).publish()
|
|
||||||
|
|
||||||
def initial_terminals(self):
|
def initial_terminals(self):
|
||||||
terminals = []
|
terminals = []
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div>
|
||||||
|
{% for term, errors in terms_with_errors %}
|
||||||
|
<h4>{{ term.name }}</h4>
|
||||||
|
<ul>
|
||||||
|
{% for error in errors %}
|
||||||
|
<li>{{ error }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
|
@ -1,4 +1,6 @@
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
|
||||||
|
@ -6,7 +8,7 @@ from common.utils import reverse as js_reverse
|
||||||
from notifications.notifications import UserMessage
|
from notifications.notifications import UserMessage
|
||||||
|
|
||||||
|
|
||||||
class PermedWillExpireUserMsg(UserMessage):
|
class PermedAssetsWillExpireUserMsg(UserMessage):
|
||||||
def __init__(self, user, assets):
|
def __init__(self, user, assets):
|
||||||
super().__init__(user)
|
super().__init__(user)
|
||||||
self.assets = assets
|
self.assets = assets
|
||||||
|
@ -114,12 +116,9 @@ class AppPermsWillExpireForOrgAdminMsg(UserMessage):
|
||||||
|
|
||||||
def get_items_with_url(self):
|
def get_items_with_url(self):
|
||||||
items_with_url = []
|
items_with_url = []
|
||||||
|
perm_detail_url = urljoin(settings.SITE_URL, '/ui/#/perms/app-permissions/{}')
|
||||||
for perm in self.perms:
|
for perm in self.perms:
|
||||||
url = js_reverse(
|
url = perm_detail_url.format(perm.id) + f'?oid={perm.org_id}'
|
||||||
'perms:application-permission-detail',
|
|
||||||
kwargs={'pk': perm.id}, external=True,
|
|
||||||
api_to_ui=True
|
|
||||||
) + f'?oid={perm.org_id}'
|
|
||||||
items_with_url.append([perm.name, url])
|
items_with_url.append([perm.name, url])
|
||||||
return items_with_url
|
return items_with_url
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ from common.utils import get_logger
|
||||||
from common.utils.timezone import local_now, dt_formatter, dt_parser
|
from common.utils.timezone import local_now, dt_formatter, dt_parser
|
||||||
from ops.celery.decorator import register_as_period_task
|
from ops.celery.decorator import register_as_period_task
|
||||||
from perms.notifications import (
|
from perms.notifications import (
|
||||||
PermedWillExpireUserMsg, AssetPermsWillExpireForOrgAdminMsg,
|
PermedAssetsWillExpireUserMsg, AssetPermsWillExpireForOrgAdminMsg,
|
||||||
PermedAppsWillExpireUserMsg, AppPermsWillExpireForOrgAdminMsg
|
PermedAppsWillExpireUserMsg, AppPermsWillExpireForOrgAdminMsg
|
||||||
)
|
)
|
||||||
from perms.models import AssetPermission, ApplicationPermission
|
from perms.models import AssetPermission, ApplicationPermission
|
||||||
|
@ -83,7 +83,7 @@ def check_asset_permission_will_expired():
|
||||||
user_asset_mapper[u].update(assets)
|
user_asset_mapper[u].update(assets)
|
||||||
|
|
||||||
for user, assets in user_asset_mapper.items():
|
for user, assets in user_asset_mapper.items():
|
||||||
PermedWillExpireUserMsg(user, assets).publish_async()
|
PermedAssetsWillExpireUserMsg(user, assets).publish_async()
|
||||||
|
|
||||||
for org, perms in org_perm_mapper.items():
|
for org, perms in org_perm_mapper.items():
|
||||||
org_admins = org.admins.all()
|
org_admins = org.admins.all()
|
||||||
|
|
|
@ -17,8 +17,5 @@
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<p>
|
<p>
|
||||||
---<br />
|
{% trans 'If you have any question, please contact the administrator' %}
|
||||||
<small>
|
|
||||||
{% trans 'If you have any question, please contact the administrator' %}
|
|
||||||
</small>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import AllowAny
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
from django.templatetags.static import static
|
|
||||||
|
|
||||||
from jumpserver.utils import has_valid_xpack_license
|
from jumpserver.utils import has_valid_xpack_license
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from .. import serializers
|
from .. import serializers
|
||||||
|
from ..utils import get_interface_setting
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
@ -19,30 +18,14 @@ class PublicSettingApi(generics.RetrieveAPIView):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_logo_urls():
|
def get_logo_urls():
|
||||||
logo_urls = {
|
interface = get_interface_setting()
|
||||||
'logo_logout': static('img/logo.png'),
|
keys = ['logo_logout', 'logo_index', 'login_image', 'favicon']
|
||||||
'logo_index': static('img/logo_text.png'),
|
return {k: interface[k] for k in keys}
|
||||||
'login_image': static('img/login_image.jpg'),
|
|
||||||
'favicon': static('img/facio.ico')
|
|
||||||
}
|
|
||||||
if not settings.XPACK_ENABLED:
|
|
||||||
return logo_urls
|
|
||||||
from xpack.plugins.interface.models import Interface
|
|
||||||
obj = Interface.interface()
|
|
||||||
if not obj:
|
|
||||||
return logo_urls
|
|
||||||
for attr in ['logo_logout', 'logo_index', 'login_image', 'favicon']:
|
|
||||||
if getattr(obj, attr, '') and getattr(obj, attr).url:
|
|
||||||
logo_urls.update({attr: getattr(obj, attr).url})
|
|
||||||
return logo_urls
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_login_title():
|
def get_login_title():
|
||||||
default_title = _('Welcome to the JumpServer open source Bastion Host')
|
interface = get_interface_setting()
|
||||||
if not settings.XPACK_ENABLED:
|
return interface['login_title']
|
||||||
return default_title
|
|
||||||
from xpack.plugins.interface.models import Interface
|
|
||||||
return Interface.get_login_title()
|
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
instance = {
|
instance = {
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
from jumpserver.context_processor import default_interface
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
class ObjectDict(dict):
|
class ObjectDict(dict):
|
||||||
|
@ -16,3 +18,14 @@ class ObjectDict(dict):
|
||||||
del self[name]
|
del self[name]
|
||||||
else:
|
else:
|
||||||
raise AttributeError("No such attribute: " + name)
|
raise AttributeError("No such attribute: " + name)
|
||||||
|
|
||||||
|
|
||||||
|
def get_interface_setting():
|
||||||
|
if not settings.XPACK_ENABLED:
|
||||||
|
return default_interface
|
||||||
|
from xpack.plugins.interface.models import Interface
|
||||||
|
return Interface.get_interface_setting()
|
||||||
|
|
||||||
|
|
||||||
|
def get_login_title():
|
||||||
|
return get_interface_setting()['login_title']
|
||||||
|
|
|
@ -134,11 +134,8 @@ class Terminal(StorageMixin, TerminalStatusMixin, models.Model):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_login_title_setting():
|
def get_login_title_setting():
|
||||||
login_title = None
|
from settings.utils import get_login_title
|
||||||
if settings.XPACK_ENABLED:
|
return {'TERMINAL_HEADER_TITLE': get_login_title()}
|
||||||
from xpack.plugins.interface.models import Interface
|
|
||||||
login_title = Interface.get_login_title()
|
|
||||||
return {'TERMINAL_HEADER_TITLE': login_title}
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def config(self):
|
def config(self):
|
||||||
|
|
|
@ -13,6 +13,8 @@ from notifications.models import SystemMsgSubscription
|
||||||
from notifications.backends import BACKEND
|
from notifications.backends import BACKEND
|
||||||
from orgs.utils import tmp_to_root_org
|
from orgs.utils import tmp_to_root_org
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
|
from common.utils.timezone import local_now_display
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
@ -73,25 +75,26 @@ class CommandAlertMessage(CommandAlertMixin, SystemMessage):
|
||||||
@classmethod
|
@classmethod
|
||||||
def gen_test_msg(cls):
|
def gen_test_msg(cls):
|
||||||
command = Command.objects.first().to_dict()
|
command = Command.objects.first().to_dict()
|
||||||
|
command['session'] = Session.objects.first().id
|
||||||
return cls(command)
|
return cls(command)
|
||||||
|
|
||||||
def get_html_msg(self) -> dict:
|
def get_html_msg(self) -> dict:
|
||||||
command = self.command
|
command = self.command
|
||||||
|
|
||||||
with tmp_to_root_org():
|
|
||||||
session = Session.objects.get(id=command['session'])
|
|
||||||
session_detail_url = reverse(
|
session_detail_url = reverse(
|
||||||
'api-terminal:session-detail', kwargs={'pk': command['session']},
|
'api-terminal:session-detail', kwargs={'pk': command['session']},
|
||||||
external=True, api_to_ui=True
|
external=True, api_to_ui=True
|
||||||
)
|
) + '?oid={}'.format(self.command['org_id'])
|
||||||
|
level = Command.get_risk_level_str(command['risk_level'])
|
||||||
|
items = {
|
||||||
|
_("Asset"): command['asset'],
|
||||||
|
_("User"): command['user'],
|
||||||
|
_("Level"): level,
|
||||||
|
_("Date"): local_now_display(),
|
||||||
|
}
|
||||||
context = {
|
context = {
|
||||||
'command': command['input'],
|
'items': items,
|
||||||
'hostname': command['asset'],
|
'session_url': session_detail_url,
|
||||||
'host_ip': session.asset_obj.ip,
|
"command": command['input'],
|
||||||
'user': command['user'],
|
|
||||||
'risk_level': Command.get_risk_level_str(command['risk_level']),
|
|
||||||
'session_detail_url': session_detail_url,
|
|
||||||
'oid': session.org_id
|
|
||||||
}
|
}
|
||||||
message = render_to_string('terminal/_msg_command_alert.html', context)
|
message = render_to_string('terminal/_msg_command_alert.html', context)
|
||||||
return {
|
return {
|
||||||
|
@ -122,19 +125,25 @@ class CommandExecutionAlert(CommandAlertMixin, SystemMessage):
|
||||||
|
|
||||||
def get_html_msg(self) -> dict:
|
def get_html_msg(self) -> dict:
|
||||||
command = self.command
|
command = self.command
|
||||||
_input = command['input']
|
|
||||||
_input = _input.replace('\n', '<br>')
|
|
||||||
|
|
||||||
assets_with_url = []
|
assets_with_url = []
|
||||||
for asset in command['assets']:
|
for asset in command['assets']:
|
||||||
url = reverse('assets:asset-detail', kwargs={'pk': asset.id}, api_to_ui=True, external=True)
|
url = reverse(
|
||||||
|
'assets:asset-detail', kwargs={'pk': asset.id},
|
||||||
|
api_to_ui=True, external=True
|
||||||
|
) + '?oid={}'.format(asset.org_id)
|
||||||
assets_with_url.append([asset, url])
|
assets_with_url.append([asset, url])
|
||||||
|
|
||||||
|
level = Command.get_risk_level_str(command['risk_level'])
|
||||||
|
items = {
|
||||||
|
_("User"): command['user'],
|
||||||
|
_("Level"): level,
|
||||||
|
_("Date"): local_now_display(),
|
||||||
|
}
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'command': _input,
|
'items': items,
|
||||||
'assets_with_url': assets_with_url,
|
'assets_with_url': assets_with_url,
|
||||||
'user': command['user'],
|
'command': command['input'],
|
||||||
'risk_level': Command.get_risk_level_str(command['risk_level'])
|
|
||||||
}
|
}
|
||||||
message = render_to_string('terminal/_msg_command_execute_alert.html', context)
|
message = render_to_string('terminal/_msg_command_execute_alert.html', context)
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
<p>
|
<div>
|
||||||
<b>{% trans 'Command' %}:</b> {{ command }}
|
{% for item, value in items.items %}
|
||||||
</p>
|
<span class="cmd-item">
|
||||||
<p>
|
<b>{{ item }}:</b> {{ value }}
|
||||||
<b>{% trans 'Asset' %}:</b> {{ hostname }}({{ host_ip }})
|
</span>
|
||||||
</p>
|
<br />
|
||||||
<p>
|
{% endfor %}
|
||||||
<b>{% trans 'User' %}:</b> {{ user }}
|
<b>{% trans 'Session' %}:</b> <a href="{{ session_url }}">{% trans 'view' %}</a>
|
||||||
</p>
|
<br />
|
||||||
<p>
|
<b>{% trans 'Command' %}: </b><br />
|
||||||
<b>{% trans 'Level' %}:</b> {{ risk_level }}
|
<pre>
|
||||||
</p>
|
{{ command }}
|
||||||
<p>
|
</pre>
|
||||||
<b>{% trans 'Session' %}:</b> <a href="{{ session_detail_url}}?oid={{ oid }}">{% trans 'view' %}</a>
|
</div>
|
||||||
</p>
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
<p>
|
|
||||||
<b>{% trans 'User' %}:</b> {{ user }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>{% trans 'Level' %}:</b> {{ risk_level }}
|
|
||||||
</p>
|
|
||||||
<div>
|
<div>
|
||||||
<b>{% trans 'Command' %}: </b><br>
|
{% for item, value in items.items %}
|
||||||
<pre>
|
<span class="cmd-item">
|
||||||
|
<b>{{ item }}:</b> {{ value }}
|
||||||
|
</span>
|
||||||
|
<br />
|
||||||
|
{% endfor %}
|
||||||
|
<b>{% trans 'Command' %}: </b><br />
|
||||||
|
<pre>
|
||||||
{{ command }}
|
{{ command }}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<b>{% trans 'Assets' %}:</b><br>
|
<b>{% trans 'Assets' %}:</b><br>
|
||||||
|
|
|
@ -19,6 +19,7 @@ class BaseTicketMessage(UserMessage):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ticket_detail_url(self):
|
def ticket_detail_url(self):
|
||||||
|
tp = self.ticket.type
|
||||||
return urljoin(settings.SITE_URL, const.TICKET_DETAIL_URL.format(id=str(self.ticket.id)))
|
return urljoin(settings.SITE_URL, const.TICKET_DETAIL_URL.format(id=str(self.ticket.id)))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
from datetime import datetime
|
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -10,6 +9,38 @@ from common.utils import reverse, get_request_ip_or_data, get_request_user_agent
|
||||||
from notifications.notifications import UserMessage
|
from notifications.notifications import UserMessage
|
||||||
|
|
||||||
|
|
||||||
|
class UserCreatedMsg(UserMessage):
|
||||||
|
def get_html_msg(self) -> dict:
|
||||||
|
user = self.user
|
||||||
|
subject = _('Create account successfully')
|
||||||
|
if settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT:
|
||||||
|
subject = settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT
|
||||||
|
|
||||||
|
honorific = settings.EMAIL_CUSTOM_USER_CREATED_HONORIFIC or _('Hello {}').format(user.name)
|
||||||
|
signature = settings.EMAIL_CUSTOM_USER_CREATED_SIGNATURE or 'JumpServer'
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'honorific': honorific,
|
||||||
|
'signature': signature,
|
||||||
|
'username': user.username,
|
||||||
|
'rest_password_url': reverse('authentication:reset-password', external=True),
|
||||||
|
'rest_password_token': user.generate_reset_token(),
|
||||||
|
'forget_password_url': reverse('authentication:forgot-password', external=True),
|
||||||
|
'email': user.email,
|
||||||
|
'login_url': reverse('authentication:login', external=True),
|
||||||
|
}
|
||||||
|
message = render_to_string('users/_msg_user_created.html', context)
|
||||||
|
return {
|
||||||
|
'subject': subject,
|
||||||
|
'message': message
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def gen_test_msg(cls):
|
||||||
|
user = cls.get_test_user()
|
||||||
|
return cls(user)
|
||||||
|
|
||||||
|
|
||||||
class ResetPasswordMsg(UserMessage):
|
class ResetPasswordMsg(UserMessage):
|
||||||
def __init__(self, user):
|
def __init__(self, user):
|
||||||
super().__init__(user)
|
super().__init__(user)
|
||||||
|
@ -71,18 +102,17 @@ class ResetPasswordSuccessMsg(UserMessage):
|
||||||
|
|
||||||
|
|
||||||
class PasswordExpirationReminderMsg(UserMessage):
|
class PasswordExpirationReminderMsg(UserMessage):
|
||||||
update_password_url = urljoin(settings.SITE_URL, '/ui/#/users/profile/?activeTab=PasswordUpdate')
|
|
||||||
|
|
||||||
def get_html_msg(self) -> dict:
|
def get_html_msg(self) -> dict:
|
||||||
user = self.user
|
user = self.user
|
||||||
subject = _('Password is about expire')
|
subject = _('Password is about expire')
|
||||||
|
|
||||||
date_password_expired_local = timezone.localtime(user.date_password_expired)
|
date_password_expired_local = timezone.localtime(user.date_password_expired)
|
||||||
|
update_password_url = urljoin(settings.SITE_URL, '/ui/#/users/profile/?activeTab=PasswordUpdate')
|
||||||
date_password_expired = date_password_expired_local.strftime('%Y-%m-%d %H:%M:%S')
|
date_password_expired = date_password_expired_local.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
context = {
|
context = {
|
||||||
'name': user.name,
|
'name': user.name,
|
||||||
'date_password_expired': date_password_expired,
|
'date_password_expired': date_password_expired,
|
||||||
'update_password_url': self.update_password_url,
|
'update_password_url': update_password_url,
|
||||||
'forget_password_url': reverse('authentication:forgot-password', external=True),
|
'forget_password_url': reverse('authentication:forgot-password', external=True),
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
'login_url': reverse('authentication:login', external=True),
|
'login_url': reverse('authentication:login', external=True),
|
||||||
|
@ -125,9 +155,10 @@ class UserExpirationReminderMsg(UserMessage):
|
||||||
class ResetSSHKeyMsg(UserMessage):
|
class ResetSSHKeyMsg(UserMessage):
|
||||||
def get_html_msg(self) -> dict:
|
def get_html_msg(self) -> dict:
|
||||||
subject = _('Reset SSH Key')
|
subject = _('Reset SSH Key')
|
||||||
|
update_url = urljoin(settings.SITE_URL, '/ui/#/users/profile/?activeTab=SSHUpdate')
|
||||||
context = {
|
context = {
|
||||||
'name': self.user.name,
|
'name': self.user.name,
|
||||||
'login_url': reverse('authentication:login', external=True),
|
'url': update_url,
|
||||||
}
|
}
|
||||||
message = render_to_string('users/_msg_reset_ssh_key.html', context)
|
message = render_to_string('users/_msg_reset_ssh_key.html', context)
|
||||||
return {
|
return {
|
||||||
|
@ -147,7 +178,7 @@ class ResetMFAMsg(UserMessage):
|
||||||
subject = _('Reset MFA')
|
subject = _('Reset MFA')
|
||||||
context = {
|
context = {
|
||||||
'name': self.user.name,
|
'name': self.user.name,
|
||||||
'login_url': reverse('authentication:login', external=True),
|
'url': reverse('authentication:user-otp-enable-start', external=True),
|
||||||
}
|
}
|
||||||
message = render_to_string('users/_msg_reset_mfa.html', context)
|
message = render_to_string('users/_msg_reset_mfa.html', context)
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -13,10 +13,6 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
{% trans 'If your password has expired, please click' %}
|
{% trans 'If your password has expired, please click the link below to' %}
|
||||||
<a href="{{ forget_password_url }}?email={{ email }}">{% trans 'Reset password' %}</a>
|
<a href="{{ forget_password_url }}?email={{ email }}">{% trans 'Reset password' %}</a>
|
||||||
{% trans 'to apply for a password reset email.' %}
|
|
||||||
</p>
|
</p>
|
||||||
---
|
|
||||||
<br>
|
|
||||||
<a href="{{ login_url }}">{% trans 'Login direct' %}</a>
|
|
|
@ -4,9 +4,9 @@
|
||||||
{% trans 'Hello' %} {{ name }},
|
{% trans 'Hello' %} {{ name }},
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{% trans 'Your MFA has been reset by site administrator.' %} <br />
|
{% trans 'Your MFA has been reset by site administrator' %} <br />
|
||||||
{% trans 'Please login and reset your MFA.' %}
|
{% trans 'Please click the link below to set' %}
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<a href="{{ url }}" class='showLink'>{% trans 'Click here set' %}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
|
||||||
<a href="{{ login_url }}">{% trans 'Login direct' %}</a>
|
|
||||||
</p>
|
|
|
@ -4,9 +4,9 @@
|
||||||
{% trans 'Hello' %} {{ name }},
|
{% trans 'Hello' %} {{ name }},
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{% trans 'Your ssh public key has been reset by site administrator.' %} <br />
|
{% trans 'Your ssh public key has been reset by site administrator' %} <br />
|
||||||
{% trans 'Please login and reset your ssh public key.' %}
|
{% trans 'Please click the link below to set' %}
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<a href="{{ url }}" class='showLink'>{% trans 'Click here set' %}</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
|
||||||
<a href="{{ login_url }}">{% trans 'Login direct' %}</a>
|
|
||||||
</p>
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{{ honorific }}:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p>{% trans 'Your account has been created successfully' %}</p>
|
||||||
|
<p>
|
||||||
|
{% trans 'Username' %}: {{ username }} <br />
|
||||||
|
{% trans 'Password' %}:
|
||||||
|
<a href="{{ rest_password_url}}?token={{ rest_password_token }}">
|
||||||
|
{% trans 'click here to set your password' %}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{% trans 'This link is valid for 1 hour. After it expires' %}
|
||||||
|
<a href="{{ forget_password_url }}?email={{ email }}">{% trans 'request new one' %}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
|
@ -8,67 +8,24 @@ import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext as _
|
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
||||||
from common.tasks import send_mail_async
|
from common.tasks import send_mail_async
|
||||||
from common.utils import reverse, get_object_or_none, get_request_ip_or_data, get_request_user_agent
|
from common.utils import reverse, get_object_or_none
|
||||||
from .models import User
|
from .models import User
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('jumpserver')
|
logger = logging.getLogger('jumpserver')
|
||||||
|
|
||||||
|
|
||||||
def construct_user_created_email_body(user):
|
|
||||||
default_body = _("""
|
|
||||||
<div>
|
|
||||||
<p>Your account has been created successfully</p>
|
|
||||||
<div>
|
|
||||||
Username: %(username)s
|
|
||||||
<br/>
|
|
||||||
Password: <a href="%(rest_password_url)s?token=%(rest_password_token)s">
|
|
||||||
click here to set your password</a>
|
|
||||||
(This link is valid for 1 hour. After it expires, <a href="%(forget_password_url)s?email=%(email)s">request new one</a>)
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p>---</p>
|
|
||||||
<a href="%(login_url)s">Login direct</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
""") % {
|
|
||||||
'username': user.username,
|
|
||||||
'rest_password_url': reverse('authentication:reset-password', external=True),
|
|
||||||
'rest_password_token': user.generate_reset_token(),
|
|
||||||
'forget_password_url': reverse('authentication:forgot-password', external=True),
|
|
||||||
'email': user.email,
|
|
||||||
'login_url': reverse('authentication:login', external=True),
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.EMAIL_CUSTOM_USER_CREATED_BODY:
|
|
||||||
custom_body = '<p style="text-indent:2em">' + settings.EMAIL_CUSTOM_USER_CREATED_BODY + '</p>'
|
|
||||||
else:
|
|
||||||
custom_body = ''
|
|
||||||
body = custom_body + default_body
|
|
||||||
return body
|
|
||||||
|
|
||||||
|
|
||||||
def send_user_created_mail(user):
|
def send_user_created_mail(user):
|
||||||
|
from .notifications import UserCreatedMsg
|
||||||
|
|
||||||
recipient_list = [user.email]
|
recipient_list = [user.email]
|
||||||
subject = _('Create account successfully')
|
msg = UserCreatedMsg.html_msg
|
||||||
if settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT:
|
subject = msg['subject']
|
||||||
subject = settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT
|
message = msg['message']
|
||||||
|
|
||||||
honorific = '<p>' + _('Hello %(name)s') % {'name': user.name} + ':</p>'
|
|
||||||
if settings.EMAIL_CUSTOM_USER_CREATED_HONORIFIC:
|
|
||||||
honorific = '<p>' + settings.EMAIL_CUSTOM_USER_CREATED_HONORIFIC + ':</p>'
|
|
||||||
|
|
||||||
body = construct_user_created_email_body(user)
|
|
||||||
|
|
||||||
signature = '<p style="float:right">jumpserver</p>'
|
|
||||||
if settings.EMAIL_CUSTOM_USER_CREATED_SIGNATURE:
|
|
||||||
signature = '<p style="float:right">' + settings.EMAIL_CUSTOM_USER_CREATED_SIGNATURE + '</p>'
|
|
||||||
|
|
||||||
message = honorific + body + signature
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
try:
|
try:
|
||||||
print(message)
|
print(message)
|
||||||
|
|
Loading…
Reference in New Issue