Browse Source

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

* perf:  再次优化通知

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

* perf: 修复url地址

Co-authored-by: ibuler <ibuler@qq.com>
pull/7063/head
fit2bot 3 years ago committed by GitHub
parent
commit
c244cf5f43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      apps/authentication/templates/authentication/_msg_different_city.html
  2. 30
      apps/authentication/templates/authentication/_msg_reset_password.html
  3. 16
      apps/authentication/templates/authentication/_msg_rest_password_success.html
  4. 4
      apps/common/utils/timezone.py
  5. 1
      apps/jumpserver/api.py
  6. 36
      apps/jumpserver/context_processor.py
  7. 4
      apps/locale/zh/LC_MESSAGES/django.mo
  8. 370
      apps/locale/zh/LC_MESSAGES/django.po
  9. 45
      apps/notifications/api/notifications.py
  10. 71
      apps/notifications/notifications.py
  11. 6
      apps/notifications/urls/api_urls.py
  12. 85
      apps/ops/notifications.py
  13. 10
      apps/ops/templates/ops/_msg_terminal_performance.html
  14. 11
      apps/perms/notifications.py
  15. 4
      apps/perms/tasks.py
  16. 5
      apps/perms/templates/perms/_msg_permed_items_expire.html
  17. 29
      apps/settings/api/public.py
  18. 13
      apps/settings/utils/common.py
  19. 7
      apps/terminal/models/terminal.py
  20. 45
      apps/terminal/notifications.py
  21. 29
      apps/terminal/templates/terminal/_msg_command_alert.html
  22. 18
      apps/terminal/templates/terminal/_msg_command_execute_alert.html
  23. 1
      apps/tickets/notifications.py
  24. 43
      apps/users/notifications.py
  25. 6
      apps/users/templates/users/_msg_password_expire_reminder.html
  26. 10
      apps/users/templates/users/_msg_reset_mfa.html
  27. 10
      apps/users/templates/users/_msg_reset_ssh_key.html
  28. 20
      apps/users/templates/users/_msg_user_created.html
  29. 55
      apps/users/utils.py

4
apps/authentication/templates/authentication/_msg_different_city.html

@ -12,7 +12,5 @@
</p>
<p>
<small>
{% trans 'If you suspect that the login behavior is abnormal, please modify the account password in time.' %}
</small>
{% trans 'If you suspect that the login behavior is abnormal, please modify the account password in time.' %}
</p>

30
apps/authentication/templates/authentication/_msg_reset_password.html

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

16
apps/authentication/templates/authentication/_msg_rest_password_success.html

@ -1,18 +1,14 @@
{% load i18n %}
<p>{% trans 'Hello' %}: {{ name }},</p>
<p>{% trans 'Hello' %} {{ name }},</p>
<p>
{% trans 'Your password has just been successfully updated.' %}
{% trans 'Your password has just been successfully updated' %}
</p>
<p>
{% trans 'IP' %}: {{ ip_address }} <br />
{% trans 'Browser' %}: {{ browser }}
<b>{% trans 'IP' %}:</b> {{ ip_address }} <br />
<b>{% trans 'Browser' %}:</b> {{ browser }}
</p>
<p>---</p>
<p>
<small>
{% 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.' %}
</small>
{% 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' %}
</p>

4
apps/common/utils/timezone.py

@ -28,6 +28,10 @@ def local_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()
dt_parser = _rest_dt_field.to_internal_value
dt_formatter = _rest_dt_field.to_representation

1
apps/jumpserver/api.py

@ -8,7 +8,6 @@ from django.http.response import JsonResponse, HttpResponse
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
from collections import Counter
from django.conf import settings
from rest_framework.response import Response
from users.models import User

36
apps/jumpserver/context_processor.py

@ -4,27 +4,39 @@ from django.templatetags.static import static
from django.conf import settings
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):
# Setting default pk
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'),
context = default_context
context.update({
'VERSION': settings.VERSION,
'COPYRIGHT': 'FIT2CLOUD 飞致云' + ' © 2014-2021',
'SECURITY_COMMAND_EXECUTION': settings.SECURITY_COMMAND_EXECUTION,
'SECURITY_MFA_VERIFY_TTL': settings.SECURITY_MFA_VERIFY_TTL,
'FORCE_SCRIPT_NAME': settings.FORCE_SCRIPT_NAME,
'SECURITY_VIEW_AUTH_NEED_MFA': settings.SECURITY_VIEW_AUTH_NEED_MFA,
}
})
return context

4
apps/locale/zh/LC_MESSAGES/django.mo

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b5a90a96a51ef2f38d4530f3e5b79cd59b07dbca39f60bc35cde5ee0e364b210
size 91089
oid sha256:b2663d90ceadd419c40abd472a3b5030b007b1e1db1fcaeda9893ff90cd7cdd6
size 89955

