From e4178849ba08982506e8988ca6696756a2bf1b5f Mon Sep 17 00:00:00 2001 From: feng626 <1304903146@qq.com> Date: Wed, 15 Dec 2021 14:23:07 +0800 Subject: [PATCH 1/8] perf: ticket filter --- apps/tickets/filters.py | 2 +- apps/tickets/handler/base.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/tickets/filters.py b/apps/tickets/filters.py index 676efbea2..3c795f0df 100644 --- a/apps/tickets/filters.py +++ b/apps/tickets/filters.py @@ -10,7 +10,7 @@ class TicketFilter(BaseFilterSet): class Meta: model = Ticket fields = ( - 'id', 'title', 'type', 'status', 'applicant', 'assignees__id', + 'id', 'title', 'type', 'status', 'state', 'applicant', 'assignees__id', 'applicant_display', ) diff --git a/apps/tickets/handler/base.py b/apps/tickets/handler/base.py index 5e13b7a60..4b09531fa 100644 --- a/apps/tickets/handler/base.py +++ b/apps/tickets/handler/base.py @@ -29,9 +29,9 @@ class BaseHandler(object): self._send_applied_mail_to_assignees() is_finished = False else: - self._send_processed_mail_to_applicant(self.ticket.processor) self.ticket.set_state_approve() self.ticket.set_status_closed() + self._send_processed_mail_to_applicant(self.ticket.processor) is_finished = True self.ticket.save() From ac1479096099f9212701047c8f84f3c3994fad40 Mon Sep 17 00:00:00 2001 From: Michael Bai Date: Wed, 15 Dec 2021 14:43:03 +0800 Subject: [PATCH 2/8] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=BF=87=E6=BB=A4=E8=A7=84=E5=88=99=E5=8A=A8=E4=BD=9C=E5=85=81?= =?UTF-8?q?=E8=AE=B8=E5=80=BC1->9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0083_auto_20211215_1436.py | 27 +++++++++++++++++++ apps/assets/models/cmd_filter.py | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 apps/assets/migrations/0083_auto_20211215_1436.py diff --git a/apps/assets/migrations/0083_auto_20211215_1436.py b/apps/assets/migrations/0083_auto_20211215_1436.py new file mode 100644 index 000000000..f3bde1ec9 --- /dev/null +++ b/apps/assets/migrations/0083_auto_20211215_1436.py @@ -0,0 +1,27 @@ +# Generated by Django 3.1.13 on 2021-12-15 06:36 + +from django.db import migrations, models + +OLD_ACTION_ALLOW = 1 +NEW_ACTION_ALLOW = 9 + + +def migrate_action(apps, schema_editor): + model = apps.get_model("assets", "CommandFilterRule") + model.objects.filter(action=OLD_ACTION_ALLOW).update(action=NEW_ACTION_ALLOW) + + +class Migration(migrations.Migration): + + dependencies = [ + ('assets', '0082_auto_20211209_1440'), + ] + + operations = [ + migrations.RunPython(migrate_action), + migrations.AlterField( + model_name='commandfilterrule', + name='action', + field=models.IntegerField(choices=[(0, 'Deny'), (9, 'Allow'), (2, 'Reconfirm')], default=0, verbose_name='Action'), + ), + ] diff --git a/apps/assets/models/cmd_filter.py b/apps/assets/models/cmd_filter.py index bff1002f8..9de4859b5 100644 --- a/apps/assets/models/cmd_filter.py +++ b/apps/assets/models/cmd_filter.py @@ -68,7 +68,7 @@ class CommandFilterRule(OrgModelMixin): class ActionChoices(models.IntegerChoices): deny = 0, _('Deny') - allow = 1, _('Allow') + allow = 9, _('Allow') confirm = 2, _('Reconfirm') id = models.UUIDField(default=uuid.uuid4, primary_key=True) From 022e93d7a246dd5421b205637521b3ab0bfa7e77 Mon Sep 17 00:00:00 2001 From: feng626 <1304903146@qq.com> Date: Wed, 15 Dec 2021 16:15:21 +0800 Subject: [PATCH 3/8] feat: translate --- apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 94 +++++++++++++++------------- 2 files changed, 51 insertions(+), 47 deletions(-) diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index e9a002a25..3b62528ee 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a8f5840c041b5f3188621ec731fa1b4a5da20730ea6394cf5e2b5c9c241a00e -size 94712 +oid sha256:2bf3340b7ca0dc3e698160fe8df980df07ebdecfd9312c5aca230d18a05fea18 +size 94929 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 7a2257f19..fcc84607b 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/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-12-14 17:54+0800\n" +"POT-Creation-Date: 2021-12-15 15:41+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -35,12 +35,12 @@ msgid "Name" msgstr "名称" #: acls/models/base.py:27 assets/models/cmd_filter.py:77 -#: assets/models/user.py:200 +#: assets/models/user.py:209 msgid "Priority" msgstr "优先级" #: acls/models/base.py:28 assets/models/cmd_filter.py:77 -#: assets/models/user.py:200 +#: assets/models/user.py:209 msgid "1-100, the lower the value will be match first" msgstr "优先级可选范围为 1-100 (数值越小越优先)" @@ -209,7 +209,7 @@ msgid "" msgstr "格式为逗号分隔的字符串, * 表示匹配所有. 可选的协议有: {}" #: acls/serializers/login_asset_acl.py:55 assets/models/asset.py:214 -#: assets/models/domain.py:63 assets/models/user.py:201 +#: assets/models/domain.py:63 assets/models/user.py:210 #: terminal/serializers/session.py:30 terminal/serializers/storage.py:69 msgid "Protocol" msgstr "协议" @@ -265,7 +265,7 @@ msgid "Custom" msgstr "自定义" #: applications/models/account.py:11 assets/models/authbook.py:19 -#: assets/models/cmd_filter.py:38 assets/models/user.py:291 audits/models.py:39 +#: assets/models/cmd_filter.py:38 assets/models/user.py:300 audits/models.py:39 #: perms/models/application_permission.py:32 #: perms/models/asset_permission.py:101 templates/_nav.html:45 #: terminal/backends/command/models.py:20 @@ -306,7 +306,7 @@ msgstr "类别" #: applications/models/application.py:171 #: applications/serializers/application.py:90 assets/models/cmd_filter.py:76 -#: assets/models/user.py:199 perms/models/application_permission.py:23 +#: assets/models/user.py:208 perms/models/application_permission.py:23 #: perms/serializers/application/user_permission.py:34 #: terminal/models/storage.py:55 terminal/models/storage.py:116 #: tickets/models/flow.py:51 tickets/models/ticket.py:48 @@ -523,7 +523,7 @@ msgstr "主机名原始" msgid "Protocols" msgstr "协议组" -#: assets/models/asset.py:219 assets/models/user.py:191 +#: assets/models/asset.py:219 assets/models/user.py:200 #: perms/models/asset_permission.py:100 #: xpack/plugins/change_auth_plan/models/asset.py:44 #: xpack/plugins/gathered_user/models.py:24 @@ -536,7 +536,7 @@ msgid "Is active" msgstr "激活" #: assets/models/asset.py:223 assets/models/cluster.py:19 -#: assets/models/user.py:188 assets/models/user.py:340 templates/_nav.html:44 +#: assets/models/user.py:197 assets/models/user.py:349 templates/_nav.html:44 msgid "Admin user" msgstr "特权用户" @@ -790,75 +790,75 @@ msgstr "ssh私钥" msgid "Node" msgstr "节点" -#: assets/models/user.py:182 +#: assets/models/user.py:191 msgid "Automatic managed" msgstr "托管密码" -#: assets/models/user.py:183 +#: assets/models/user.py:192 msgid "Manually input" msgstr "手动输入" -#: assets/models/user.py:187 +#: assets/models/user.py:196 msgid "Common user" msgstr "普通用户" -#: assets/models/user.py:190 +#: assets/models/user.py:199 msgid "Username same with user" msgstr "用户名与用户相同" -#: assets/models/user.py:193 assets/serializers/domain.py:29 +#: assets/models/user.py:202 assets/serializers/domain.py:29 #: templates/_nav.html:39 #: terminal/templates/terminal/_msg_command_execute_alert.html:16 #: xpack/plugins/change_auth_plan/models/asset.py:40 msgid "Assets" msgstr "资产" -#: assets/models/user.py:197 templates/_nav.html:17 +#: assets/models/user.py:206 templates/_nav.html:17 #: users/views/profile/pubkey.py:37 msgid "Users" msgstr "用户管理" -#: assets/models/user.py:198 +#: assets/models/user.py:207 msgid "User groups" msgstr "用户组" -#: assets/models/user.py:202 +#: assets/models/user.py:211 msgid "Auto push" msgstr "自动推送" -#: assets/models/user.py:203 +#: assets/models/user.py:212 msgid "Sudo" msgstr "Sudo" -#: assets/models/user.py:204 +#: assets/models/user.py:213 msgid "Shell" msgstr "Shell" -#: assets/models/user.py:205 +#: assets/models/user.py:214 msgid "Login mode" msgstr "认证方式" -#: assets/models/user.py:206 +#: assets/models/user.py:215 msgid "SFTP Root" msgstr "SFTP根路径" -#: assets/models/user.py:207 authentication/models.py:45 +#: assets/models/user.py:216 authentication/models.py:45 msgid "Token" msgstr "" -#: assets/models/user.py:208 +#: assets/models/user.py:217 msgid "Home" msgstr "家目录" -#: assets/models/user.py:209 +#: assets/models/user.py:218 msgid "System groups" msgstr "用户组" -#: assets/models/user.py:212 +#: assets/models/user.py:221 msgid "User switch" msgstr "用户切换" -#: assets/models/user.py:213 +#: assets/models/user.py:222 msgid "Switch from" msgstr "切换自" @@ -1068,24 +1068,24 @@ msgid "" "The task of self-checking is already running and cannot be started repeatedly" msgstr "自检程序已经在运行,不能重复启动" -#: assets/tasks/push_system_user.py:194 +#: assets/tasks/push_system_user.py:199 msgid "System user is dynamic: {}" msgstr "系统用户是动态的: {}" -#: assets/tasks/push_system_user.py:234 +#: assets/tasks/push_system_user.py:239 msgid "Start push system user for platform: [{}]" msgstr "推送系统用户到平台: [{}]" -#: assets/tasks/push_system_user.py:235 +#: assets/tasks/push_system_user.py:240 #: assets/tasks/system_user_connectivity.py:106 msgid "Hosts count: {}" msgstr "主机数量: {}" -#: assets/tasks/push_system_user.py:277 assets/tasks/push_system_user.py:310 +#: assets/tasks/push_system_user.py:282 assets/tasks/push_system_user.py:315 msgid "Push system users to assets: {}" msgstr "推送系统用户到入资产: {}" -#: assets/tasks/push_system_user.py:289 +#: assets/tasks/push_system_user.py:294 msgid "Push system users to asset: {}({}) => {}" msgstr "推送系统用户到入资产: {}({}) => {}" @@ -2785,23 +2785,23 @@ msgstr "测试成功" msgid "Test mail sent to {}, please check" msgstr "邮件已经发送{}, 请检查" -#: settings/api/ldap.py:152 +#: settings/api/ldap.py:157 msgid "Synchronization start, please wait." msgstr "同步开始,请稍等" -#: settings/api/ldap.py:156 +#: settings/api/ldap.py:161 msgid "Synchronization is running, please wait." msgstr "同步正在运行,请稍等" -#: settings/api/ldap.py:161 +#: settings/api/ldap.py:166 msgid "Synchronization error: {}" msgstr "同步错误: {}" -#: settings/api/ldap.py:194 +#: settings/api/ldap.py:199 msgid "Get ldap users is None" msgstr "获取 LDAP 用户为 None" -#: settings/api/ldap.py:203 +#: settings/api/ldap.py:208 msgid "Imported {} users successfully (Organization: {})" msgstr "成功导入 {} 个用户 ( 组织: {} )" @@ -5516,31 +5516,31 @@ msgstr "账号保护已开启,请根据提示完成以下操作" msgid "Open MFA Authenticator and enter the 6-bit dynamic code" msgstr "请打开 MFA 验证器,输入 6 位动态码" -#: users/views/profile/otp.py:86 +#: users/views/profile/otp.py:87 msgid "Already bound" msgstr "已经绑定" -#: users/views/profile/otp.py:87 +#: users/views/profile/otp.py:88 msgid "MFA already bound, disable first, then bound" msgstr "MFA(OTP) 已经绑定,请先禁用,再绑定" -#: users/views/profile/otp.py:114 +#: users/views/profile/otp.py:115 msgid "OTP enable success" msgstr "MFA(OTP) 启用成功" -#: users/views/profile/otp.py:115 +#: users/views/profile/otp.py:116 msgid "OTP enable success, return login page" msgstr "MFA(OTP) 启用成功,返回到登录页面" -#: users/views/profile/otp.py:157 +#: users/views/profile/otp.py:158 msgid "Disable OTP" msgstr "禁用虚拟 MFA(OTP)" -#: users/views/profile/otp.py:163 +#: users/views/profile/otp.py:164 msgid "OTP disable success" msgstr "MFA(OTP) 禁用成功" -#: users/views/profile/otp.py:164 +#: users/views/profile/otp.py:165 msgid "OTP disable success, return login page" msgstr "MFA(OTP) 禁用成功,返回登录页面" @@ -5752,15 +5752,19 @@ msgstr "* 请输入正确的密码长度" msgid "* Password length range 6-30 bits" msgstr "* 密码长度范围 6-30 位" -#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:249 +#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:236 +msgid "After many attempts to change the secret, it still failed" +msgstr "多次尝试改密后, 依然失败" + +#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:255 msgid "Invalid/incorrect password" msgstr "无效/错误 密码" -#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:251 +#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:257 msgid "Failed to connect to the host" msgstr "连接主机失败" -#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:253 +#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:259 msgid "Data could not be sent to remote" msgstr "无法将数据发送到远程" From ae1d419f707244201e6ccbcb6611c5fdaa35315d Mon Sep 17 00:00:00 2001 From: Michael Bai Date: Wed, 15 Dec 2021 16:33:06 +0800 Subject: [PATCH 4/8] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=BB=84=E5=91=BD=E4=BB=A4=E8=BF=87=E6=BB=A4=E8=A7=84=E5=88=99?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E4=B8=8D=E5=88=B0=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/system_user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/assets/api/system_user.py b/apps/assets/api/system_user.py index 912630b79..cf61be658 100644 --- a/apps/assets/api/system_user.py +++ b/apps/assets/api/system_user.py @@ -217,7 +217,7 @@ class SystemUserCommandFilterRuleListApi(generics.ListAPIView): q = Q() if user: q |= Q(users=user) - if user_group: + if user_groups: q |= Q(user_groups__in=set(user_groups)) if system_user: q |= Q(system_users=system_user) From 93d77b23128ef6183e11ff27e4e3ded519ba2415 Mon Sep 17 00:00:00 2001 From: xinwen Date: Wed, 15 Dec 2021 17:58:14 +0800 Subject: [PATCH 5/8] =?UTF-8?q?fix:=20=E6=89=A7=E8=A1=8C=20ansible=20?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=97=A5=E5=BF=97=E8=AE=B0=E5=BD=95=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ops/ansible/display.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/ops/ansible/display.py b/apps/ops/ansible/display.py index 0c4d57788..ab93892b2 100644 --- a/apps/ops/ansible/display.py +++ b/apps/ops/ansible/display.py @@ -54,6 +54,9 @@ class AdHocDisplay(Display, metaclass=UnSingleton): self.log_file.write(msg) def display(self, msg, color=None, stderr=False, screen_only=False, log_only=False, newline=True): + if log_only: + return + if color: msg = stringc(msg, color) @@ -62,7 +65,5 @@ class AdHocDisplay(Display, metaclass=UnSingleton): else: msg2 = msg - if log_only: - self._write_to_log_file(msg2) - else: - self._write_to_screen(msg2, stderr) + self._write_to_log_file(msg2) + self._write_to_screen(msg2, stderr) From eb3165f8e75decab42b6362502e46941d2107d23 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 15 Dec 2021 19:53:30 +0800 Subject: [PATCH 6/8] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20saml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/backends/saml2/views.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/authentication/backends/saml2/views.py b/apps/authentication/backends/saml2/views.py index f1affb8af..4ce812fe8 100644 --- a/apps/authentication/backends/saml2/views.py +++ b/apps/authentication/backends/saml2/views.py @@ -270,7 +270,7 @@ class Saml2AuthCallbackView(View, PrepareRequestMixin): class Saml2AuthMetadataView(View, PrepareRequestMixin): - def get(self, _): + def get(self, request): saml_settings = self.get_sp_settings() saml_settings = JmsSaml2Settings( settings=saml_settings, sp_validation_only=True, @@ -279,8 +279,17 @@ class Saml2AuthMetadataView(View, PrepareRequestMixin): metadata = saml_settings.get_sp_metadata() errors = saml_settings.validate_metadata(metadata) + key = saml_settings.get_sp_key() + cert = saml_settings.get_sp_cert() + if not key: + errors.append('Not found SP private key') + if not cert: + errors.append('Not found SP cert') + if len(errors) == 0: resp = HttpResponse(content=metadata, content_type='text/xml') else: - resp = HttpResponseServerError(content=', '.join(errors)) + content = "Error occur:
" + content += '
'.join(errors) + resp = HttpResponseServerError(content=content) return resp From b113eeb1d695e81d868b3106d26303573ba31014 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 15 Dec 2021 18:44:51 +0800 Subject: [PATCH 7/8] =?UTF-8?q?perf:=20=E4=BF=AE=E5=A4=8D=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E8=AE=BE=E7=BD=AE=E4=B8=AD=E7=9A=84=20base=5Fsite=20?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E5=B8=A6=20/=20=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/settings/serializers/basic.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/settings/serializers/basic.py b/apps/settings/serializers/basic.py index 4f38e2fd5..97ef96cbe 100644 --- a/apps/settings/serializers/basic.py +++ b/apps/settings/serializers/basic.py @@ -44,3 +44,10 @@ class BasicSettingSerializer(serializers.Serializer): TICKETS_ENABLED = serializers.BooleanField(required=False, default=True, label=_("Enable tickets")) ANNOUNCEMENT_ENABLED = serializers.BooleanField(label=_('Enable announcement'), default=True) ANNOUNCEMENT = AnnouncementSerializer(label=_("Announcement")) + + @staticmethod + def validate_SITE_URL(s): + if not s: + return 'http://127.0.0.1' + return s.strip('/') + From b92530f0b943141735753b124de38647fb86937c Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 15 Dec 2021 15:01:46 +0800 Subject: [PATCH 8/8] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=80=9A?= =?UTF-8?q?=E7=9F=A5=EF=BC=8C=E5=AF=B9=E6=94=AF=E6=8C=81=20markdown=20?= =?UTF-8?q?=E7=9A=84=E5=8F=91=20markdown?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authentication/_msg_different_city.html | 1 + .../authentication/_msg_reset_password.html | 5 ++-- .../_msg_rest_password_success.html | 1 + .../_msg_rest_public_key_success.html | 1 + apps/common/sdk/im/dingtalk/__init__.py | 21 +++++++++++++-- apps/common/sdk/im/wecom/__init__.py | 12 ++++++++- apps/notifications/backends/dingtalk.py | 2 +- apps/notifications/backends/wecom.py | 2 +- apps/notifications/notifications.py | 27 ++++++++++++++----- .../perms/_msg_permed_items_expire.html | 1 + .../users/_msg_password_expire_reminder.html | 2 +- .../templates/users/_msg_user_created.html | 3 +++ 12 files changed, 63 insertions(+), 15 deletions(-) diff --git a/apps/authentication/templates/authentication/_msg_different_city.html b/apps/authentication/templates/authentication/_msg_different_city.html index b12e9aab6..02dbf4271 100644 --- a/apps/authentication/templates/authentication/_msg_different_city.html +++ b/apps/authentication/templates/authentication/_msg_different_city.html @@ -11,6 +11,7 @@ {% trans 'Login city' %}: {{ city }}({{ ip }})

