diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 098558e3f..2247e8f62 100644 Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index a7dd721b8..cc7e6b362 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Jumpserver 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-30 18:48+0800\n" +"POT-Creation-Date: 2019-07-31 16:35+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -167,7 +167,7 @@ msgstr "系统用户" #: settings/templates/settings/terminal_setting.html:105 terminal/models.py:22 #: terminal/models.py:258 terminal/templates/terminal/terminal_detail.html:43 #: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 -#: users/models/user.py:330 users/templates/users/_select_user_modal.html:13 +#: users/models/user.py:331 users/templates/users/_select_user_modal.html:13 #: users/templates/users/user_detail.html:63 #: users/templates/users/user_group_detail.html:55 #: users/templates/users/user_group_list.html:35 @@ -218,7 +218,7 @@ msgstr "参数" #: perms/models/asset_permission.py:117 perms/models/base.py:41 #: perms/templates/perms/asset_permission_detail.html:98 #: perms/templates/perms/remote_app_permission_detail.html:90 -#: users/models/user.py:371 users/serializers/v1.py:120 +#: users/models/user.py:372 users/serializers/v1.py:120 #: users/templates/users/user_detail.html:111 #: xpack/plugins/change_auth_plan/models.py:106 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113 @@ -279,7 +279,7 @@ msgstr "创建日期" #: perms/templates/perms/remote_app_permission_detail.html:94 #: settings/models.py:34 terminal/models.py:32 #: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15 -#: users/models/user.py:363 users/templates/users/user_detail.html:129 +#: users/models/user.py:364 users/templates/users/user_detail.html:129 #: users/templates/users/user_group_detail.html:67 #: users/templates/users/user_group_list.html:37 #: users/templates/users/user_profile.html:138 @@ -721,12 +721,12 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC" #: assets/templates/assets/system_user_list.html:52 audits/models.py:94 #: audits/templates/audits/login_log_list.html:51 authentication/forms.py:13 #: authentication/templates/authentication/login.html:65 -#: authentication/templates/authentication/new_login.html:91 +#: authentication/templates/authentication/new_login.html:92 #: ops/models/adhoc.py:164 perms/templates/perms/asset_permission_list.html:70 #: perms/templates/perms/asset_permission_user.html:55 #: perms/templates/perms/remote_app_permission_user.html:54 #: settings/templates/settings/_ldap_list_users_modal.html:37 users/forms.py:14 -#: users/models/user.py:328 users/templates/users/_select_user_modal.html:14 +#: users/models/user.py:329 users/templates/users/_select_user_modal.html:14 #: users/templates/users/user_detail.html:67 #: users/templates/users/user_list.html:36 #: users/templates/users/user_profile.html:47 @@ -750,7 +750,7 @@ msgstr "密码或密钥密码" #: assets/templates/assets/_asset_user_auth_view_modal.html:27 #: authentication/forms.py:15 #: authentication/templates/authentication/login.html:68 -#: authentication/templates/authentication/new_login.html:94 +#: authentication/templates/authentication/new_login.html:95 #: settings/forms.py:110 users/forms.py:16 users/forms.py:28 #: users/templates/users/reset_password.html:53 #: users/templates/users/user_password_authentication.html:18 @@ -765,7 +765,7 @@ msgstr "密码" #: assets/forms/user.py:29 assets/serializers/asset_user.py:70 #: assets/templates/assets/_asset_user_auth_update_modal.html:27 -#: users/models/user.py:357 +#: users/models/user.py:358 msgid "Private key" msgstr "ssh私钥" @@ -971,7 +971,7 @@ msgstr "带宽" msgid "Contact" msgstr "联系人" -#: assets/models/cluster.py:22 users/models/user.py:349 +#: assets/models/cluster.py:22 users/models/user.py:350 #: users/templates/users/user_detail.html:76 msgid "Phone" msgstr "手机" @@ -997,7 +997,7 @@ msgid "Default" msgstr "默认" #: assets/models/cluster.py:36 assets/models/label.py:14 -#: users/models/user.py:457 +#: users/models/user.py:470 msgid "System" msgstr "系统" @@ -1116,7 +1116,7 @@ msgstr "默认资产组" #: terminal/templates/terminal/command_list.html:65 #: terminal/templates/terminal/session_list.html:27 #: terminal/templates/terminal/session_list.html:71 users/forms.py:316 -#: users/models/user.py:127 users/models/user.py:445 +#: users/models/user.py:128 users/models/user.py:458 #: users/serializers/v1.py:109 users/templates/users/user_group_detail.html:78 #: users/templates/users/user_group_list.html:36 users/views/user.py:243 #: xpack/plugins/orgs/forms.py:26 @@ -1223,7 +1223,7 @@ msgid "Backend" msgstr "后端" #: assets/serializers/asset_user.py:66 users/forms.py:263 -#: users/models/user.py:360 users/templates/users/first_login.html:42 +#: users/models/user.py:361 users/templates/users/first_login.html:42 #: users/templates/users/user_password_update.html:49 #: users/templates/users/user_profile.html:69 #: users/templates/users/user_profile_update.html:46 @@ -1312,30 +1312,30 @@ msgstr "测试系统用户可连接性: {} => {}" msgid "Test system user connectivity period: {}" msgstr "定期测试系统用户可连接性: {}" -#: assets/tasks.py:471 assets/tasks.py:557 +#: assets/tasks.py:479 assets/tasks.py:565 #: xpack/plugins/change_auth_plan/models.py:522 msgid "The asset {} system platform {} does not support run Ansible tasks" msgstr "资产 {} 系统平台 {} 不支持运行 Ansible 任务" -#: assets/tasks.py:483 +#: assets/tasks.py:491 msgid "" "Push system user task skip, auto push not enable or protocol is not ssh or " "rdp: {}" msgstr "推送系统用户任务跳过,自动推送没有打开,或协议不是ssh或rdp: {}" -#: assets/tasks.py:490 +#: assets/tasks.py:498 msgid "For security, do not push user {}" msgstr "为了安全,禁止推送用户 {}" -#: assets/tasks.py:518 assets/tasks.py:532 +#: assets/tasks.py:526 assets/tasks.py:540 msgid "Push system users to assets: {}" msgstr "推送系统用户到入资产: {}" -#: assets/tasks.py:524 +#: assets/tasks.py:532 msgid "Push system users to asset: {} => {}" msgstr "推送系统用户到入资产: {} => {}" -#: assets/tasks.py:604 +#: assets/tasks.py:612 msgid "Test asset user connectivity: {}" msgstr "测试资产用户可连接性: {}" @@ -2212,7 +2212,7 @@ msgstr "Agent" #: audits/models.py:99 audits/templates/audits/login_log_list.html:56 #: authentication/templates/authentication/_mfa_confirm_modal.html:14 -#: users/forms.py:175 users/models/user.py:352 +#: users/forms.py:175 users/models/user.py:353 #: users/templates/users/first_login.html:45 msgid "MFA" msgstr "MFA" @@ -2479,23 +2479,23 @@ msgstr "改变世界,从一点点开始。" #: authentication/templates/authentication/login.html:46 #: authentication/templates/authentication/login.html:73 -#: authentication/templates/authentication/new_login.html:100 +#: authentication/templates/authentication/new_login.html:101 #: templates/_header_bar.html:101 msgid "Login" msgstr "登录" #: authentication/templates/authentication/login.html:54 -#: authentication/templates/authentication/new_login.html:79 +#: authentication/templates/authentication/new_login.html:80 msgid "The user password has expired" msgstr "用户密码已过期" #: authentication/templates/authentication/login.html:57 -#: authentication/templates/authentication/new_login.html:82 +#: authentication/templates/authentication/new_login.html:83 msgid "Captcha invalid" msgstr "验证码错误" #: authentication/templates/authentication/login.html:84 -#: authentication/templates/authentication/new_login.html:104 +#: authentication/templates/authentication/new_login.html:105 #: users/templates/users/forgot_password.html:10 #: users/templates/users/forgot_password.html:25 msgid "Forgot password" @@ -3022,7 +3022,7 @@ msgstr "空" #: perms/templates/perms/asset_permission_list.html:118 #: perms/templates/perms/remote_app_permission_list.html:16 #: templates/_nav.html:14 users/forms.py:286 users/models/group.py:26 -#: users/models/user.py:336 users/templates/users/_select_user_modal.html:16 +#: users/models/user.py:337 users/templates/users/_select_user_modal.html:16 #: users/templates/users/user_detail.html:217 #: users/templates/users/user_list.html:38 #: xpack/plugins/orgs/templates/orgs/org_list.html:15 @@ -3071,7 +3071,7 @@ msgstr "资产授权" #: perms/models/asset_permission.py:116 perms/models/base.py:40 #: perms/templates/perms/asset_permission_detail.html:90 #: perms/templates/perms/remote_app_permission_detail.html:82 -#: users/models/user.py:368 users/templates/users/user_detail.html:107 +#: users/models/user.py:369 users/templates/users/user_detail.html:107 #: users/templates/users/user_profile.html:120 msgid "Date expired" msgstr "失效日期" @@ -3625,7 +3625,7 @@ msgid "Please submit the LDAP configuration before import" msgstr "请先提交LDAP配置再进行导入" #: settings/templates/settings/_ldap_list_users_modal.html:39 -#: users/models/user.py:332 users/templates/users/user_detail.html:71 +#: users/models/user.py:333 users/templates/users/user_detail.html:71 #: users/templates/users/user_profile.html:59 msgid "Email" msgstr "邮件" @@ -3893,7 +3893,24 @@ msgstr "下载导入模版" msgid "Select the CSV file to import" msgstr "请选择csv文件导入" -#: templates/_message.html:7 +#: templates/_message.html:6 +msgid "" +"\n" +" Your account has expired, please contact the administrator.\n" +" " +msgstr "" +"\n" +" 您的账户已经过期,请联系管理员。 " + +#: templates/_message.html:13 +msgid "Your account will at" +msgstr "您的账户将于" + +#: templates/_message.html:13 templates/_message.html:30 +msgid "expired. " +msgstr "过期。" + +#: templates/_message.html:23 #, python-format msgid "" "\n" @@ -3906,15 +3923,11 @@ msgstr "" "\"%(user_password_update_url)s\"> 链接 更新密码\n" " " -#: templates/_message.html:14 +#: templates/_message.html:30 msgid "Your password will at" msgstr "您的密码将于" -#: templates/_message.html:14 -msgid "expired. " -msgstr "过期。" - -#: templates/_message.html:15 +#: templates/_message.html:31 #, python-format msgid "" "\n" @@ -3927,7 +3940,7 @@ msgstr "" "新密码\n" " " -#: templates/_message.html:27 +#: templates/_message.html:43 #, python-format msgid "" "\n" @@ -3940,7 +3953,7 @@ msgstr "" " 补充完整\n" " " -#: templates/_message.html:40 +#: templates/_message.html:56 #, python-format msgid "" "\n" @@ -4408,7 +4421,7 @@ msgstr "你没有权限" msgid "Could not reset self otp, use profile reset instead" msgstr "不能再该页面重置MFA, 请去个人信息页面重置" -#: users/forms.py:33 users/models/user.py:340 +#: users/forms.py:33 users/models/user.py:341 #: users/templates/users/_select_user_modal.html:15 #: users/templates/users/user_detail.html:87 #: users/templates/users/user_list.html:37 @@ -4527,52 +4540,52 @@ msgstr "选择用户" msgid "User auth from {}, go there change password" msgstr "用户认证源来自 {}, 请去相应系统修改密码" -#: users/models/user.py:126 users/models/user.py:453 +#: users/models/user.py:127 users/models/user.py:466 msgid "Administrator" msgstr "管理员" -#: users/models/user.py:128 +#: users/models/user.py:129 msgid "Application" msgstr "应用程序" -#: users/models/user.py:129 +#: users/models/user.py:130 msgid "Auditor" msgstr "审计员" -#: users/models/user.py:287 users/templates/users/user_profile.html:94 +#: users/models/user.py:288 users/templates/users/user_profile.html:94 #: users/templates/users/user_profile.html:163 #: users/templates/users/user_profile.html:166 msgid "Disable" msgstr "禁用" -#: users/models/user.py:288 users/templates/users/user_profile.html:92 +#: users/models/user.py:289 users/templates/users/user_profile.html:92 #: users/templates/users/user_profile.html:170 msgid "Enable" msgstr "启用" -#: users/models/user.py:289 users/templates/users/user_profile.html:90 +#: users/models/user.py:290 users/templates/users/user_profile.html:90 msgid "Force enable" msgstr "强制启用" -#: users/models/user.py:343 +#: users/models/user.py:344 msgid "Avatar" msgstr "头像" -#: users/models/user.py:346 users/templates/users/user_detail.html:82 +#: users/models/user.py:347 users/templates/users/user_detail.html:82 msgid "Wechat" msgstr "微信" -#: users/models/user.py:375 users/templates/users/user_detail.html:103 +#: users/models/user.py:376 users/templates/users/user_detail.html:103 #: users/templates/users/user_list.html:39 #: users/templates/users/user_profile.html:102 msgid "Source" msgstr "用户来源" -#: users/models/user.py:379 +#: users/models/user.py:380 msgid "Date password last updated" msgstr "最后更新密码日期" -#: users/models/user.py:456 +#: users/models/user.py:469 msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员" @@ -5115,43 +5128,43 @@ msgstr "您好 %(name)s" msgid "" "\n" " Hello %(name)s:\n" -"
\n" +"
\n" " Please click the link below to reset your password, if not your request, " "concern your account security\n" -"
\n" +"
\n" " Click " "here reset password\n" -"
\n" +"
\n" " This link is valid for 1 hour. After it expires, request new one\n" "\n" -"
\n" +"
\n" " ---\n" "\n" -"
\n" +"
\n" " Login direct\n" "\n" -"
\n" +"
\n" " " msgstr "" "\n" " 您好 %(name)s:\n" -"
\n" +"
\n" " 请点击下面链接重置密码, 如果不是您申请的,请关注账号安全\n" -"
\n" +"
\n" " 请点击这" "里设置密码 \n" -"
\n" +"
\n" " 这个链接有效期1小时, 超过时间您可以重新申请\n" "\n" -"
\n" +"
\n" " ---\n" "\n" -"
\n" +"
\n" " 直接登录\n" "\n" -"
\n" +"
\n" " " #: users/utils.py:121 @@ -5163,88 +5176,114 @@ msgstr "安全通知" msgid "" "\n" " Hello %(name)s:\n" -"
\n" +"
\n" " Your password will expire in %(date_password_expired)s,\n" -"
\n" +"
\n" " For your account security, please click on the link below to update your " "password in time\n" -"
\n" +"
\n" " Click here update password\n" -"
\n" +"
\n" " If your password has expired, please click \n" " Password expired \n" " to apply for a password reset email.\n" "\n" -"
\n" +"
\n" " ---\n" "\n" -"
\n" +"
\n" "
Login direct\n" "\n" -"
\n" +"
\n" " " msgstr "" "\n" " 您好 %(name)s:\n" -"
\n" +"
\n" " 您的密码会在 %(date_password_expired)s 过期,\n" -"
\n" +"
\n" " 为了您的账号安全,请点击下面的链接及时更新密码\n" -"
\n" +"
\n" " 请点击这里更新密码\n" -"
\n" +"
\n" " 如果您的密码已经过期,请点击 \n" " 密码过期 \n" " 申请一份重置密码邮件。\n" "\n" -"
\n" +"
\n" " ---\n" "\n" -"
\n" +"
\n" " 直接登录\n" "\n" -"
\n" +"
\n" " " #: users/utils.py:159 -msgid "SSH Key Reset" -msgstr "重置ssh密钥" +msgid "Expiration notice" +msgstr "过期通知" #: users/utils.py:161 #, python-format msgid "" "\n" +" Hello %(name)s:\n" +"
\n" +" Your account will expire in %(date_expired)s,\n" +"
\n" +" In order not to affect your normal work, please contact the " +"administrator for confirmation.\n" +"
\n" +" " +msgstr "" +"\n" +" 您好 %(name)s:\n" +"
\n" +" 您的账户会在 %(date_expired)s 过期,\n" +"
\n" +" 为了不影响您正常工作,请联系管理员确认。\n" +"
\n" +" " + +#: users/utils.py:180 +msgid "SSH Key Reset" +msgstr "重置ssh密钥" + +#: users/utils.py:182 +#, python-format +msgid "" +"\n" " Hello %(name)s:\n" -"
\n" +"
\n" " Your ssh public key has been reset by site administrator.\n" " Please login and reset your ssh public key.\n" -"
\n" +"
\n" " Login direct\n" "\n" -"
\n" +"
\n" " " msgstr "" "\n" " 你好 %(name)s:\n" -"
\n" +"
\n" " 您的密钥已被管理员重置,\n" " 请登录并重新设置您的密钥.\n" -"
\n" +"
\n" " Login direct\n" "\n" -"
\n" +"
\n" " " -#: users/utils.py:194 +#: users/utils.py:215 msgid "User not exist" msgstr "用户不存在" -#: users/utils.py:196 +#: users/utils.py:217 msgid "Disabled or expired" msgstr "禁用或失效" -#: users/utils.py:209 +#: users/utils.py:230 msgid "Password or SSH public key invalid" msgstr "密码或密钥不合法" diff --git a/apps/templates/_message.html b/apps/templates/_message.html index bdcbb6d5f..19e559d36 100644 --- a/apps/templates/_message.html +++ b/apps/templates/_message.html @@ -1,8 +1,24 @@ {% load i18n %} +{% block user_expired_message %} + {% if request.user.is_expired %} +
+ {% blocktrans %} + Your account has expired, please contact the administrator. + {% endblocktrans %} + +
+ {% elif request.user.will_expired %} +
+ {% trans 'Your account will at' %} {{ request.user.date_expired }} {% trans 'expired. ' %} + +
+ {% endif %} +{% endblock %} + {% block password_expired_message %} {% url 'users:user-password-update' as user_password_update_url %} - {% if request.user.password_has_expired %} + {% if request.user.password_has_expired %}
{% blocktrans %} Your password has expired, please click this link update password. diff --git a/apps/users/models/user.py b/apps/users/models/user.py index a6cdf9f0e..c2a568c34 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -402,6 +402,18 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser): else: return False + @property + def expired_remain_days(self): + date_remain = self.date_expired - timezone.now() + return date_remain.days + + @property + def will_expired(self): + if 0 <= self.expired_remain_days < 5: + return True + else: + return False + @property def is_valid(self): if self.is_active and not self.is_expired: @@ -411,7 +423,7 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser): @property def is_local(self): return self.source == self.SOURCE_LOCAL - + def save(self, *args, **kwargs): if not self.name: self.name = self.username diff --git a/apps/users/tasks.py b/apps/users/tasks.py index ab025cae3..cbdfd4848 100644 --- a/apps/users/tasks.py +++ b/apps/users/tasks.py @@ -1,16 +1,15 @@ # -*- coding: utf-8 -*- # -import datetime -from django.utils import timezone -from django.conf import settings from celery import shared_task from ops.celery.utils import create_or_update_celery_periodic_tasks -from ops.celery.decorator import after_app_ready_start, register_as_period_task +from ops.celery.decorator import after_app_ready_start from common.utils import get_logger from .models import User -from .utils import send_password_expiration_reminder_mail +from .utils import ( + send_password_expiration_reminder_mail, send_user_expiration_reminder_mail +) logger = get_logger(__file__) @@ -43,4 +42,27 @@ def check_password_expired_periodic(): create_or_update_celery_periodic_tasks(tasks) +@shared_task +def check_user_expired(): + users = User.objects.exclude(role=User.ROLE_APP) + for user in users: + if not user.is_valid: + continue + if not user.will_expired: + continue + send_user_expiration_reminder_mail(user) + + +@shared_task +@after_app_ready_start +def check_user_expired_periodic(): + tasks = { + 'check_user_expired_periodic': { + 'task': check_user_expired.name, + 'interval': None, + 'crontab': '0 14 * * *', + 'enabled': True, + } + } + create_or_update_celery_periodic_tasks(tasks) diff --git a/apps/users/utils.py b/apps/users/utils.py index 3ccdc15b0..f076e8df7 100644 --- a/apps/users/utils.py +++ b/apps/users/utils.py @@ -89,20 +89,20 @@ def send_reset_password_mail(user): recipient_list = [user.email] message = _(""" Hello %(name)s: -
+
Please click the link below to reset your password, if not your request, concern your account security -
+
Click here reset password -
+
This link is valid for 1 hour. After it expires, request new one -
+
--- -
+
Login direct -
+
""") % { 'name': user.name, 'rest_password_url': reverse('users:reset-password', external=True), @@ -122,24 +122,24 @@ def send_password_expiration_reminder_mail(user): recipient_list = [user.email] message = _(""" Hello %(name)s: -
+
Your password will expire in %(date_password_expired)s, -
+
For your account security, please click on the link below to update your password in time -
+
Click here update password -
+
If your password has expired, please click Password expired to apply for a password reset email. -
+
--- -
+
Login direct -
+
""") % { 'name': user.name, 'date_password_expired': datetime.fromtimestamp(datetime.timestamp( @@ -155,18 +155,39 @@ def send_password_expiration_reminder_mail(user): send_mail_async.delay(subject, message, recipient_list, html_message=message) +def send_user_expiration_reminder_mail(user): + subject = _('Expiration notice') + recipient_list = [user.email] + message = _(""" + Hello %(name)s: +
+ Your account will expire in %(date_expired)s, +
+ In order not to affect your normal work, please contact the administrator for confirmation. +
+ """) % { + 'name': user.name, + 'date_expired': datetime.fromtimestamp(datetime.timestamp( + user.date_expired)).strftime('%Y-%m-%d %H:%M'), + } + if settings.DEBUG: + logger.debug(message) + + send_mail_async.delay(subject, message, recipient_list, html_message=message) + + def send_reset_ssh_key_mail(user): subject = _('SSH Key Reset') recipient_list = [user.email] message = _(""" Hello %(name)s: -
+
Your ssh public key has been reset by site administrator. Please login and reset your ssh public key. -
+
Login direct -
+
""") % { 'name': user.name, 'login_url': reverse('authentication:login', external=True),