370
apps/locale/zh/LC_MESSAGES/django.po

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\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"
"Last-Translator: ibuler <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
#: templates/index.html:78 terminal/backends/command/models.py:18
#: terminal/backends/command/serializers.py:12 terminal/models/session.py:38
#: terminal/templates/terminal/_msg_command_alert.html:10
#: terminal/templates/terminal/_msg_command_execute_alert.html:4
#: terminal/notifications.py:91 terminal/notifications.py:136
#: 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/serializers/group.py:19
@ -128,7 +127,7 @@ msgstr "系统用户"
#: audits/models.py:38 perms/models/asset_permission.py:99
#: templates/index.html:82 terminal/backends/command/models.py:19
#: 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:70
#: 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
#: authentication/templates/authentication/_msg_different_city.html:9
#: 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
#: xpack/plugins/change_auth_plan/models/asset.py:35
#: xpack/plugins/change_auth_plan/models/asset.py:191
@ -174,7 +174,7 @@ msgstr ""
#: applications/serializers/attrs/application_type/mysql_workbench.py:18
#: assets/models/asset.py:180 assets/models/domain.py:61
#: 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
#: users/templates/users/_granted_assets.html:26
#: users/templates/users/user_asset_permission.html:156
@ -384,6 +384,7 @@ msgstr "目标URL"
#: authentication/forms.py:22
#: authentication/templates/authentication/login.html:151
#: 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_password_update.html:43
#: users/templates/users/user_password_verify.html:18
@ -647,7 +648,7 @@ msgstr "正则表达式"
#: assets/models/cmd_filter.py:41 ops/models/command.py:25
#: 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
msgid "Command"
msgstr "命令"
@ -1445,7 +1446,7 @@ msgstr "{ApplicationPermission} 添加 {SystemUser}"
msgid "{ApplicationPermission} REMOVE {SystemUser}"
msgstr "{ApplicationPermission} 移除 {SystemUser}"
#: authentication/api/connection_token.py:235
#: authentication/api/connection_token.py:239
msgid "Invalid token"
msgstr "无效的令牌"
@ -1731,6 +1732,7 @@ msgid "Secret"
msgstr "密钥"
#: authentication/templates/authentication/_access_key_modal.html:33
#: terminal/notifications.py:93 terminal/notifications.py:138
msgid "Date"
msgstr "日期"
@ -1788,8 +1790,8 @@ msgid "Code error"
msgstr "代码错误"
#: authentication/templates/authentication/_msg_different_city.html:3
#: authentication/templates/authentication/_msg_reset_password.html:2
#: authentication/templates/authentication/_msg_rest_password_success.html:3
#: authentication/templates/authentication/_msg_reset_password.html:3
#: authentication/templates/authentication/_msg_rest_password_success.html:2
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: perms/templates/perms/_msg_permed_items_expire.html:3
#: users/templates/users/_msg_account_expire_reminder.html:4
@ -1807,53 +1809,48 @@ msgstr "你的账号存在异地登录行为,请关注。"
msgid "Login time"
msgstr "登录日期"
#: authentication/templates/authentication/_msg_different_city.html:16
#: authentication/templates/authentication/_msg_different_city.html:15
msgid ""
"If you suspect that the login behavior is abnormal, please modify the "
"account password in time."
msgstr "若怀疑此次登录行为异常,请及时修改账号密码"
#: authentication/templates/authentication/_msg_reset_password.html:4
#: authentication/templates/authentication/_msg_reset_password.html:6
msgid ""
"Please click the link below to reset your password, if not your request, "
"concern your account security"
msgstr "请点击下面链接重置密码, 如果不是您申请的,请关注账号安全"
#: authentication/templates/authentication/_msg_reset_password.html:7
#: authentication/templates/authentication/_msg_reset_password.html:9
msgid "Click here reset password"
msgstr "点击这里重置密码"
#: authentication/templates/authentication/_msg_reset_password.html:10
msgid "This link is valid for 1 hour. After it expires,"
#: authentication/templates/authentication/_msg_reset_password.html:13
#: users/templates/users/_msg_user_created.html:17
msgid "This link is valid for 1 hour. After it expires"
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"
msgstr "重新申请"
#: authentication/templates/authentication/_msg_reset_password.html:14
#: users/templates/users/_msg_password_expire_reminder.html:22
#: users/templates/users/_msg_reset_mfa.html:11
#: users/templates/users/_msg_reset_ssh_key.html:11
msgid "Login direct"
msgstr "直接登录"
#: authentication/templates/authentication/_msg_rest_password_success.html:6
msgid "Your password has just been successfully updated."
msgstr "你的密码刚刚已经成功更新。"
#: authentication/templates/authentication/_msg_rest_password_success.html:5
msgid "Your password has just been successfully updated"
msgstr "你的密码刚刚成功更新"
#: authentication/templates/authentication/_msg_rest_password_success.html:10
#: authentication/templates/authentication/_msg_rest_password_success.html:9
msgid "Browser"
msgstr "浏览器"
#: authentication/templates/authentication/_msg_rest_password_success.html:15
#: authentication/templates/authentication/_msg_rest_password_success.html:12
msgid ""
"If the password update was not initiated by you, your account may have "
"security issues."
msgstr "如果这次密码更新不是由你发起的,那么你的账号可能存在安全问题"
"security issues"
msgstr "如果这次密码更新不是由你发起的,那么你的账号可能存在安全问题"
#: authentication/templates/authentication/_msg_rest_password_success.html:16
msgid "If you have any questions, you can contact the administrator."
#: authentication/templates/authentication/_msg_rest_password_success.html:13
msgid "If you have any questions, you can contact the administrator"
msgstr "如果有疑问或需求,请联系系统管理员"
#: authentication/templates/authentication/login.html:143
@ -2206,7 +2203,7 @@ msgstr "不能包含特殊字符"
msgid "The mobile phone number format is incorrect"
msgstr "手机号格式不正确"
#: jumpserver/context_processor.py:20
#: jumpserver/context_processor.py:17
msgid "JumpServer Open Source Bastion Host"
msgstr "JumpServer 开源堡垒机"
@ -2246,7 +2243,7 @@ msgstr "邮件"
msgid "Site message"
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:190
#: xpack/plugins/gathered_user/models.py:79
@ -2261,7 +2258,7 @@ msgstr "等待任务开始"
msgid "Not has host {} permission"
msgstr "没有该主机 {} 权限"
#: ops/apps.py:9 ops/notifications.py:14
#: ops/apps.py:9 ops/notifications.py:15
msgid "Operations"
msgstr "运维"
@ -2383,29 +2380,33 @@ msgstr "命令 `{}` 不允许被执行 ......."
msgid "Task end"
msgstr "任务结束"
#: ops/notifications.py:15
#: ops/notifications.py:16
msgid "Server performance"
msgstr "监控告警"
#: ops/notifications.py:54
#: ops/notifications.py:22
msgid "Terminal health check warning"
msgstr ""
#: ops/notifications.py:63
#, python-brace-format
msgid "The terminal is offline: {name}"
msgstr "终端已离线: {name}"
#: ops/notifications.py:60
#: ops/notifications.py:68
#, python-brace-format
msgid "Disk used more than {max_threshold}%: => {value} ({name})"
msgstr "硬盘使用率超过 {max_threshold}%: => {value} ({name})"
msgid "Disk used more than {max_threshold}%: => {value}"
msgstr "硬盘使用率超过 {max_threshold}%: => {value}"
#: ops/notifications.py:67
#: ops/notifications.py:73
#, python-brace-format
msgid "Memory used more than {max_threshold}%: => {value} ({name})"
msgstr "内存使用率超过 {max_threshold}%: => {value} ({name})"
msgid "Memory used more than {max_threshold}%: => {value}"
msgstr "内存使用率超过 {max_threshold}%: => {value}"
#: ops/notifications.py:74
#: ops/notifications.py:78
#, python-brace-format
msgid "CPU load more than {max_threshold}: => {value} ({name})"
msgstr "CPU 使用率超过 {max_threshold}: => {value} ({name})"
msgid "CPU load more than {max_threshold}: => {value}"
msgstr "CPU 使用率超过 {max_threshold}: => {value}"
#: ops/tasks.py:71
msgid "Clean task history period"
@ -2533,35 +2534,35 @@ msgstr "失效日期"
msgid "From ticket"
msgstr "来自工单"
#: perms/notifications.py:19
#: perms/notifications.py:15
msgid "You permed assets is about to expire"
msgstr "你授权的资产即将到期"
#: perms/notifications.py:23
#: perms/notifications.py:19
msgid "permed assets"
msgstr "授权的资产"
#: perms/notifications.py:61
#: perms/notifications.py:57
msgid "Asset permissions is about to expire"
msgstr "资产授权规则将要过期"
#: perms/notifications.py:65
#: perms/notifications.py:61
msgid "asset permissions of organization {}"
msgstr "组织 ({}) 的资产授权"
#: perms/notifications.py:91
#: perms/notifications.py:87
msgid "Your permed applications is about to expire"
msgstr "你授权的应用即将过期"
#: perms/notifications.py:94
#: perms/notifications.py:90
msgid "permed applications"
msgstr "授权的应用"
#: perms/notifications.py:132
#: perms/notifications.py:128
msgid "Application permissions is about to expire"
msgstr "应用授权规则即将过期"
#: perms/notifications.py:135
#: perms/notifications.py:131
msgid "application permissions of organization {}"
msgstr "组织 ({}) 的应用授权"
@ -2633,7 +2634,7 @@ msgstr ""
" 以下 %(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"
msgstr "如果有疑问或需求,请联系系统管理员"
@ -2671,11 +2672,6 @@ msgstr "获取 LDAP 用户为 None"
msgid "Imported {} users successfully (Organization: {})"
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
msgid "Setting"
msgstr "设置"
@ -3725,7 +3721,7 @@ msgstr "数据库应用"
msgid "Perms"
msgstr "权限管理"
#: templates/_nav.html:97 terminal/notifications.py:22
#: templates/_nav.html:97 terminal/notifications.py:24
msgid "Sessions"
msgstr "会话管理"
@ -4068,7 +4064,7 @@ msgstr "输出"
#: terminal/backends/command/models.py:23 terminal/models/sharing.py:15
#: terminal/models/sharing.py:58
#: terminal/templates/terminal/_msg_command_alert.html:16
#: terminal/templates/terminal/_msg_command_alert.html:10
msgid "Session"
msgstr "会话"
@ -4235,11 +4231,15 @@ msgstr "命令存储"
msgid "Replay storage"
msgstr "录像存储"
#: terminal/notifications.py:68
#: terminal/notifications.py:70
msgid "Danger command alert"
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"
msgstr "批量危险命令告警"
@ -4348,12 +4348,7 @@ msgstr ""
msgid "Not found"
msgstr "没有发现"
#: terminal/templates/terminal/_msg_command_alert.html:13
#: terminal/templates/terminal/_msg_command_execute_alert.html:7
msgid "Level"
msgstr "级别"
#: terminal/templates/terminal/_msg_command_alert.html:16
#: terminal/templates/terminal/_msg_command_alert.html:10
msgid "view"
msgstr "查看"
@ -4445,7 +4440,7 @@ msgstr "申请的开始日期"
msgid "Applied date expired"
msgstr "申请的失效日期"
#: tickets/handler/apply_application.py:79 tickets/handler/apply_asset.py:72
#: tickets/handler/apply_application.py:79
msgid ""
"Created by the ticket, ticket title: {}, ticket applicant: {}, ticket "
"processor: {}, ticket ID: {}"
@ -4460,87 +4455,94 @@ msgstr "申请的主机名组"
msgid "Applied actions"
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
msgid "{} {} the ticket"
msgstr "{} {}工单"
msgstr "{} {} 工单"
#: tickets/handler/base.py:113
#: tickets/handler/base.py:114
msgid "Ticket title"
msgstr "工单标题"
#: tickets/handler/base.py:114
#: tickets/handler/base.py:115
msgid "Ticket type"
msgstr "工单类型"
#: tickets/handler/base.py:115
#: tickets/handler/base.py:116
msgid "Ticket status"
msgstr "工单状态"
#: tickets/handler/base.py:116
#: tickets/handler/base.py:117
msgid "Ticket applicant"
msgstr "工单申请人"
#: tickets/handler/base.py:118
#: tickets/handler/base.py:119
msgid "Ticket basic info"
msgstr "工单基本信息"
#: tickets/handler/base.py:129
#: tickets/handler/base.py:130
msgid "No content"
msgstr "无内容"
#: tickets/handler/base.py:131
#: tickets/handler/base.py:132
msgid "Ticket applied info"
msgstr "工单申请信息"
#: tickets/handler/command_confirm.py:24
#: tickets/handler/command_confirm.py:25
msgid "Applied run user"
msgstr "申请运行的用户"
#: tickets/handler/command_confirm.py:25
#: tickets/handler/command_confirm.py:26
msgid "Applied run asset"
msgstr "申请运行的资产"
#: tickets/handler/command_confirm.py:26
#: tickets/handler/command_confirm.py:27
msgid "Applied run system user"
msgstr "申请运行的系统用户"
#: tickets/handler/command_confirm.py:27
#: tickets/handler/command_confirm.py:28
msgid "Applied run command"
msgstr "申请运行的命令"
#: tickets/handler/command_confirm.py:28
#: tickets/handler/command_confirm.py:29
msgid "Applied from session"
msgstr "申请来自会话"
#: tickets/handler/command_confirm.py:29
#: tickets/handler/command_confirm.py:30
msgid "Applied from command filter rules"
msgstr "申请来自命令过滤规则"
#: tickets/handler/command_confirm.py:30
#: tickets/handler/command_confirm.py:31
msgid "Applied from command filter"
msgstr "申请来自命令过滤规则"
#: tickets/handler/login_asset_confirm.py:16
#: tickets/handler/login_asset_confirm.py:17
msgid "Applied login user"
msgstr "申请登录的用户"
#: tickets/handler/login_asset_confirm.py:17
#: tickets/handler/login_asset_confirm.py:18
msgid "Applied login asset"
msgstr "申请登录的资产"
#: tickets/handler/login_asset_confirm.py:18
#: tickets/handler/login_asset_confirm.py:19
msgid "Applied login system user"
msgstr "申请登录的系统用户"
#: tickets/handler/login_confirm.py:16
#: tickets/handler/login_confirm.py:17
msgid "Applied login IP"
msgstr "申请登录的IP"
#: tickets/handler/login_confirm.py:17
#: tickets/handler/login_confirm.py:18
msgid "Applied login city"
msgstr "申请登录的城市"
#: tickets/handler/login_confirm.py:18
#: tickets/handler/login_confirm.py:19
msgid "Applied login datetime"
msgstr "申请登录的日期"
@ -4741,7 +4743,8 @@ msgstr "请选择受理人"
msgid "The current organization type already exists"
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"
msgstr "点击查看"
@ -4901,30 +4904,38 @@ msgstr "管理员"
msgid "Administrator is the super user of system"
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/reset_password.html:5
#: users/templates/users/reset_password.html:6
msgid "Reset password"
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"
msgstr "重置密码成功"
#: users/notifications.py:78
#: users/notifications.py:110
msgid "Password is about expire"
msgstr "密码即将过期"
#: users/notifications.py:105
#: users/notifications.py:137
msgid "Account is about expire"
msgstr "账号即将过期"
#: users/notifications.py:127
#: users/notifications.py:161
msgid "Reset SSH Key"
msgstr "重置 SSH 密钥"
#: users/notifications.py:147
#: users/notifications.py:181
msgid "Reset MFA"
msgstr "重置 MFA"
@ -5073,28 +5084,34 @@ msgid "Click here update password"
msgstr "点击这里更新密码"
#: users/templates/users/_msg_password_expire_reminder.html:16
msgid "If your password has expired, please click"
msgstr "如果你的密码已过期,先点击"
#: users/templates/users/_msg_password_expire_reminder.html:18
msgid "to apply for a password reset email."
msgstr "申请重置"
msgid "If your password has expired, please click the link below to"
msgstr "如果你的密码已过期,请点击"
#: users/templates/users/_msg_reset_mfa.html:7
msgid "Your MFA has been reset by site administrator."
msgstr "你的 MFA 已经被管理员重置"
msgid "Your MFA has been reset by site administrator"
msgstr "你的 MFA 已经被管理员重置"
#: users/templates/users/_msg_reset_mfa.html:8
msgid "Please login and reset your MFA."
msgstr "请登录并重新设置你的 MFA"
#: users/templates/users/_msg_reset_ssh_key.html:8
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
msgid "Your ssh public key has been reset by site administrator."
msgstr "你的 SSH 密钥已经被管理员重置。"
msgid "Your ssh public key has been reset by site administrator"
msgstr "你的 SSH 密钥已经被管理员重置"
#: users/templates/users/_msg_reset_ssh_key.html:8
msgid "Please login and reset your ssh public key."
msgstr "请登录并重新设置你的密钥"
#: users/templates/users/_msg_user_created.html:8
msgid "Your account has been created successfully"
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
msgid "Please Select User"
@ -5279,56 +5296,6 @@ msgstr "账号保护已开启,请根据提示完成以下操作"
msgid "Open MFA Authenticator and enter the 6-bit dynamic code"
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:181
msgid "MFA code invalid, or ntp sync server time"
@ -5923,11 +5890,11 @@ msgstr "资产为空,请更改节点"
msgid "Executed times"
msgstr "执行次数"
#: xpack/plugins/interface/api.py:68
#: xpack/plugins/interface/api.py:43
msgid "It is already in the default setting state!"
msgstr "当前已经是初始化状态!"
#: xpack/plugins/interface/api.py:72
#: xpack/plugins/interface/api.py:46
msgid "Restore default successfully."
msgstr "恢复默认成功!"
@ -5935,23 +5902,23 @@ msgstr "恢复默认成功!"
msgid "Interface settings"
msgstr "界面设置"
#: xpack/plugins/interface/models.py:15
#: xpack/plugins/interface/models.py:16
msgid "Title of login page"
msgstr "登录页面标题"
#: xpack/plugins/interface/models.py:19
#: xpack/plugins/interface/models.py:20
msgid "Image of login page"
msgstr "登录页面图片"
#: xpack/plugins/interface/models.py:23
#: xpack/plugins/interface/models.py:24
msgid "Website icon"
msgstr "网站图标"
#: xpack/plugins/interface/models.py:27
#: xpack/plugins/interface/models.py:28
msgid "Logo of management page"
msgstr "管理页面logo"
#: xpack/plugins/interface/models.py:31
#: xpack/plugins/interface/models.py:32
msgid "Logo of logout page"
msgstr "退出页面logo"
@ -5983,6 +5950,69 @@ msgstr "旗舰版"
msgid "Community edition"
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"
#~ msgstr "登录IP"

