pref: 修改使用的消息内容 (#7061)

* perf:  再次优化通知

* pref: 修改使用的消息内容

* perf: 修复url地址

Co-authored-by: ibuler <ibuler@qq.com>
pull/7063/head
fit2bot 2021-10-22 20:06:16 +08:00 committed by GitHub
parent a0db2f6ef8
commit c244cf5f43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 570 additions and 420 deletions

View File

@ -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>

View File

@ -1,15 +1,17 @@
{% load i18n %} {% load i18n %}
<p>
{% trans 'Hello' %} {{ user.name }}, {% trans 'Hello' %} {{ user.name }},
<br> </p>
<p>
{% trans 'Please click the link below to reset your password, if not your request, concern your account security' %} {% trans 'Please click the link below to reset your password, if not your request, concern your account security' %}
<br> <br>
<br> <br>
<a href="{{ rest_password_url }}?token={{ rest_password_token}}" class='showLink'>{% trans 'Click here reset password' %}</a> <a href="{{ rest_password_url }}?token={{ rest_password_token}}" class='showLink'>{% trans 'Click here reset password' %}</a>
<br> </p>
<br>
{% 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> {% trans 'This link is valid for 1 hour. After it expires' %}
--- <a href="{{ forget_password_url }}?email={{ user.email }}">
<br> {% trans 'request new one' %}
<a href="{{ login_url }}">{% trans 'Login direct' %}</a> </a>
<br> </p>

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -4,10 +4,7 @@ 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 = {
def jumpserver_processor(request):
# Setting default pk
context = {
'DEFAULT_PK': '00000000-0000-0000-0000-000000000000', 'DEFAULT_PK': '00000000-0000-0000-0000-000000000000',
'LOGO_URL': static('img/logo.png'), 'LOGO_URL': static('img/logo.png'),
'LOGO_TEXT_URL': static('img/logo_text.png'), 'LOGO_TEXT_URL': static('img/logo_text.png'),
@ -18,13 +15,28 @@ def jumpserver_processor(request):
'LOGIN_DINGTALK_LOGO_URL': static('img/login_dingtalk_logo.png'), 'LOGIN_DINGTALK_LOGO_URL': static('img/login_dingtalk_logo.png'),
'LOGIN_FEISHU_LOGO_URL': static('img/login_feishu_logo.png'), 'LOGIN_FEISHU_LOGO_URL': static('img/login_feishu_logo.png'),
'JMS_TITLE': _('JumpServer Open Source Bastion Host'), '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):
# Setting default pk
context = default_context
context.update({
'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

View File

@ -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

View File

@ -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"

View File

@ -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)

View File

@ -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

View File

@ -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')
]

View File

@ -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
terms_with_errors = []
terms = Terminal.objects.all()[:5]
for i, term in enumerate(terms, 1):
errors = []
for item, data in items_mapper.items(): for item, data in items_mapper.items():
msg = data['alarm_msg_format'] msg = data['alarm_msg_format']
max_threshold = data['max_threshold'] max_threshold = data['max_threshold']
value = 123 value = 123 // i+1
msg = msg.format(max_threshold=max_threshold, value=value, name='Fake terminal') msg = msg.format(max_threshold=max_threshold, value=value, name=term.name)
alarm_messages.append(msg) errors.append(msg)
terms_with_errors.append([term, errors])
msg = '<br>'.join(alarm_messages) return cls(terms_with_errors)
return cls(msg)
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 = []

View File

@ -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>

View File

@ -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

View File

@ -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()

View File

@ -17,8 +17,5 @@
<br /> <br />
<p> <p>
---<br />
<small>
{% trans 'If you have any question, please contact the administrator' %} {% trans 'If you have any question, please contact the administrator' %}
</small>
</p> </p>

View File

@ -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 = {

View File

@ -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']

View File

@ -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):

View File

@ -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 {

View File

@ -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>

View File

@ -1,13 +1,13 @@
{% 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 %}
<span class="cmd-item">
<b>{{ item }}:</b> {{ value }}
</span>
<br />
{% endfor %}
<b>{% trans 'Command' %}: </b><br />
<pre> <pre>
{{ command }} {{ command }}
</pre> </pre>

View File

@ -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

View File

@ -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 {

View File

@ -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>

View File

@ -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' %}
</p> <br>
<p> <br>
<a href="{{ login_url }}">{% trans 'Login direct' %}</a> <a href="{{ url }}" class='showLink'>{% trans 'Click here set' %}</a>
</p> </p>

View File

@ -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' %}
</p> <br>
<p> <br>
<a href="{{ login_url }}">{% trans 'Login direct' %}</a> <a href="{{ url }}" class='showLink'>{% trans 'Click here set' %}</a>
</p> </p>

View File

@ -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>

View File

@ -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)