+-

{% trans 'If you suspect that the login behavior is abnormal, please modify the account password in time.' %}

\ No newline at end of file diff --git a/apps/authentication/templates/authentication/_msg_reset_password.html b/apps/authentication/templates/authentication/_msg_reset_password.html index 7bb80a17d..f53bda209 100644 --- a/apps/authentication/templates/authentication/_msg_reset_password.html +++ b/apps/authentication/templates/authentication/_msg_reset_password.html @@ -11,9 +11,8 @@

+-

{% trans 'This link is valid for 1 hour. After it expires' %} - - {% trans 'request new one' %} - + {% trans 'request new one' %}

diff --git a/apps/authentication/templates/authentication/_msg_rest_password_success.html b/apps/authentication/templates/authentication/_msg_rest_password_success.html index a12d611f7..dce3ee13c 100644 --- a/apps/authentication/templates/authentication/_msg_rest_password_success.html +++ b/apps/authentication/templates/authentication/_msg_rest_password_success.html @@ -8,6 +8,7 @@ {% trans 'IP' %}: {{ ip_address }}
{% trans 'Browser' %}: {{ browser }}

+-

{% trans 'If the password update was not initiated by you, your account may have security issues' %}
{% trans 'If you have any questions, you can contact the administrator' %} diff --git a/apps/authentication/templates/authentication/_msg_rest_public_key_success.html b/apps/authentication/templates/authentication/_msg_rest_public_key_success.html index a95bfdd9b..c8e8fabb6 100644 --- a/apps/authentication/templates/authentication/_msg_rest_public_key_success.html +++ b/apps/authentication/templates/authentication/_msg_rest_public_key_success.html @@ -8,6 +8,7 @@ {% trans 'IP' %}: {{ ip_address }}
{% trans 'Browser' %}: {{ browser }}