45
apps/notifications/api/notifications.py

@ -12,7 +12,10 @@ from notifications.serializers import (
UserMsgSubscriptionSerializer,
)
__all__ = ('BackendListView', 'SystemMsgSubscriptionViewSet', 'UserMsgSubscriptionViewSet')
__all__ = (
'BackendListView', 'SystemMsgSubscriptionViewSet',
'UserMsgSubscriptionViewSet', 'get_all_test_messages'
)
class BackendListView(APIView):
@ -80,3 +83,43 @@ class UserMsgSubscriptionViewSet(ListModelMixin,
queryset = UserMsgSubscription.objects.all()
serializer_class = UserMsgSubscriptionSerializer
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)

71
apps/notifications/notifications.py

@ -2,22 +2,23 @@ import traceback
from html2text import HTML2Text
from typing import Iterable
from itertools import chain
import textwrap
from celery import shared_task
from django.utils.translation import gettext_lazy as _
from common.utils.timezone import local_now
from common.utils import lazyproperty
from settings.utils import get_login_title
from users.models import User
from notifications.backends import BACKEND
from .models import SystemMsgSubscription, UserMsgSubscription
__all__ = ('SystemMessage', 'UserMessage', 'system_msgs')
__all__ = ('SystemMessage', 'UserMessage', 'system_msgs', 'Message')
system_msgs = []
user_msgs = []
all_msgs = []
class MessageType(type):
@ -55,7 +56,6 @@ class Message(metaclass=MessageType):
- publish 该方法的实现与消息订阅的表结构有关
- send_msg
"""
message_type_label: str
category: str
category_label: str
@ -84,16 +84,13 @@ class Message(metaclass=MessageType):
backend = BACKEND(backend)
if not backend.is_enable:
continue
get_msg_method = getattr(self, f'get_{backend}_msg', self.get_common_msg)
try:
msg = get_msg_method()
except NotImplementedError:
continue
msg = get_msg_method()
client = backend.client()
client.send_msg(users, **msg)
except Exception:
except NotImplementedError:
continue
except:
traceback.print_exc()
@classmethod
@ -111,10 +108,7 @@ class Message(metaclass=MessageType):
@staticmethod
def get_common_msg() -> dict:
return {
'subject': '',
'message': ''
}
return {'subject': '', 'message': ''}
def get_html_msg(self) -> dict:
return self.get_common_msg()
@ -133,11 +127,39 @@ class Message(metaclass=MessageType):
@lazyproperty
def text_msg(self) -> dict:
return self.get_text_msg()
msg = self.get_text_msg()
return msg
@lazyproperty
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 标签
@ -159,16 +181,16 @@ class Message(metaclass=MessageType):
return self.text_msg
def get_email_msg(self) -> dict:
return self.html_msg
return self.html_msg_with_sign
def get_site_msg_msg(self) -> dict:
return self.html_msg
def get_sms_msg(self) -> dict:
return self.text_msg
return self.text_msg_with_sign
@classmethod
def test_all_messages(cls):
def get_all_sub_messages(cls):
def get_subclasses(cls):
"""returns all subclasses of argument, cls"""
if issubclass(cls, type):
@ -180,6 +202,12 @@ class Message(metaclass=MessageType):
return subclasses
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:
try:
msg = _cls.send_test_msg()
@ -225,6 +253,11 @@ class UserMessage(Message):
sub = UserMsgSubscription.objects.get(user=self.user)
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
def gen_test_msg(cls):
raise NotImplementedError

6
apps/notifications/urls/api_urls.py

@ -1,6 +1,7 @@
from rest_framework_bulk.routes import BulkRouter
from django.urls import path
from django.conf import settings
from notifications import api
@ -14,3 +15,8 @@ router.register('site-message', api.SiteMessageViewSet, 'site-message')
urlpatterns = [
path('backends/', api.BackendListView.as_view(), name='backends')
] + router.urls
if settings.DEBUG:
urlpatterns += [
path('debug-msgs/', api.get_all_test_messages, name='debug-all-msgs')
]

85
apps/ops/notifications.py

@ -1,4 +1,5 @@
from django.utils.translation import gettext_lazy as _
from django.template.loader import render_to_string
from notifications.notifications import SystemMessage
from notifications.models import SystemMsgSubscription
@ -14,14 +15,18 @@ class ServerPerformanceMessage(SystemMessage):
category_label = _('Operations')
message_type_label = _('Server performance')
def __init__(self, msg):
self._msg = msg
def __init__(self, terms_with_errors):
self.terms_with_errors = terms_with_errors
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 {
'subject': subject.replace('<br>', '; '),
'message': self._msg
'subject': subject,
'message': message
}
@classmethod
@ -33,17 +38,21 @@ class ServerPerformanceMessage(SystemMessage):
@classmethod
def gen_test_msg(cls):
alarm_messages = []
from terminal.models import Terminal
items_mapper = ServerPerformanceCheckUtil.items_mapper
for item, data in items_mapper.items():
msg = data['alarm_msg_format']
max_threshold = data['max_threshold']
value = 123
msg = msg.format(max_threshold=max_threshold, value=value, name='Fake terminal')
alarm_messages.append(msg)
terms_with_errors = []
terms = Terminal.objects.all()[:5]
msg = '<br>'.join(alarm_messages)
return cls(msg)
for i, term in enumerate(terms, 1):
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):
@ -56,59 +65,65 @@ class ServerPerformanceCheckUtil(object):
'disk_used': {
'default': 0,
'max_threshold': 80,
'alarm_msg_format': _(
'Disk used more than {max_threshold}%: => {value} ({name})'
)
'alarm_msg_format': _('Disk used more than {max_threshold}%: => {value}')
},
'memory_used': {
'default': 0,
'max_threshold': 85,
'alarm_msg_format': _(
'Memory used more than {max_threshold}%: => {value} ({name})'
),
'alarm_msg_format': _('Memory used more than {max_threshold}%: => {value}'),
},
'cpu_load': {
'default': 0,
'max_threshold': 5,
'alarm_msg_format': _(
'CPU load more than {max_threshold}: => {value} ({name})'
),
'alarm_msg_format': _('CPU load more than {max_threshold}: => {value}'),
},
}
def __init__(self):
self.alarm_messages = []
self.terms_with_errors = []
self._terminals = []
self._terminal = None
def check_and_publish(self):
self.check()
self.publish()
def check(self):
self.alarm_messages = []
self.terms_with_errors = []
self.initial_terminals()
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():
for self._terminal in self._terminals:
self.check_item(item, data)
error = self.check_item(term, item, data)
if not error:
continue
errors.append(error)
return errors
def check_item(self, item, data):
@staticmethod
def check_item(term, item, data):
default = data['default']
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:
return
elif isinstance(value, (int, float)) and value < max_threshold:
return
msg = data['alarm_msg_format']
msg = msg.format(max_threshold=max_threshold, value=value, name=self._terminal.name)
self.alarm_messages.append(msg)
error = msg.format(max_threshold=max_threshold, value=value, name=term.name)
return error
def publish(self):
if not self.alarm_messages:
if not self.terms_with_errors:
return
msg = '<br>'.join(self.alarm_messages)
ServerPerformanceMessage(msg).publish()
ServerPerformanceMessage(self.terms_with_errors).publish()
def initial_terminals(self):
terminals = []

10
apps/ops/templates/ops/_msg_terminal_performance.html

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

11
apps/perms/notifications.py

@ -1,4 +1,6 @@
from urllib.parse import urljoin
from django.conf import settings
from django.utils.translation import ugettext as _
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
class PermedWillExpireUserMsg(UserMessage):
class PermedAssetsWillExpireUserMsg(UserMessage):
def __init__(self, user, assets):
super().__init__(user)
self.assets = assets
@ -114,12 +116,9 @@ class AppPermsWillExpireForOrgAdminMsg(UserMessage):
def get_items_with_url(self):
items_with_url = []
perm_detail_url = urljoin(settings.SITE_URL, '/ui/#/perms/app-permissions/{}')
for perm in self.perms:
url = js_reverse(
'perms:application-permission-detail',
kwargs={'pk': perm.id}, external=True,
api_to_ui=True
) + f'?oid={perm.org_id}'
url = perm_detail_url.format(perm.id) + f'?oid={perm.org_id}'
items_with_url.append([perm.name, url])
return items_with_url

4
apps/perms/tasks.py

@ -12,7 +12,7 @@ from common.utils import get_logger
from common.utils.timezone import local_now, dt_formatter, dt_parser
from ops.celery.decorator import register_as_period_task
from perms.notifications import (
PermedWillExpireUserMsg, AssetPermsWillExpireForOrgAdminMsg,
PermedAssetsWillExpireUserMsg, AssetPermsWillExpireForOrgAdminMsg,
PermedAppsWillExpireUserMsg, AppPermsWillExpireForOrgAdminMsg
)
from perms.models import AssetPermission, ApplicationPermission
@ -83,7 +83,7 @@ def check_asset_permission_will_expired():
user_asset_mapper[u].update(assets)
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():
org_admins = org.admins.all()

5
apps/perms/templates/perms/_msg_permed_items_expire.html

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

29
apps/settings/api/public.py

@ -1,12 +1,11 @@
from rest_framework import generics
from rest_framework.permissions import AllowAny
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 common.utils import get_logger
from .. import serializers
from ..utils import get_interface_setting
logger = get_logger(__name__)
@ -19,30 +18,14 @@ class PublicSettingApi(generics.RetrieveAPIView):
@staticmethod
def get_logo_urls():
logo_urls = {
'logo_logout': static('img/logo.png'),
'logo_index': static('img/logo_text.png'),
'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
interface = get_interface_setting()
keys = ['logo_logout', 'logo_index', 'login_image', 'favicon']
return {k: interface[k] for k in keys}
@staticmethod
def get_login_title():
default_title = _('Welcome to the JumpServer open source Bastion Host')
if not settings.XPACK_ENABLED:
return default_title
from xpack.plugins.interface.models import Interface
return Interface.get_login_title()
interface = get_interface_setting()
return interface['login_title']
def get_object(self):
instance = {

13
apps/settings/utils/common.py

@ -1,4 +1,6 @@
# coding: utf-8
from jumpserver.context_processor import default_interface
from django.conf import settings
class ObjectDict(dict):
@ -16,3 +18,14 @@ class ObjectDict(dict):
del self[name]
else:
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']

7
apps/terminal/models/terminal.py

@ -134,11 +134,8 @@ class Terminal(StorageMixin, TerminalStatusMixin, models.Model):
@staticmethod
def get_login_title_setting():
login_title = None
if settings.XPACK_ENABLED:
from xpack.plugins.interface.models import Interface
login_title = Interface.get_login_title()
return {'TERMINAL_HEADER_TITLE': login_title}
from settings.utils import get_login_title
return {'TERMINAL_HEADER_TITLE': get_login_title()}
@property
def config(self):

45
apps/terminal/notifications.py

@ -13,6 +13,8 @@ from notifications.models import SystemMsgSubscription
from notifications.backends import BACKEND
from orgs.utils import tmp_to_root_org
from common.utils import lazyproperty
from common.utils.timezone import local_now_display
logger = get_logger(__name__)
@ -73,25 +75,26 @@ class CommandAlertMessage(CommandAlertMixin, SystemMessage):
@classmethod
def gen_test_msg(cls):
command = Command.objects.first().to_dict()
command['session'] = Session.objects.first().id
return cls(command)
def get_html_msg(self) -> dict:
command = self.command
with tmp_to_root_org():
session = Session.objects.get(id=command['session'])
session_detail_url = reverse(
'api-terminal:session-detail', kwargs={'pk': command['session']},
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 = {
'command': command['input'],
'hostname': command['asset'],
'host_ip': session.asset_obj.ip,
'user': command['user'],
'risk_level': Command.get_risk_level_str(command['risk_level']),
'session_detail_url': session_detail_url,
'oid': session.org_id
'items': items,
'session_url': session_detail_url,
"command": command['input'],
}
message = render_to_string('terminal/_msg_command_alert.html', context)
return {
@ -122,19 +125,25 @@ class CommandExecutionAlert(CommandAlertMixin, SystemMessage):
def get_html_msg(self) -> dict:
command = self.command
_input = command['input']
_input = _input.replace('\n', '<br>')
assets_with_url = []
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])
level = Command.get_risk_level_str(command['risk_level'])
items = {
_("User"): command['user'],
_("Level"): level,
_("Date"): local_now_display(),
}
context = {
'command': _input,
'items': items,
'assets_with_url': assets_with_url,
'user': command['user'],
'risk_level': Command.get_risk_level_str(command['risk_level'])
'command': command['input'],
}
message = render_to_string('terminal/_msg_command_execute_alert.html', context)
return {

29
apps/terminal/templates/terminal/_msg_command_alert.html

@ -1,17 +1,16 @@
{% load i18n %}
<p>
<b>{% trans 'Command' %}:</b> {{ command }}
</p>
<p>
<b>{% trans 'Asset' %}:</b> {{ hostname }}({{ host_ip }})
</p>
<p>
<b>{% trans 'User' %}:</b> {{ user }}
</p>
<p>
<b>{% trans 'Level' %}:</b> {{ risk_level }}
</p>
<p>
<b>{% trans 'Session' %}:</b> <a href="{{ session_detail_url}}?oid={{ oid }}">{% trans 'view' %}</a>
</p>
<div>
{% for item, value in items.items %}
<span class="cmd-item">
<b>{{ item }}:</b> {{ value }}
</span>
<br />
{% endfor %}
<b>{% trans 'Session' %}:</b> <a href="{{ session_url }}">{% trans 'view' %}</a>
<br />
<b>{% trans 'Command' %}: </b><br />
<pre>
{{ command }}
</pre>
</div>

18
apps/terminal/templates/terminal/_msg_command_execute_alert.html

@ -1,16 +1,16 @@
{% load i18n %}
<p>
<b>{% trans 'User' %}:</b> {{ user }}
</p>
<p>
<b>{% trans 'Level' %}:</b> {{ risk_level }}
</p>
<div>
<b>{% trans 'Command' %}: </b><br>
<pre>
{% for item, value in items.items %}
<span class="cmd-item">
<b>{{ item }}:</b> {{ value }}
</span>
<br />
{% endfor %}
<b>{% trans 'Command' %}: </b><br />
<pre>
{{ command }}
</pre>
</pre>
</div>
<div>
<b>{% trans 'Assets' %}:</b><br>

1
apps/tickets/notifications.py

@ -19,6 +19,7 @@ class BaseTicketMessage(UserMessage):
@property
def ticket_detail_url(self):
tp = self.ticket.type
return urljoin(settings.SITE_URL, const.TICKET_DETAIL_URL.format(id=str(self.ticket.id)))
@property

43
apps/users/notifications.py

@ -1,4 +1,3 @@
from datetime import datetime
from urllib.parse import urljoin
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
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):
def __init__(self, user):
super().__init__(user)
@ -71,18 +102,17 @@ class ResetPasswordSuccessMsg(UserMessage):
class PasswordExpirationReminderMsg(UserMessage):
update_password_url = urljoin(settings.SITE_URL, '/ui/#/users/profile/?activeTab=PasswordUpdate')
def get_html_msg(self) -> dict:
user = self.user
subject = _('Password is about expire')
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')
context = {
'name': user.name,
'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),
'email': user.email,
'login_url': reverse('authentication:login', external=True),
@ -125,9 +155,10 @@ class UserExpirationReminderMsg(UserMessage):
class ResetSSHKeyMsg(UserMessage):
def get_html_msg(self) -> dict:
subject = _('Reset SSH Key')
update_url = urljoin(settings.SITE_URL, '/ui/#/users/profile/?activeTab=SSHUpdate')
context = {
'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)
return {
@ -147,7 +178,7 @@ class ResetMFAMsg(UserMessage):
subject = _('Reset MFA')
context = {
'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)
return {

6
apps/users/templates/users/_msg_password_expire_reminder.html

@ -13,10 +13,6 @@
</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>
{% trans 'to apply for a password reset email.' %}
</p>
---
<br>
<a href="{{ login_url }}">{% trans 'Login direct' %}</a>

10
apps/users/templates/users/_msg_reset_mfa.html

@ -4,9 +4,9 @@
{% trans 'Hello' %} {{ name }},
</p>
<p>
{% trans 'Your MFA has been reset by site administrator.' %} <br />
{% trans 'Please login and reset your MFA.' %}
{% trans 'Your MFA has been reset by site administrator' %} <br />
{% trans 'Please click the link below to set' %}
<br>
<br>
<a href="{{ url }}" class='showLink'>{% trans 'Click here set' %}</a>
</p>
<p>
<a href="{{ login_url }}">{% trans 'Login direct' %}</a>
</p>

10
apps/users/templates/users/_msg_reset_ssh_key.html

@ -4,9 +4,9 @@
{% trans 'Hello' %} {{ name }},
</p>
<p>
{% trans 'Your ssh public key has been reset by site administrator.' %} <br />
{% trans 'Please login and reset your ssh public key.' %}
{% trans 'Your ssh public key has been reset by site administrator' %} <br />
{% trans 'Please click the link below to set' %}
<br>
<br>
<a href="{{ url }}" class='showLink'>{% trans 'Click here set' %}</a>
</p>
<p>
<a href="{{ login_url }}">{% trans 'Login direct' %}</a>
</p>

20
apps/users/templates/users/_msg_user_created.html

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

55
apps/users/utils.py

@ -8,67 +8,24 @@ import logging
import time
from django.conf import settings
from django.utils.translation import ugettext as _
from django.core.cache import cache
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
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):
recipient_list = [user.email]
subject = _('Create account successfully')
if settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT:
subject = settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT
from .notifications import UserCreatedMsg
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>'
recipient_list = [user.email]
msg = UserCreatedMsg.html_msg
subject = msg['subject']
message = msg['message']
message = honorific + body + signature
if settings.DEBUG:
try:
print(message)

Loading…
Cancel
Save