+-

{% trans 'If the public key update was not initiated by you, your account may have security issues' %}
{% trans 'If you have any questions, you can contact the administrator' %} diff --git a/apps/common/sdk/im/dingtalk/__init__.py b/apps/common/sdk/im/dingtalk/__init__.py index af57f2cf5..f18cd4b35 100644 --- a/apps/common/sdk/im/dingtalk/__init__.py +++ b/apps/common/sdk/im/dingtalk/__init__.py @@ -151,12 +151,29 @@ class DingTalk: 'data': data } data = self._request.post(URL.SEND_MESSAGE_BY_TEMPLATE, json=body, with_token=True) + return data + + def send_markdown(self, user_ids, title, msg): + body = { + 'agent_id': self._agentid, + 'userid_list': ','.join(user_ids), + 'to_all_user': False, + 'msg': { + 'msgtype': 'markdown', + 'markdown': { + 'title': title, + 'text': msg + } + } + } + logger.info(f'Dingtalk send markdown to user {user_ids}: {msg}') + data = self._request.post(URL.SEND_MESSAGE, json=body, with_token=True) + return data def send_text(self, user_ids, msg): body = { 'agent_id': self._agentid, 'userid_list': ','.join(user_ids), - # 'dept_id_list': '', 'to_all_user': False, 'msg': { 'msgtype': 'text', @@ -165,7 +182,7 @@ class DingTalk: } } } - logger.info(f'Dingtalk send text: user_ids={user_ids} msg={msg}') + logger.info(f'Dingtalk send msg to user {user_ids}: {msg}') data = self._request.post(URL.SEND_MESSAGE, json=body, with_token=True) return data diff --git a/apps/common/sdk/im/wecom/__init__.py b/apps/common/sdk/im/wecom/__init__.py index 6d7c2bf66..ceda292c7 100644 --- a/apps/common/sdk/im/wecom/__init__.py +++ b/apps/common/sdk/im/wecom/__init__.py @@ -90,7 +90,10 @@ class WeCom(RequestMixin): timeout=timeout ) - def send_text(self, users: Iterable, msg: AnyStr, **kwargs): + def send_markdown(self, users: Iterable, msg: AnyStr, **kwargs): + pass + + def send_text(self, users: Iterable, msg: AnyStr, markdown=False, **kwargs): """ https://open.work.weixin.qq.com/api/doc/90000/90135/90236 @@ -115,6 +118,13 @@ class WeCom(RequestMixin): }, **extra_params } + if markdown: + body['msgtype'] = 'markdown' + body["markdown"] = { + "content": msg + } + body.pop('text', '') + logger.info(f'Wecom send text: users={users} msg={msg}') data = self._requests.post(URL.SEND_MESSAGE, json=body, check_errcode_is_0=False) diff --git a/apps/notifications/backends/dingtalk.py b/apps/notifications/backends/dingtalk.py index 426a05fc0..52d11d041 100644 --- a/apps/notifications/backends/dingtalk.py +++ b/apps/notifications/backends/dingtalk.py @@ -16,7 +16,7 @@ class DingTalk(BackendBase): def send_msg(self, users, message, subject=None): accounts, __, __ = self.get_accounts(users) - return self.dingtalk.send_text(accounts, message) + return self.dingtalk.send_markdown(accounts, subject, message) backend = DingTalk diff --git a/apps/notifications/backends/wecom.py b/apps/notifications/backends/wecom.py index c2aadd4a9..fa615b7e7 100644 --- a/apps/notifications/backends/wecom.py +++ b/apps/notifications/backends/wecom.py @@ -17,7 +17,7 @@ class WeCom(BackendBase): def send_msg(self, users, message, subject=None): accounts, __, __ = self.get_accounts(users) - return self.wecom.send_text(accounts, message) + return self.wecom.send_text(accounts, message, markdown=True) backend = WeCom diff --git a/apps/notifications/notifications.py b/apps/notifications/notifications.py index 11e8f7011..481a4bc08 100644 --- a/apps/notifications/notifications.py +++ b/apps/notifications/notifications.py @@ -94,7 +94,7 @@ class Message(metaclass=MessageType): traceback.print_exc() @classmethod - def send_test_msg(cls, ding=True): + def send_test_msg(cls, ding=True, wecom=False): msg = cls.gen_test_msg() if not msg: return @@ -104,6 +104,8 @@ class Message(metaclass=MessageType): backends = [] if ding: backends.append(BACKEND.DINGTALK) + if wecom: + backends.append(BACKEND.WECOM) msg.send_msg(users, backends) @staticmethod @@ -113,8 +115,17 @@ class Message(metaclass=MessageType): def get_html_msg(self) -> dict: return self.get_common_msg() + def get_markdown_msg(self) -> dict: + h = HTML2Text() + h.body_width = 300 + msg = self.get_html_msg() + content = msg['message'] + msg['message'] = h.handle(content) + return msg + def get_text_msg(self) -> dict: h = HTML2Text() + h.body_width = 90 msg = self.get_html_msg() content = msg['message'] h.ignore_links = self.text_msg_ignore_links @@ -130,6 +141,10 @@ class Message(metaclass=MessageType): msg = self.get_text_msg() return msg + @lazyproperty + def markdown_msg(self): + return self.get_markdown_msg() + @lazyproperty def html_msg(self) -> dict: msg = self.get_html_msg() @@ -167,17 +182,17 @@ class Message(metaclass=MessageType): # 支持不同发送消息的方式定义自己的消息内容,比如有些支持 html 标签 def get_dingtalk_msg(self) -> dict: # 钉钉相同的消息一天只能发一次,所以给所有消息添加基于时间的序号,使他们不相同 - message = self.text_msg['message'] + message = self.markdown_msg['message'] time = local_now().strftime('%Y-%m-%d %H:%M:%S') suffix = '\n{}: {}'.format(_('Time'), time) return { - 'subject': self.text_msg['subject'], + 'subject': self.markdown_msg['subject'], 'message': message + suffix } def get_wecom_msg(self) -> dict: - return self.text_msg + return self.markdown_msg def get_feishu_msg(self) -> dict: return self.text_msg @@ -207,12 +222,12 @@ class Message(metaclass=MessageType): return messages_cls @classmethod - def test_all_messages(cls): + def test_all_messages(cls, ding=True, wecom=False): messages_cls = cls.get_all_sub_messages() for _cls in messages_cls: try: - msg = _cls.send_test_msg() + _cls.send_test_msg(ding=ding, wecom=wecom) except NotImplementedError: continue diff --git a/apps/perms/templates/perms/_msg_permed_items_expire.html b/apps/perms/templates/perms/_msg_permed_items_expire.html index 74df4556d..f50c59933 100644 --- a/apps/perms/templates/perms/_msg_permed_items_expire.html +++ b/apps/perms/templates/perms/_msg_permed_items_expire.html @@ -16,6 +16,7 @@
+-

{% trans 'If you have any question, please contact the administrator' %}

diff --git a/apps/users/templates/users/_msg_password_expire_reminder.html b/apps/users/templates/users/_msg_password_expire_reminder.html index 0c8175c23..bfd290156 100644 --- a/apps/users/templates/users/_msg_password_expire_reminder.html +++ b/apps/users/templates/users/_msg_password_expire_reminder.html @@ -11,7 +11,7 @@ {% trans 'Click here update password' %}

- +-

{% trans 'If your password has expired, please click the link below to' %} {% trans 'Reset password' %} diff --git a/apps/users/templates/users/_msg_user_created.html b/apps/users/templates/users/_msg_user_created.html index 678ca237f..3b1c36ed5 100644 --- a/apps/users/templates/users/_msg_user_created.html +++ b/apps/users/templates/users/_msg_user_created.html @@ -15,6 +15,9 @@ {% trans 'click here to set your password' %}

+ + + -

{% trans 'This link is valid for 1 hour. After it expires' %} {% trans 'request new one' %}