[Update] 基本完成登陆审核

pull/3428/head
ibuler 2019-10-31 18:23:43 +08:00
parent 23b777b23b
commit dc3a9561c2
19 changed files with 532 additions and 242 deletions

View File

@ -5,3 +5,4 @@ from .auth import *
from .token import * from .token import *
from .mfa import * from .mfa import *
from .access_key import * from .access_key import *
from .login_confirm import *

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
#
from rest_framework.generics import UpdateAPIView
from django.shortcuts import get_object_or_404
from common.permissions import IsOrgAdmin
from ..models import LoginConfirmSetting
from ..serializers import LoginConfirmSettingSerializer
__all__ = ['LoginConfirmSettingUpdateApi']
class LoginConfirmSettingUpdateApi(UpdateAPIView):
permission_classes = (IsOrgAdmin,)
serializer_class = LoginConfirmSettingSerializer
def get_object(self):
from users.models import User
user_id = self.kwargs.get('user_id')
user = get_object_or_404(User, pk=user_id)
defaults = {'user': user}
s, created = LoginConfirmSetting.objects.get_or_create(
defaults, user=user,
)
return s

View File

@ -0,0 +1,32 @@
# Generated by Django 2.2.5 on 2019-10-31 10:23
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('authentication', '0002_auto_20190729_1423'),
]
operations = [
migrations.CreateModel(
name='LoginConfirmSetting',
fields=[
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('is_active', models.BooleanField(default=True, verbose_name='Is active')),
('reviewers', models.ManyToManyField(blank=True, related_name='review_login_confirm_settings', to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='login_confirm_setting', to=settings.AUTH_USER_MODEL, verbose_name='User')),
],
options={
'abstract': False,
},
),
]

View File

@ -1,7 +1,7 @@
import uuid import uuid
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _, ugettext as __
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
from django.conf import settings from django.conf import settings
@ -40,8 +40,8 @@ class PrivateToken(Token):
class LoginConfirmSetting(CommonModelMixin): class LoginConfirmSetting(CommonModelMixin):
user = models.OneToOneField('users.User', on_delete=models.CASCADE, verbose_name=_("User"), related_name=_("login_confirmation_setting")) user = models.OneToOneField('users.User', on_delete=models.CASCADE, verbose_name=_("User"), related_name="login_confirm_setting")
reviewers = models.ManyToManyField('users.User', verbose_name=_("Reviewers"), related_name=_("review_login_confirmation_settings")) reviewers = models.ManyToManyField('users.User', verbose_name=_("Reviewers"), related_name="review_login_confirm_settings", blank=True)
is_active = models.BooleanField(default=True, verbose_name=_("Is active")) is_active = models.BooleanField(default=True, verbose_name=_("Is active"))
@classmethod @classmethod
@ -50,7 +50,7 @@ class LoginConfirmSetting(CommonModelMixin):
def create_confirm_order(self, request=None): def create_confirm_order(self, request=None):
from orders.models import LoginConfirmOrder from orders.models import LoginConfirmOrder
title = _('User login confirm: {}'.format(self.user)) title = _('User login confirm: {}').format(self.user)
if request: if request:
remote_addr = get_request_ip(request) remote_addr = get_request_ip(request)
city = get_ip_city(remote_addr) city = get_ip_city(remote_addr)

View File

@ -4,17 +4,16 @@ from django.core.cache import cache
from rest_framework import serializers from rest_framework import serializers
from users.models import User from users.models import User
from .models import AccessKey from .models import AccessKey, LoginConfirmSetting
__all__ = [ __all__ = [
'AccessKeySerializer', 'OtpVerifySerializer', 'BearerTokenSerializer', 'AccessKeySerializer', 'OtpVerifySerializer', 'BearerTokenSerializer',
'MFAChallengeSerializer', 'MFAChallengeSerializer', 'LoginConfirmSettingSerializer',
] ]
class AccessKeySerializer(serializers.ModelSerializer): class AccessKeySerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = AccessKey model = AccessKey
fields = ['id', 'secret', 'is_active', 'date_created'] fields = ['id', 'secret', 'is_active', 'date_created']
@ -87,3 +86,9 @@ class MFAChallengeSerializer(BearerTokenMixin, serializers.Serializer):
username = self.context["username"] username = self.context["username"]
return self.create_response(username) return self.create_response(username)
class LoginConfirmSettingSerializer(serializers.ModelSerializer):
class Meta:
model = LoginConfirmSetting
fields = ['id', 'user', 'reviewers', 'date_created', 'date_updated']
read_only_fields = ['date_created', 'date_updated']

View File

@ -61,9 +61,6 @@
<div class="col-md-6"> <div class="col-md-6">
{% include '_copyright.html' %} {% include '_copyright.html' %}
</div> </div>
<div class="col-md-6 text-right">
<small>2014-2019</small>
</div>
</div> </div>
</div> </div>
</body> </body>

View File

@ -19,7 +19,8 @@ urlpatterns = [
api.UserConnectionTokenApi.as_view(), name='connection-token'), api.UserConnectionTokenApi.as_view(), name='connection-token'),
path('otp/auth/', api.UserOtpAuthApi.as_view(), name='user-otp-auth'), path('otp/auth/', api.UserOtpAuthApi.as_view(), name='user-otp-auth'),
path('otp/verify/', api.UserOtpVerifyApi.as_view(), name='user-otp-verify'), path('otp/verify/', api.UserOtpVerifyApi.as_view(), name='user-otp-verify'),
path('order/auth/', api.UserOrderAcceptAuthApi.as_view(), name='user-order-auth') path('order/auth/', api.UserOrderAcceptAuthApi.as_view(), name='user-order-auth'),
path('login-confirm-settings/<uuid:user_id>/', api.LoginConfirmSettingUpdateApi.as_view(), name='login-confirm-setting-update')
] ]
urlpatterns += router.urls urlpatterns += router.urls

View File

@ -179,7 +179,7 @@ class UserLoginGuardView(RedirectView):
if user.otp_enabled and user.otp_secret_key and \ if user.otp_enabled and user.otp_secret_key and \
not self.request.session.get('auth_otp'): not self.request.session.get('auth_otp'):
return reverse('authentication:login-otp') return reverse('authentication:login-otp')
confirm_setting = LoginConfirmSetting.get_user_confirm_setting(user) confirm_setting = user.get_login_confirm_setting()
if confirm_setting and not self.request.session.get('auth_confirm'): if confirm_setting and not self.request.session.get('auth_confirm'):
order = confirm_setting.create_confirm_order(self.request) order = confirm_setting.create_confirm_order(self.request)
self.request.session['auth_order_id'] = str(order.id) self.request.session['auth_order_id'] = str(order.id)

Binary file not shown.

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n" "Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-10-30 14:51+0800\n" "POT-Creation-Date: 2019-10-31 16:57+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n" "Language-Team: Jumpserver team<ibuler@qq.com>\n"
@ -83,7 +83,7 @@ msgstr "运行参数"
#: assets/templates/assets/domain_detail.html:60 #: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_list.html:26 #: assets/templates/assets/domain_list.html:26
#: assets/templates/assets/label_list.html:16 #: assets/templates/assets/label_list.html:16
#: assets/templates/assets/system_user_list.html:51 audits/models.py:19 #: assets/templates/assets/system_user_list.html:51 audits/models.py:20
#: audits/templates/audits/ftp_log_list.html:44 #: audits/templates/audits/ftp_log_list.html:44
#: audits/templates/audits/ftp_log_list.html:74 #: audits/templates/audits/ftp_log_list.html:74
#: perms/forms/asset_permission.py:84 perms/models/asset_permission.py:80 #: perms/forms/asset_permission.py:84 perms/models/asset_permission.py:80
@ -144,7 +144,7 @@ msgstr "资产"
#: settings/templates/settings/terminal_setting.html:105 terminal/models.py:23 #: settings/templates/settings/terminal_setting.html:105 terminal/models.py:23
#: terminal/models.py:260 terminal/templates/terminal/terminal_detail.html:43 #: terminal/models.py:260 terminal/templates/terminal/terminal_detail.html:43
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 #: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
#: users/models/user.py:375 users/templates/users/_select_user_modal.html:13 #: users/models/user.py:382 users/templates/users/_select_user_modal.html:13
#: users/templates/users/user_detail.html:63 #: users/templates/users/user_detail.html:63
#: users/templates/users/user_group_detail.html:55 #: users/templates/users/user_group_detail.html:55
#: users/templates/users/user_group_list.html:35 #: users/templates/users/user_group_list.html:35
@ -197,7 +197,7 @@ msgstr "参数"
#: orgs/models.py:16 perms/models/base.py:54 #: orgs/models.py:16 perms/models/base.py:54
#: perms/templates/perms/asset_permission_detail.html:98 #: perms/templates/perms/asset_permission_detail.html:98
#: perms/templates/perms/remote_app_permission_detail.html:90 #: perms/templates/perms/remote_app_permission_detail.html:90
#: users/models/user.py:416 users/serializers/group.py:32 #: users/models/user.py:423 users/serializers/group.py:32
#: users/templates/users/user_detail.html:111 #: users/templates/users/user_detail.html:111
#: xpack/plugins/change_auth_plan/models.py:108 #: xpack/plugins/change_auth_plan/models.py:108
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113
@ -261,7 +261,7 @@ msgstr "创建日期"
#: perms/templates/perms/remote_app_permission_detail.html:94 #: perms/templates/perms/remote_app_permission_detail.html:94
#: settings/models.py:34 terminal/models.py:33 #: settings/models.py:34 terminal/models.py:33
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15 #: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15
#: users/models/user.py:408 users/templates/users/user_detail.html:129 #: users/models/user.py:415 users/templates/users/user_detail.html:129
#: users/templates/users/user_group_detail.html:67 #: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_list.html:37 #: users/templates/users/user_group_list.html:37
#: users/templates/users/user_profile.html:138 #: users/templates/users/user_profile.html:138
@ -413,7 +413,7 @@ msgstr "详情"
#: assets/templates/assets/label_list.html:39 #: assets/templates/assets/label_list.html:39
#: assets/templates/assets/system_user_detail.html:26 #: assets/templates/assets/system_user_detail.html:26
#: assets/templates/assets/system_user_list.html:29 #: assets/templates/assets/system_user_list.html:29
#: assets/templates/assets/system_user_list.html:81 audits/models.py:33 #: assets/templates/assets/system_user_list.html:81 audits/models.py:34
#: perms/templates/perms/asset_permission_detail.html:30 #: perms/templates/perms/asset_permission_detail.html:30
#: perms/templates/perms/asset_permission_list.html:178 #: perms/templates/perms/asset_permission_list.html:178
#: perms/templates/perms/remote_app_permission_detail.html:30 #: perms/templates/perms/remote_app_permission_detail.html:30
@ -457,7 +457,7 @@ msgstr "更新"
#: assets/templates/assets/domain_list.html:55 #: assets/templates/assets/domain_list.html:55
#: assets/templates/assets/label_list.html:40 #: assets/templates/assets/label_list.html:40
#: assets/templates/assets/system_user_detail.html:30 #: assets/templates/assets/system_user_detail.html:30
#: assets/templates/assets/system_user_list.html:82 audits/models.py:34 #: assets/templates/assets/system_user_list.html:82 audits/models.py:35
#: authentication/templates/authentication/_access_key_modal.html:65 #: authentication/templates/authentication/_access_key_modal.html:65
#: ops/templates/ops/task_list.html:69 #: ops/templates/ops/task_list.html:69
#: perms/templates/perms/asset_permission_detail.html:34 #: perms/templates/perms/asset_permission_detail.html:34
@ -513,7 +513,7 @@ msgstr "创建远程应用"
#: assets/templates/assets/domain_gateway_list.html:73 #: assets/templates/assets/domain_gateway_list.html:73
#: assets/templates/assets/domain_list.html:29 #: assets/templates/assets/domain_list.html:29
#: assets/templates/assets/label_list.html:17 #: assets/templates/assets/label_list.html:17
#: assets/templates/assets/system_user_list.html:56 audits/models.py:38 #: assets/templates/assets/system_user_list.html:56 audits/models.py:39
#: audits/templates/audits/operate_log_list.html:47 #: audits/templates/audits/operate_log_list.html:47
#: audits/templates/audits/operate_log_list.html:73 #: audits/templates/audits/operate_log_list.html:73
#: authentication/templates/authentication/_access_key_modal.html:34 #: authentication/templates/authentication/_access_key_modal.html:34
@ -700,7 +700,7 @@ msgstr "SSH网关支持代理SSH,RDP和VNC"
#: assets/templates/assets/admin_user_list.html:45 #: assets/templates/assets/admin_user_list.html:45
#: assets/templates/assets/domain_gateway_list.html:71 #: assets/templates/assets/domain_gateway_list.html:71
#: assets/templates/assets/system_user_detail.html:62 #: assets/templates/assets/system_user_detail.html:62
#: assets/templates/assets/system_user_list.html:48 audits/models.py:80 #: assets/templates/assets/system_user_list.html:48 audits/models.py:81
#: audits/templates/audits/login_log_list.html:57 authentication/forms.py:13 #: audits/templates/audits/login_log_list.html:57 authentication/forms.py:13
#: authentication/templates/authentication/login.html:65 #: authentication/templates/authentication/login.html:65
#: authentication/templates/authentication/xpack_login.html:92 #: authentication/templates/authentication/xpack_login.html:92
@ -708,7 +708,7 @@ msgstr "SSH网关支持代理SSH,RDP和VNC"
#: perms/templates/perms/asset_permission_user.html:55 #: perms/templates/perms/asset_permission_user.html:55
#: perms/templates/perms/remote_app_permission_user.html:54 #: perms/templates/perms/remote_app_permission_user.html:54
#: settings/templates/settings/_ldap_list_users_modal.html:30 users/forms.py:13 #: settings/templates/settings/_ldap_list_users_modal.html:30 users/forms.py:13
#: users/models/user.py:373 users/templates/users/_select_user_modal.html:14 #: users/models/user.py:380 users/templates/users/_select_user_modal.html:14
#: users/templates/users/user_detail.html:67 #: users/templates/users/user_detail.html:67
#: users/templates/users/user_list.html:36 #: users/templates/users/user_list.html:36
#: users/templates/users/user_profile.html:47 #: users/templates/users/user_profile.html:47
@ -748,7 +748,7 @@ msgstr "密码"
#: assets/forms/user.py:30 assets/serializers/asset_user.py:71 #: assets/forms/user.py:30 assets/serializers/asset_user.py:71
#: assets/templates/assets/_asset_user_auth_update_modal.html:27 #: assets/templates/assets/_asset_user_auth_update_modal.html:27
#: users/models/user.py:402 #: users/models/user.py:409
msgid "Private key" msgid "Private key"
msgstr "ssh私钥" msgstr "ssh私钥"
@ -798,7 +798,7 @@ msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig"
#: assets/templates/assets/user_asset_list.html:76 #: assets/templates/assets/user_asset_list.html:76
#: audits/templates/audits/login_log_list.html:60 #: audits/templates/audits/login_log_list.html:60
#: orders/templates/orders/login_confirm_order_detail.html:33 #: orders/templates/orders/login_confirm_order_detail.html:33
#: orders/templates/orders/login_confirm_order_list.html:15 #: orders/templates/orders/login_confirm_order_list.html:16
#: perms/templates/perms/asset_permission_asset.html:58 settings/forms.py:144 #: perms/templates/perms/asset_permission_asset.html:58 settings/forms.py:144
#: users/templates/users/_granted_assets.html:31 #: users/templates/users/_granted_assets.html:31
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:54 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:54
@ -964,7 +964,7 @@ msgstr "带宽"
msgid "Contact" msgid "Contact"
msgstr "联系人" msgstr "联系人"
#: assets/models/cluster.py:22 users/models/user.py:394 #: assets/models/cluster.py:22 users/models/user.py:401
#: users/templates/users/user_detail.html:76 #: users/templates/users/user_detail.html:76
msgid "Phone" msgid "Phone"
msgstr "手机" msgstr "手机"
@ -990,7 +990,7 @@ msgid "Default"
msgstr "默认" msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:14 #: assets/models/cluster.py:36 assets/models/label.py:14
#: users/models/user.py:514 #: users/models/user.py:521
msgid "System" msgid "System"
msgstr "系统" msgstr "系统"
@ -1097,8 +1097,8 @@ msgstr "资产组"
msgid "Default asset group" msgid "Default asset group"
msgstr "默认资产组" msgstr "默认资产组"
#: assets/models/label.py:15 audits/models.py:17 audits/models.py:37 #: assets/models/label.py:15 audits/models.py:18 audits/models.py:38
#: audits/models.py:50 audits/templates/audits/ftp_log_list.html:36 #: audits/models.py:51 audits/templates/audits/ftp_log_list.html:36
#: audits/templates/audits/ftp_log_list.html:73 #: audits/templates/audits/ftp_log_list.html:73
#: audits/templates/audits/operate_log_list.html:39 #: audits/templates/audits/operate_log_list.html:39
#: audits/templates/audits/operate_log_list.html:72 #: audits/templates/audits/operate_log_list.html:72
@ -1108,7 +1108,7 @@ msgstr "默认资产组"
#: ops/templates/ops/command_execution_list.html:63 orders/models.py:11 #: ops/templates/ops/command_execution_list.html:63 orders/models.py:11
#: orders/models.py:32 #: orders/models.py:32
#: orders/templates/orders/login_confirm_order_detail.html:32 #: orders/templates/orders/login_confirm_order_detail.html:32
#: orders/templates/orders/login_confirm_order_list.html:14 #: orders/templates/orders/login_confirm_order_list.html:15
#: perms/forms/asset_permission.py:78 perms/forms/remote_app_permission.py:34 #: perms/forms/asset_permission.py:78 perms/forms/remote_app_permission.py:34
#: perms/models/base.py:49 #: perms/models/base.py:49
#: perms/templates/perms/asset_permission_create_update.html:41 #: perms/templates/perms/asset_permission_create_update.html:41
@ -1121,7 +1121,7 @@ msgstr "默认资产组"
#: terminal/templates/terminal/command_list.html:65 #: terminal/templates/terminal/command_list.html:65
#: terminal/templates/terminal/session_list.html:27 #: terminal/templates/terminal/session_list.html:27
#: terminal/templates/terminal/session_list.html:71 users/forms.py:319 #: terminal/templates/terminal/session_list.html:71 users/forms.py:319
#: users/models/user.py:129 users/models/user.py:145 users/models/user.py:502 #: users/models/user.py:136 users/models/user.py:152 users/models/user.py:509
#: users/serializers/group.py:21 #: users/serializers/group.py:21
#: users/templates/users/user_group_detail.html:78 #: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:36 users/views/user.py:250 #: users/templates/users/user_group_list.html:36 users/views/user.py:250
@ -1211,7 +1211,7 @@ msgid "Login mode"
msgstr "登录模式" msgstr "登录模式"
#: assets/models/user.py:166 assets/templates/assets/user_asset_list.html:79 #: assets/models/user.py:166 assets/templates/assets/user_asset_list.html:79
#: audits/models.py:20 audits/templates/audits/ftp_log_list.html:52 #: audits/models.py:21 audits/templates/audits/ftp_log_list.html:52
#: audits/templates/audits/ftp_log_list.html:75 #: audits/templates/audits/ftp_log_list.html:75
#: perms/forms/asset_permission.py:90 perms/forms/remote_app_permission.py:43 #: perms/forms/asset_permission.py:90 perms/forms/remote_app_permission.py:43
#: perms/models/asset_permission.py:82 perms/models/remote_app_permission.py:16 #: perms/models/asset_permission.py:82 perms/models/remote_app_permission.py:16
@ -1277,7 +1277,7 @@ msgid "Backend"
msgstr "后端" msgstr "后端"
#: assets/serializers/asset_user.py:67 users/forms.py:262 #: assets/serializers/asset_user.py:67 users/forms.py:262
#: users/models/user.py:405 users/templates/users/first_login.html:42 #: users/models/user.py:412 users/templates/users/first_login.html:42
#: users/templates/users/user_password_update.html:49 #: users/templates/users/user_password_update.html:49
#: users/templates/users/user_profile.html:69 #: users/templates/users/user_profile.html:69
#: users/templates/users/user_profile_update.html:46 #: users/templates/users/user_profile_update.html:46
@ -1470,8 +1470,8 @@ msgstr "请输入密码"
#: assets/templates/assets/_asset_user_auth_update_modal.html:68 #: assets/templates/assets/_asset_user_auth_update_modal.html:68
#: assets/templates/assets/asset_detail.html:302 #: assets/templates/assets/asset_detail.html:302
#: users/templates/users/user_detail.html:313 #: users/templates/users/user_detail.html:364
#: users/templates/users/user_detail.html:340 #: users/templates/users/user_detail.html:391
#: xpack/plugins/interface/views.py:35 #: xpack/plugins/interface/views.py:35
msgid "Update successfully!" msgid "Update successfully!"
msgstr "更新成功" msgstr "更新成功"
@ -1668,10 +1668,11 @@ msgstr "选择节点"
#: authentication/templates/authentication/_mfa_confirm_modal.html:20 #: authentication/templates/authentication/_mfa_confirm_modal.html:20
#: settings/templates/settings/terminal_setting.html:168 #: settings/templates/settings/terminal_setting.html:168
#: templates/_modal.html:23 terminal/templates/terminal/session_detail.html:112 #: templates/_modal.html:23 terminal/templates/terminal/session_detail.html:112
#: users/templates/users/user_detail.html:394 #: users/templates/users/user_detail.html:271
#: users/templates/users/user_detail.html:420 #: users/templates/users/user_detail.html:445
#: users/templates/users/user_detail.html:443 #: users/templates/users/user_detail.html:471
#: users/templates/users/user_detail.html:488 #: users/templates/users/user_detail.html:494
#: users/templates/users/user_detail.html:539
#: users/templates/users/user_group_create_update.html:32 #: users/templates/users/user_group_create_update.html:32
#: users/templates/users/user_group_list.html:120 #: users/templates/users/user_group_list.html:120
#: users/templates/users/user_list.html:256 #: users/templates/users/user_list.html:256
@ -1871,9 +1872,9 @@ msgstr "显示所有子节点资产"
#: assets/templates/assets/asset_list.html:417 #: assets/templates/assets/asset_list.html:417
#: assets/templates/assets/system_user_list.html:129 #: assets/templates/assets/system_user_list.html:129
#: users/templates/users/user_detail.html:388 #: users/templates/users/user_detail.html:439
#: users/templates/users/user_detail.html:414 #: users/templates/users/user_detail.html:465
#: users/templates/users/user_detail.html:482 #: users/templates/users/user_detail.html:533
#: users/templates/users/user_group_list.html:114 #: users/templates/users/user_group_list.html:114
#: users/templates/users/user_list.html:250 #: users/templates/users/user_list.html:250
#: xpack/plugins/interface/templates/interface/interface.html:97 #: xpack/plugins/interface/templates/interface/interface.html:97
@ -1887,9 +1888,9 @@ msgstr "删除选择资产"
#: assets/templates/assets/asset_list.html:421 #: assets/templates/assets/asset_list.html:421
#: assets/templates/assets/system_user_list.html:133 #: assets/templates/assets/system_user_list.html:133
#: settings/templates/settings/terminal_setting.html:166 #: settings/templates/settings/terminal_setting.html:166
#: users/templates/users/user_detail.html:392 #: users/templates/users/user_detail.html:443
#: users/templates/users/user_detail.html:418 #: users/templates/users/user_detail.html:469
#: users/templates/users/user_detail.html:486 #: users/templates/users/user_detail.html:537
#: users/templates/users/user_group_list.html:118 #: users/templates/users/user_group_list.html:118
#: users/templates/users/user_list.html:254 #: users/templates/users/user_list.html:254
#: xpack/plugins/interface/templates/interface/interface.html:101 #: xpack/plugins/interface/templates/interface/interface.html:101
@ -2194,7 +2195,7 @@ msgstr "资产管理"
msgid "System user asset" msgid "System user asset"
msgstr "系统用户资产" msgstr "系统用户资产"
#: audits/models.py:18 audits/models.py:41 audits/models.py:52 #: audits/models.py:19 audits/models.py:42 audits/models.py:53
#: audits/templates/audits/ftp_log_list.html:76 #: audits/templates/audits/ftp_log_list.html:76
#: audits/templates/audits/operate_log_list.html:76 #: audits/templates/audits/operate_log_list.html:76
#: audits/templates/audits/password_change_log_list.html:58 #: audits/templates/audits/password_change_log_list.html:58
@ -2204,86 +2205,86 @@ msgstr "系统用户资产"
msgid "Remote addr" msgid "Remote addr"
msgstr "远端地址" msgstr "远端地址"
#: audits/models.py:21 audits/templates/audits/ftp_log_list.html:77 #: audits/models.py:22 audits/templates/audits/ftp_log_list.html:77
msgid "Operate" msgid "Operate"
msgstr "操作" msgstr "操作"
#: audits/models.py:22 audits/templates/audits/ftp_log_list.html:59 #: audits/models.py:23 audits/templates/audits/ftp_log_list.html:59
#: audits/templates/audits/ftp_log_list.html:78 #: audits/templates/audits/ftp_log_list.html:78
msgid "Filename" msgid "Filename"
msgstr "文件名" msgstr "文件名"
#: audits/models.py:23 audits/models.py:76 #: audits/models.py:24 audits/models.py:77
#: audits/templates/audits/ftp_log_list.html:79 #: audits/templates/audits/ftp_log_list.html:79
#: ops/templates/ops/command_execution_list.html:68 #: ops/templates/ops/command_execution_list.html:68
#: ops/templates/ops/task_list.html:15 #: ops/templates/ops/task_list.html:15
#: users/templates/users/user_detail.html:464 #: users/templates/users/user_detail.html:515
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:14 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:14
#: xpack/plugins/cloud/api.py:61 #: xpack/plugins/cloud/api.py:61
msgid "Success" msgid "Success"
msgstr "成功" msgstr "成功"
#: audits/models.py:32 #: audits/models.py:33
#: authentication/templates/authentication/_access_key_modal.html:22 #: authentication/templates/authentication/_access_key_modal.html:22
#: xpack/plugins/vault/templates/vault/vault.html:46 #: xpack/plugins/vault/templates/vault/vault.html:46
msgid "Create" msgid "Create"
msgstr "创建" msgstr "创建"
#: audits/models.py:39 audits/templates/audits/operate_log_list.html:55 #: audits/models.py:40 audits/templates/audits/operate_log_list.html:55
#: audits/templates/audits/operate_log_list.html:74 #: audits/templates/audits/operate_log_list.html:74
msgid "Resource Type" msgid "Resource Type"
msgstr "资源类型" msgstr "资源类型"
#: audits/models.py:40 audits/templates/audits/operate_log_list.html:75 #: audits/models.py:41 audits/templates/audits/operate_log_list.html:75
msgid "Resource" msgid "Resource"
msgstr "资源" msgstr "资源"
#: audits/models.py:51 audits/templates/audits/password_change_log_list.html:57 #: audits/models.py:52 audits/templates/audits/password_change_log_list.html:57
msgid "Change by" msgid "Change by"
msgstr "修改者" msgstr "修改者"
#: audits/models.py:70 users/templates/users/user_detail.html:98 #: audits/models.py:71 users/templates/users/user_detail.html:98
msgid "Disabled" msgid "Disabled"
msgstr "禁用" msgstr "禁用"
#: audits/models.py:71 settings/models.py:33 #: audits/models.py:72 settings/models.py:33
#: users/templates/users/user_detail.html:96 #: users/templates/users/user_detail.html:96
msgid "Enabled" msgid "Enabled"
msgstr "启用" msgstr "启用"
#: audits/models.py:72 #: audits/models.py:73
msgid "-" msgid "-"
msgstr "" msgstr ""
#: audits/models.py:77 xpack/plugins/cloud/models.py:264 #: audits/models.py:78 xpack/plugins/cloud/models.py:264
#: xpack/plugins/cloud/models.py:287 #: xpack/plugins/cloud/models.py:287
msgid "Failed" msgid "Failed"
msgstr "失败" msgstr "失败"
#: audits/models.py:81 #: audits/models.py:82
msgid "Login type" msgid "Login type"
msgstr "登录方式" msgstr "登录方式"
#: audits/models.py:82 #: audits/models.py:83
msgid "Login ip" msgid "Login ip"
msgstr "登录IP" msgstr "登录IP"
#: audits/models.py:83 #: audits/models.py:84
msgid "Login city" msgid "Login city"
msgstr "登录城市" msgstr "登录城市"
#: audits/models.py:84 #: audits/models.py:85
msgid "User agent" msgid "User agent"
msgstr "Agent" msgstr "Agent"
#: audits/models.py:85 audits/templates/audits/login_log_list.html:62 #: audits/models.py:86 audits/templates/audits/login_log_list.html:62
#: authentication/templates/authentication/_mfa_confirm_modal.html:14 #: authentication/templates/authentication/_mfa_confirm_modal.html:14
#: users/forms.py:174 users/models/user.py:397 #: users/forms.py:174 users/models/user.py:404
#: users/templates/users/first_login.html:45 #: users/templates/users/first_login.html:45
msgid "MFA" msgid "MFA"
msgstr "MFA" msgstr "MFA"
#: audits/models.py:86 audits/templates/audits/login_log_list.html:63 #: audits/models.py:87 audits/templates/audits/login_log_list.html:63
#: xpack/plugins/change_auth_plan/models.py:416 #: xpack/plugins/change_auth_plan/models.py:416
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:15 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:15
#: xpack/plugins/cloud/models.py:278 #: xpack/plugins/cloud/models.py:278
@ -2291,16 +2292,17 @@ msgstr "MFA"
msgid "Reason" msgid "Reason"
msgstr "原因" msgstr "原因"
#: audits/models.py:87 audits/templates/audits/login_log_list.html:64 #: audits/models.py:88 audits/templates/audits/login_log_list.html:64
#: orders/templates/orders/login_confirm_order_detail.html:35 #: orders/templates/orders/login_confirm_order_detail.html:35
#: orders/templates/orders/login_confirm_order_list.html:17 #: orders/templates/orders/login_confirm_order_list.html:17
#: orders/templates/orders/login_confirm_order_list.html:91
#: xpack/plugins/cloud/models.py:275 xpack/plugins/cloud/models.py:310 #: xpack/plugins/cloud/models.py:275 xpack/plugins/cloud/models.py:310
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:70 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:70
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:65 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:65
msgid "Status" msgid "Status"
msgstr "状态" msgstr "状态"
#: audits/models.py:88 #: audits/models.py:89
msgid "Date login" msgid "Date login"
msgstr "登录日期" msgstr "登录日期"
@ -2355,7 +2357,6 @@ msgstr "Agent"
#: audits/templates/audits/login_log_list.html:61 #: audits/templates/audits/login_log_list.html:61
#: orders/templates/orders/login_confirm_order_detail.html:58 #: orders/templates/orders/login_confirm_order_detail.html:58
#: orders/templates/orders/login_confirm_order_list.html:16
msgid "City" msgid "City"
msgstr "城市" msgstr "城市"
@ -2522,15 +2523,15 @@ msgid "Private Token"
msgstr "ssh密钥" msgstr "ssh密钥"
#: authentication/models.py:43 #: authentication/models.py:43
msgid "login_confirmation_setting" msgid "login_confirm_setting"
msgstr "" msgstr "登录复核设置"
#: authentication/models.py:44 #: authentication/models.py:44 users/templates/users/user_detail.html:265
msgid "Reviewers" msgid "Reviewers"
msgstr "" msgstr "审批人"
#: authentication/models.py:44 #: authentication/models.py:44
msgid "review_login_confirmation_settings" msgid "review_login_confirm_settings"
msgstr "" msgstr ""
#: authentication/models.py:53 #: authentication/models.py:53
@ -2571,14 +2572,14 @@ msgid "Show"
msgstr "显示" msgstr "显示"
#: authentication/templates/authentication/_access_key_modal.html:66 #: authentication/templates/authentication/_access_key_modal.html:66
#: users/models/user.py:332 users/templates/users/user_profile.html:94 #: users/models/user.py:339 users/templates/users/user_profile.html:94
#: users/templates/users/user_profile.html:163 #: users/templates/users/user_profile.html:163
#: users/templates/users/user_profile.html:166 #: users/templates/users/user_profile.html:166
msgid "Disable" msgid "Disable"
msgstr "禁用" msgstr "禁用"
#: authentication/templates/authentication/_access_key_modal.html:67 #: authentication/templates/authentication/_access_key_modal.html:67
#: users/models/user.py:333 users/templates/users/user_profile.html:92 #: users/models/user.py:340 users/templates/users/user_profile.html:92
#: users/templates/users/user_profile.html:170 #: users/templates/users/user_profile.html:170
msgid "Enable" msgid "Enable"
msgstr "启用" msgstr "启用"
@ -2838,8 +2839,9 @@ msgid ""
"configure nginx for url distribution,</div> </div>If you see this page, " "configure nginx for url distribution,</div> </div>If you see this page, "
"prove that you are not accessing the nginx listening port. Good luck.</div>" "prove that you are not accessing the nginx listening port. Good luck.</div>"
msgstr "" msgstr ""
"<div>Koko是单独部署的一个程序你需要部署Koko, 并确保nginx配置转发, </div><div>如果你看到了" "<div>Koko是单独部署的一个程序你需要部署Koko, 并确保nginx配置转发, </"
"这个页面证明你访问的不是nginx监听的端口祝你好运</div>" "div><div>如果你看到了这个页面证明你访问的不是nginx监听的端口祝你好运</"
"div>"
#: ops/api/celery.py:54 #: ops/api/celery.py:54
msgid "Waiting task start" msgid "Waiting task start"
@ -3113,6 +3115,7 @@ msgid "No system user was selected"
msgstr "没有选择系统用户" msgstr "没有选择系统用户"
#: ops/templates/ops/command_execution_create.html:296 orders/models.py:26 #: ops/templates/ops/command_execution_create.html:296 orders/models.py:26
#: orders/templates/orders/login_confirm_order_list.html:92
msgid "Pending" msgid "Pending"
msgstr "等待" msgstr "等待"
@ -3197,26 +3200,23 @@ msgid "Command execution"
msgstr "命令执行" msgstr "命令执行"
#: orders/models.py:12 orders/models.py:33 #: orders/models.py:12 orders/models.py:33
#, fuzzy
#| msgid "User is inactive"
msgid "User display name" msgid "User display name"
msgstr "用户已禁用" msgstr "用户显示名称"
#: orders/models.py:13 orders/models.py:36 #: orders/models.py:13 orders/models.py:36
msgid "Body" msgid "Body"
msgstr "" msgstr "内容"
#: orders/models.py:24 #: orders/models.py:24 orders/templates/orders/login_confirm_order_list.html:93
#, fuzzy
#| msgid "Accept"
msgid "Accepted" msgid "Accepted"
msgstr "接受" msgstr "已接受"
#: orders/models.py:25 #: orders/models.py:25 orders/templates/orders/login_confirm_order_list.html:94
msgid "Rejected" msgid "Rejected"
msgstr "拒绝" msgstr "拒绝"
#: orders/models.py:35 orders/templates/orders/login_confirm_order_list.html:13 #: orders/models.py:35 orders/templates/orders/login_confirm_order_list.html:14
#: orders/templates/orders/login_confirm_order_list.html:90
msgid "Title" msgid "Title"
msgstr "标题" msgstr "标题"
@ -3240,14 +3240,14 @@ msgstr "待处理人名称"
#: orders/serializers.py:21 #: orders/serializers.py:21
#: orders/templates/orders/login_confirm_order_detail.html:94 #: orders/templates/orders/login_confirm_order_detail.html:94
#: orders/templates/orders/login_confirm_order_list.html:53 #: orders/templates/orders/login_confirm_order_list.html:59
#: terminal/templates/terminal/terminal_list.html:78 #: terminal/templates/terminal/terminal_list.html:78
msgid "Accept" msgid "Accept"
msgstr "接受" msgstr "接受"
#: orders/serializers.py:22 #: orders/serializers.py:22
#: orders/templates/orders/login_confirm_order_detail.html:95 #: orders/templates/orders/login_confirm_order_detail.html:95
#: orders/templates/orders/login_confirm_order_list.html:54 #: orders/templates/orders/login_confirm_order_list.html:60
#: terminal/templates/terminal/terminal_list.html:80 #: terminal/templates/terminal/terminal_list.html:80
msgid "Reject" msgid "Reject"
msgstr "拒绝" msgstr "拒绝"
@ -3256,16 +3256,16 @@ msgstr "拒绝"
msgid "this order" msgid "this order"
msgstr "这个工单" msgstr "这个工单"
#: orders/signals_handler.py:21 #: orders/templates/orders/login_confirm_order_detail.html:75
#, fuzzy msgid "ago"
#| msgid "New node" msgstr "前"
msgid "New order"
msgstr "新节点"
# msgid "Update user" #: orders/utils.py:18
# msgstr "更新用户" msgid "New order"
#: orders/signals_handler.py:24 msgstr "新工单"
#, fuzzy, python-brace-format
#: orders/utils.py:21
#, python-brace-format
msgid "" msgid ""
"\n" "\n"
" <div>\n" " <div>\n"
@ -3275,6 +3275,8 @@ msgid ""
" <br/>\n" " <br/>\n"
" <b>User:</b> {user}\n" " <b>User:</b> {user}\n"
" <br/>\n" " <br/>\n"
" <b>Assignees:</b> {order.assignees_display}\n"
" <br/>\n"
" <b>City:</b> {order.city}\n" " <b>City:</b> {order.city}\n"
" <br/>\n" " <br/>\n"
" <b>IP:</b> {order.ip}\n" " <b>IP:</b> {order.ip}\n"
@ -3292,6 +3294,8 @@ msgstr ""
" <br/>\n" " <br/>\n"
" <b>用户:</b> {user}\n" " <b>用户:</b> {user}\n"
" <br/>\n" " <br/>\n"
" <b>待处理人:</b> {order.assignees_display}\n"
" <br/>\n"
" <b>城市:</b> {order.city}\n" " <b>城市:</b> {order.city}\n"
" <br/>\n" " <br/>\n"
" <b>IP:</b> {order.ip}\n" " <b>IP:</b> {order.ip}\n"
@ -3301,19 +3305,40 @@ msgstr ""
" </div>\n" " </div>\n"
" " " "
#: orders/templates/orders/login_confirm_order_detail.html:75 #: orders/utils.py:52
msgid "ago" msgid "Order has been reply"
msgstr "" msgstr "工单已被回复"
#: orders/templates/orders/login_confirm_order_list.html:83 #: orders/utils.py:53
#: users/templates/users/user_list.html:327 #, python-brace-format
msgid "User is expired" msgid ""
msgstr "用户已失效" "\n"
" <div>\n"
#: orders/templates/orders/login_confirm_order_list.html:86 " <p>Your order has been replay</p>\n"
#: users/templates/users/user_list.html:330 " <div>\n"
msgid "User is inactive" " <b>Title:</b> {order.title}\n"
msgstr "用户已禁用" " <br/>\n"
" <b>Assignee:</b> {order.assignee_display}\n"
" <br/>\n"
" <b>Status:</b> {order.status_display}\n"
" <br/>\n"
" </div>\n"
" </div>\n"
" "
msgstr ""
"\n"
" <div>\n"
" <p>您的工单已被回复</p>\n"
" <div>\n"
" <b>标题:</b> {order.title}\n"
" <br/>\n"
" <b>处理人:</b> {order.assignee_display}\n"
" <br/>\n"
" <b>状态:</b> {order.status_display}\n"
" <br/>\n"
" </div>\n"
" </div>\n"
" "
#: orders/views.py:15 orders/views.py:31 templates/_nav.html:127 #: orders/views.py:15 orders/views.py:31 templates/_nav.html:127
msgid "Orders" msgid "Orders"
@ -3351,7 +3376,7 @@ msgstr "提示RDP 协议不支持单独控制上传或下载文件"
#: perms/templates/perms/asset_permission_list.html:118 #: perms/templates/perms/asset_permission_list.html:118
#: perms/templates/perms/remote_app_permission_list.html:16 #: perms/templates/perms/remote_app_permission_list.html:16
#: templates/_nav.html:21 users/forms.py:293 users/models/group.py:26 #: templates/_nav.html:21 users/forms.py:293 users/models/group.py:26
#: users/models/user.py:381 users/templates/users/_select_user_modal.html:16 #: users/models/user.py:388 users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:218 #: users/templates/users/user_detail.html:218
#: users/templates/users/user_list.html:38 #: users/templates/users/user_list.html:38
#: xpack/plugins/orgs/templates/orgs/org_list.html:16 #: xpack/plugins/orgs/templates/orgs/org_list.html:16
@ -3393,7 +3418,7 @@ msgstr "资产授权"
#: perms/models/base.py:53 #: perms/models/base.py:53
#: perms/templates/perms/asset_permission_detail.html:90 #: perms/templates/perms/asset_permission_detail.html:90
#: perms/templates/perms/remote_app_permission_detail.html:82 #: perms/templates/perms/remote_app_permission_detail.html:82
#: users/models/user.py:413 users/templates/users/user_detail.html:107 #: users/models/user.py:420 users/templates/users/user_detail.html:107
#: users/templates/users/user_profile.html:120 #: users/templates/users/user_profile.html:120
msgid "Date expired" msgid "Date expired"
msgstr "失效日期" msgstr "失效日期"
@ -3957,7 +3982,7 @@ msgid "Please submit the LDAP configuration before import"
msgstr "请先提交LDAP配置再进行导入" msgstr "请先提交LDAP配置再进行导入"
#: settings/templates/settings/_ldap_list_users_modal.html:32 #: settings/templates/settings/_ldap_list_users_modal.html:32
#: users/models/user.py:377 users/templates/users/user_detail.html:71 #: users/models/user.py:384 users/templates/users/user_detail.html:71
#: users/templates/users/user_profile.html:59 #: users/templates/users/user_profile.html:59
msgid "Email" msgid "Email"
msgstr "邮件" msgstr "邮件"
@ -4362,7 +4387,7 @@ msgstr "批量命令"
msgid "Task monitor" msgid "Task monitor"
msgstr "任务监控" msgstr "任务监控"
#: templates/_nav.html:130 #: templates/_nav.html:130 users/templates/users/user_detail.html:257
msgid "Login confirm" msgid "Login confirm"
msgstr "登录复核" msgstr "登录复核"
@ -4748,7 +4773,7 @@ msgstr "你可以使用ssh客户端工具连接终端"
msgid "Could not reset self otp, use profile reset instead" msgid "Could not reset self otp, use profile reset instead"
msgstr "不能再该页面重置MFA, 请去个人信息页面重置" msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
#: users/forms.py:32 users/models/user.py:385 #: users/forms.py:32 users/models/user.py:392
#: users/templates/users/_select_user_modal.html:15 #: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:87 #: users/templates/users/user_detail.html:87
#: users/templates/users/user_list.html:37 #: users/templates/users/user_list.html:37
@ -4867,50 +4892,50 @@ msgstr "选择用户"
msgid "User auth from {}, go there change password" msgid "User auth from {}, go there change password"
msgstr "用户认证源来自 {}, 请去相应系统修改密码" msgstr "用户认证源来自 {}, 请去相应系统修改密码"
#: users/models/user.py:128 users/models/user.py:510 #: users/models/user.py:135 users/models/user.py:517
msgid "Administrator" msgid "Administrator"
msgstr "管理员" msgstr "管理员"
#: users/models/user.py:130 #: users/models/user.py:137
msgid "Application" msgid "Application"
msgstr "应用程序" msgstr "应用程序"
#: users/models/user.py:131 xpack/plugins/orgs/forms.py:30 #: users/models/user.py:138 xpack/plugins/orgs/forms.py:30
#: xpack/plugins/orgs/templates/orgs/org_list.html:14 #: xpack/plugins/orgs/templates/orgs/org_list.html:14
msgid "Auditor" msgid "Auditor"
msgstr "审计员" msgstr "审计员"
#: users/models/user.py:141 #: users/models/user.py:148
msgid "Org admin" msgid "Org admin"
msgstr "组织管理员" msgstr "组织管理员"
#: users/models/user.py:143 #: users/models/user.py:150
msgid "Org auditor" msgid "Org auditor"
msgstr "组织审计员" msgstr "组织审计员"
#: users/models/user.py:334 users/templates/users/user_profile.html:90 #: users/models/user.py:341 users/templates/users/user_profile.html:90
msgid "Force enable" msgid "Force enable"
msgstr "强制启用" msgstr "强制启用"
#: users/models/user.py:388 #: users/models/user.py:395
msgid "Avatar" msgid "Avatar"
msgstr "头像" msgstr "头像"
#: users/models/user.py:391 users/templates/users/user_detail.html:82 #: users/models/user.py:398 users/templates/users/user_detail.html:82
msgid "Wechat" msgid "Wechat"
msgstr "微信" msgstr "微信"
#: users/models/user.py:420 users/templates/users/user_detail.html:103 #: users/models/user.py:427 users/templates/users/user_detail.html:103
#: users/templates/users/user_list.html:39 #: users/templates/users/user_list.html:39
#: users/templates/users/user_profile.html:102 #: users/templates/users/user_profile.html:102
msgid "Source" msgid "Source"
msgstr "用户来源" msgstr "用户来源"
#: users/models/user.py:424 #: users/models/user.py:431
msgid "Date password last updated" msgid "Date password last updated"
msgstr "最后更新密码日期" msgstr "最后更新密码日期"
#: users/models/user.py:513 #: users/models/user.py:520
msgid "Administrator is the super user of system" msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员" msgstr "Administrator是初始的超级管理员"
@ -5082,7 +5107,7 @@ msgid "Always young, always with tears in my eyes. Stay foolish Stay hungry"
msgstr "永远年轻,永远热泪盈眶 stay foolish stay hungry" msgstr "永远年轻,永远热泪盈眶 stay foolish stay hungry"
#: users/templates/users/reset_password.html:46 #: users/templates/users/reset_password.html:46
#: users/templates/users/user_detail.html:379 users/utils.py:83 #: users/templates/users/user_detail.html:430 users/utils.py:83
msgid "Reset password" msgid "Reset password"
msgstr "重置密码" msgstr "重置密码"
@ -5199,7 +5224,7 @@ msgid "Send reset ssh key mail"
msgstr "发送重置密钥邮件" msgstr "发送重置密钥邮件"
#: users/templates/users/user_detail.html:203 #: users/templates/users/user_detail.html:203
#: users/templates/users/user_detail.html:467 #: users/templates/users/user_detail.html:518
msgid "Unblock user" msgid "Unblock user"
msgstr "解除登录限制" msgstr "解除登录限制"
@ -5207,46 +5232,46 @@ msgstr "解除登录限制"
msgid "Unblock" msgid "Unblock"
msgstr "解除" msgstr "解除"
#: users/templates/users/user_detail.html:322 #: users/templates/users/user_detail.html:373
msgid "Goto profile page enable MFA" msgid "Goto profile page enable MFA"
msgstr "请去个人信息页面启用自己的MFA" msgstr "请去个人信息页面启用自己的MFA"
#: users/templates/users/user_detail.html:378 #: users/templates/users/user_detail.html:429
msgid "An e-mail has been sent to the user`s mailbox." msgid "An e-mail has been sent to the user`s mailbox."
msgstr "已发送邮件到用户邮箱" msgstr "已发送邮件到用户邮箱"
#: users/templates/users/user_detail.html:389 #: users/templates/users/user_detail.html:440
msgid "This will reset the user password and send a reset mail" msgid "This will reset the user password and send a reset mail"
msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱" msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱"
#: users/templates/users/user_detail.html:404 #: users/templates/users/user_detail.html:455
msgid "" msgid ""
"The reset-ssh-public-key E-mail has been sent successfully. Please inform " "The reset-ssh-public-key E-mail has been sent successfully. Please inform "
"the user to update his new ssh public key." "the user to update his new ssh public key."
msgstr "重设密钥邮件将会发送到用户邮箱" msgstr "重设密钥邮件将会发送到用户邮箱"
#: users/templates/users/user_detail.html:405 #: users/templates/users/user_detail.html:456
msgid "Reset SSH public key" msgid "Reset SSH public key"
msgstr "重置SSH密钥" msgstr "重置SSH密钥"
#: users/templates/users/user_detail.html:415 #: users/templates/users/user_detail.html:466
msgid "This will reset the user public key and send a reset mail" msgid "This will reset the user public key and send a reset mail"
msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱" msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱"
#: users/templates/users/user_detail.html:433 #: users/templates/users/user_detail.html:484
msgid "Successfully updated the SSH public key." msgid "Successfully updated the SSH public key."
msgstr "更新ssh密钥成功" msgstr "更新ssh密钥成功"
#: users/templates/users/user_detail.html:434 #: users/templates/users/user_detail.html:485
#: users/templates/users/user_detail.html:438 #: users/templates/users/user_detail.html:489
msgid "User SSH public key update" msgid "User SSH public key update"
msgstr "ssh密钥" msgstr "ssh密钥"
#: users/templates/users/user_detail.html:483 #: users/templates/users/user_detail.html:534
msgid "After unlocking the user, the user can log in normally." msgid "After unlocking the user, the user can log in normally."
msgstr "解除用户登录限制后,此用户即可正常登录" msgstr "解除用户登录限制后,此用户即可正常登录"
#: users/templates/users/user_detail.html:497 #: users/templates/users/user_detail.html:548
msgid "Reset user MFA success" msgid "Reset user MFA success"
msgstr "重置用户MFA成功" msgstr "重置用户MFA成功"
@ -5299,6 +5324,14 @@ msgstr "删除"
msgid "User Deleting failed." msgid "User Deleting failed."
msgstr "用户删除失败" msgstr "用户删除失败"
#: users/templates/users/user_list.html:327
msgid "User is expired"
msgstr "用户已失效"
#: users/templates/users/user_list.html:330
msgid "User is inactive"
msgstr "用户已禁用"
#: users/templates/users/user_otp_authentication.html:6 #: users/templates/users/user_otp_authentication.html:6
#: users/templates/users/user_password_authentication.html:6 #: users/templates/users/user_password_authentication.html:6
msgid "Authenticate" msgid "Authenticate"

View File

@ -0,0 +1,59 @@
# Generated by Django 2.2.5 on 2019-10-31 10:23
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='LoginConfirmOrder',
fields=[
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('user_display', models.CharField(max_length=128, verbose_name='User display name')),
('title', models.CharField(max_length=256, verbose_name='Title')),
('body', models.TextField(verbose_name='Body')),
('assignee_display', models.CharField(blank=True, max_length=128, null=True, verbose_name='Assignee display name')),
('assignees_display', models.CharField(blank=True, max_length=128, verbose_name='Assignees display name')),
('type', models.CharField(choices=[('login_confirm', 'Login confirm')], max_length=16, verbose_name='Type')),
('status', models.CharField(choices=[('accepted', 'Accepted'), ('rejected', 'Rejected'), ('pending', 'Pending')], default='pending', max_length=16)),
('ip', models.GenericIPAddressField(blank=True, null=True)),
('city', models.CharField(blank=True, default='', max_length=16)),
('assignee', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='loginconfirmorder_handled', to=settings.AUTH_USER_MODEL, verbose_name='Assignee')),
('assignees', models.ManyToManyField(related_name='loginconfirmorder_assigned', to=settings.AUTH_USER_MODEL, verbose_name='Assignees')),
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='loginconfirmorder_requested', to=settings.AUTH_USER_MODEL, verbose_name='User')),
],
options={
'ordering': ('-date_created',),
'abstract': False,
},
),
migrations.CreateModel(
name='Comment',
fields=[
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('order_id', models.UUIDField()),
('user_display', models.CharField(max_length=128, verbose_name='User display name')),
('body', models.TextField(verbose_name='Body')),
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='comments', to=settings.AUTH_USER_MODEL, verbose_name='User')),
],
options={
'ordering': ('date_created',),
},
),
]

View File

@ -48,6 +48,14 @@ class BaseOrder(CommonModelMixin):
def comments(self): def comments(self):
return Comment.objects.filter(order_id=self.id) return Comment.objects.filter(order_id=self.id)
@property
def body_as_html(self):
return self.body.replace('\n', '<br/>')
@property
def status_display(self):
return self.get_status_display()
class Meta: class Meta:
abstract = True abstract = True
ordering = ('-date_created',) ordering = ('-date_created',)

View File

@ -1,59 +1,32 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.utils.translation import ugettext as _
from django.dispatch import receiver from django.dispatch import receiver
from django.db.models.signals import m2m_changed from django.db.models.signals import m2m_changed, post_save
from django.conf import settings
from common.tasks import send_mail_async from common.utils import get_logger
from common.utils import get_logger, reverse
from .models import LoginConfirmOrder from .models import LoginConfirmOrder
from .utils import (
send_login_confirm_order_mail_to_assignees,
send_login_confirm_action_mail_to_user
)
logger = get_logger(__name__) logger = get_logger(__name__)
def send_mail(order, assignees):
recipient_list = [user.email for user in assignees]
user = order.user
if not recipient_list:
logger.error("Order not has assignees: {}".format(order.id))
return
subject = '{}: {}'.format(_("New order"), order.title)
detail_url = reverse('orders:login-confirm-order-detail',
kwargs={'pk': order.id}, external=True)
message = _("""
<div>
<p>Your has a new order</p>
<div>
<b>Title:</b> {order.title}
<br/>
<b>User:</b> {user}
<br/>
<b>City:</b> {order.city}
<br/>
<b>IP:</b> {order.ip}
<br/>
<a href={url}>click here to review</a>
</div>
</div>
""").format(order=order, user=user, url=detail_url)
if settings.DEBUG:
try:
print(message)
except OSError:
pass
send_mail_async.delay(subject, message, recipient_list, html_message=message)
@receiver(m2m_changed, sender=LoginConfirmOrder.assignees.through) @receiver(m2m_changed, sender=LoginConfirmOrder.assignees.through)
def on_login_confirm_order_assignee_set(sender, instance=None, action=None, def on_login_confirm_order_assignees_set(sender, instance=None, action=None,
model=None, pk_set=None, **kwargs): model=None, pk_set=None, **kwargs):
print(">>>>>>>>>>>>>>>>>>>>>>>.")
print(action)
if action == 'post_add': if action == 'post_add':
print("<<<<<<<<<<<<<<<<<<<<")
logger.debug('New order create, send mail: {}'.format(instance.id)) logger.debug('New order create, send mail: {}'.format(instance.id))
assignees = model.objects.filter(pk__in=pk_set) assignees = model.objects.filter(pk__in=pk_set)
send_mail(instance, assignees) print(assignees)
send_login_confirm_order_mail_to_assignees(instance, assignees)
@receiver(post_save, sender=LoginConfirmOrder)
def on_login_confirm_order_status_change(sender, instance=None, created=False, **kwargs):
if created or instance.status == "pending":
return
logger.debug('Order changed, send mail: {}'.format(instance.id))
send_login_confirm_action_mail_to_user(instance)

View File

@ -14,7 +14,6 @@
<th class="text-center">{% trans 'Title' %}</th> <th class="text-center">{% trans 'Title' %}</th>
<th class="text-center">{% trans 'User' %}</th> <th class="text-center">{% trans 'User' %}</th>
<th class="text-center">{% trans 'IP' %}</th> <th class="text-center">{% trans 'IP' %}</th>
<th class="text-center">{% trans 'City' %}</th>
<th class="text-center">{% trans 'Status' %}</th> <th class="text-center">{% trans 'Status' %}</th>
<th class="text-center">{% trans 'Datetime' %}</th> <th class="text-center">{% trans 'Datetime' %}</th>
<th class="text-center">{% trans 'Action' %}</th> <th class="text-center">{% trans 'Action' %}</th>
@ -38,8 +37,12 @@ function initTable() {
cellData = htmlEscape(cellData); cellData = htmlEscape(cellData);
var detailBtn = '<a href="{% url "orders:login-confirm-order-detail" pk=DEFAULT_PK %}">' + cellData + '</a>'; var detailBtn = '<a href="{% url "orders:login-confirm-order-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detailBtn.replace("{{ DEFAULT_PK }}", rowData.id)); $(td).html(detailBtn.replace("{{ DEFAULT_PK }}", rowData.id));
}}, }},
{targets: 5, createdCell: function (td, cellData, rowData) { {targets: 3, createdCell: function (td, cellData, rowData) {
var d = cellData + "(" + rowData.city + ")";
$(td).html(d)
}},
{targets: 4, createdCell: function (td, cellData, rowData) {
if (cellData === "accepted") { if (cellData === "accepted") {
$(td).html('<i class="fa fa-check text-navy"></i>') $(td).html('<i class="fa fa-check text-navy"></i>')
} else if (cellData === "rejected") { } else if (cellData === "rejected") {
@ -48,13 +51,13 @@ function initTable() {
$(td).html('<i class="fa fa-spinner text-info"></i>') $(td).html('<i class="fa fa-spinner text-info"></i>')
} }
}}, }},
{targets: 6, createdCell: function (td, cellData) { {targets: 5, createdCell: function (td, cellData) {
var d = toSafeLocalDateStr(cellData); var d = toSafeLocalDateStr(cellData);
$(td).html(d) $(td).html(d)
}}, }},
{targets: 7, createdCell: function (td, cellData, rowData) { {targets: 6, createdCell: function (td, cellData, rowData) {
var acceptBtn = '<a class="btn btn-xs btn-info" data-uid="{{ DEFAULT_PK }}" >{% trans "Accept" %}</a> '; var acceptBtn = '<a class="btn btn-xs btn-info btn-action" data-action="accept" data-uid="{{ DEFAULT_PK }}" >{% trans "Accept" %}</a> ';
var rejectBtn = '<a class="btn btn-xs btn-danger " data-uid="{{ DEFAULT_PK }}" >{% trans "Reject" %}</a>'; var rejectBtn = '<a class="btn btn-xs btn-danger btn-action" data-action="reject" data-uid="{{ DEFAULT_PK }}" >{% trans "Reject" %}</a>';
acceptBtn = acceptBtn.replace('{{ DEFAULT_PK }}', cellData); acceptBtn = acceptBtn.replace('{{ DEFAULT_PK }}', cellData);
rejectBtn = rejectBtn.replace('{{ DEFAULT_PK }}', cellData); rejectBtn = rejectBtn.replace('{{ DEFAULT_PK }}', cellData);
var acceptBtnRef = $(acceptBtn); var acceptBtnRef = $(acceptBtn);
@ -68,10 +71,10 @@ function initTable() {
}}], }}],
ajax_url: '{% url "api-orders:login-confirm-order-list" %}', ajax_url: '{% url "api-orders:login-confirm-order-list" %}',
columns: [ columns: [
{data: "id"}, {data: "title", className: "text-left"}, {data: "user_display"}, {data: "id"}, {data: "title", className: "text-left"},
{data: "ip"}, {data: "city"}, {data: "user_display"}, {data: "ip"},
{data: "status", orderable: false}, {data: "status", orderable: false, width: "30px"},
{data: "date_created"}, {data: "date_created", width: "120px"},
{data: "id", orderable: false, width: "100px"} {data: "id", orderable: false, width: "100px"}
], ],
op_html: $('#actions').html() op_html: $('#actions').html()
@ -82,7 +85,6 @@ function initTable() {
$(document).ready(function(){ $(document).ready(function(){
initTable(); initTable();
$('')
var menu = [ var menu = [
{title: "IP", value: "ip"}, {title: "IP", value: "ip"},
{title: "{% trans 'Title' %}", value: "title"}, {title: "{% trans 'Title' %}", value: "title"},
@ -93,12 +95,21 @@ $(document).ready(function(){
]} ]}
]; ];
initTableFilterDropdown('#login_confirm_order_list_table_filter input', menu) initTableFilterDropdown('#login_confirm_order_list_table_filter input', menu)
}).on('click', '.expired', function () { }).on('click', '.btn-action', function () {
var msg = '{% trans "User is expired" %}'; var actionCreateUrl = "{% url 'api-orders:login-confirm-order-create-action' pk=DEFAULT_PK %}";
toastr.error(msg) var orderId = $(this).data('uid');
}).on('click', '.inactive', function () { actionCreateUrl = actionCreateUrl.replace("{{ DEFAULT_PK }}", orderId);
var msg = '{% trans 'User is inactive' %}'; var action = $(this).data('action');
toastr.error(msg) var comment = '';
var data = {
url: actionCreateUrl,
method: 'POST',
body: JSON.stringify({action: action, comment: comment}),
success: function () {
window.location.reload();
}
};
requestApi(data);
}) })
</script> </script>
{% endblock %} {% endblock %}

View File

@ -1,2 +1,62 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.conf import settings
from django.utils.translation import ugettext as _
from common.utils import get_logger, reverse
from common.tasks import send_mail_async
logger = get_logger(__name__)
def send_login_confirm_order_mail_to_assignees(order, assignees):
recipient_list = [user.email for user in assignees]
user = order.user
if not recipient_list:
logger.error("Order not has assignees: {}".format(order.id))
return
subject = '{}: {}'.format(_("New order"), order.title)
detail_url = reverse('orders:login-confirm-order-detail',
kwargs={'pk': order.id}, external=True)
message = _("""
<div>
<p>Your has a new order</p>
<div>
<b>Title:</b> {order.title}
<br/>
<b>User:</b> {user}
<br/>
<b>Assignees:</b> {order.assignees_display}
<br/>
<b>City:</b> {order.city}
<br/>
<b>IP:</b> {order.ip}
<br/>
<a href={url}>click here to review</a>
</div>
</div>
""").format(order=order, user=user, url=detail_url)
send_mail_async.delay(subject, message, recipient_list, html_message=message)
def send_login_confirm_action_mail_to_user(order):
if not order.user:
logger.error("Order not has user: {}".format(order.id))
return
user = order.user
recipient_list = [user.email]
subject = '{}: {}'.format(_("Order has been reply"), order.title)
message = _("""
<div>
<p>Your order has been replay</p>
<div>
<b>Title:</b> {order.title}
<br/>
<b>Assignee:</b> {order.assignee_display}
<br/>
<b>Status:</b> {order.status_display}
<br/>
</div>
</div>
""").format(order=order)
send_mail_async.delay(subject, message, recipient_list, html_message=message)

View File

@ -416,6 +416,9 @@ function makeLabel(data) {
function parseTableFilter(value) { function parseTableFilter(value) {
var cleanValues = []; var cleanValues = [];
if (!value) {
return {}
}
var valuesArray = value.split(':'); var valuesArray = value.split(':');
for (var i=0; i<valuesArray.length; i++) { for (var i=0; i<valuesArray.length; i++) {
var v = valuesArray[i].trim(); var v = valuesArray[i].trim();

View File

@ -55,9 +55,6 @@
<div class="col-md-6"> <div class="col-md-6">
{% include '_copyright.html' %} {% include '_copyright.html' %}
</div> </div>
<div class="col-md-6 text-right">
<small>2014-2019</small>
</div>
</div> </div>
</div> </div>
</body> </body>

View File

@ -117,6 +117,13 @@ class AuthMixin:
return True return True
return False return False
def get_login_confirm_setting(self):
if hasattr(self, 'login_confirm_setting'):
s = self.login_confirm_setting
if s.reviewers.all().count() and s.is_active:
return s
return False
class RoleMixin: class RoleMixin:
ROLE_ADMIN = 'Admin' ROLE_ADMIN = 'Admin'

View File

@ -7,6 +7,7 @@
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet"> <link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script> <script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script> <script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
<script src="{% static "js/vue.min.js" %}"></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
@ -212,46 +213,82 @@
</div> </div>
</div> </div>
{% if user_object.is_current_org_admin %} {% if user_object.is_current_org_admin or user_object.is_superuser %}
<div class="panel panel-info"> <div class="panel panel-info">
<div class="panel-heading"> <div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'User group' %} <i class="fa fa-info-circle"></i> {% trans 'User group' %}
</div>
<div class="panel-body">
<table class="table group_edit">
<tbody>
<form>
<tr>
<td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Join user groups' %}" id="groups_selected" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for group in groups %}
<option value="{{ group.id }}" id="opt_{{ group.id }}" >{{ group.name }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td colspan="2" class="no-borders">
<button type="button" class="btn btn-info btn-small" id="btn_join_group">{% trans 'Join' %}</button>
</td>
</tr>
</form>
{% for group in user_object.groups.all %}
<tr>
<td >
<b class="bdg_group" data-gid={{ group.id }}>{{ group.name }}</b>
</td>
<td>
<button class="btn btn-danger pull-right btn-xs btn_leave_group" type="button"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div> </div>
<div class="panel-body">
<table class="table group_edit">
<tbody>
<form>
<tr>
<td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Join user groups' %}" id="groups_selected" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for group in groups %}
<option value="{{ group.id }}" id="opt_{{ group.id }}" >{{ group.name }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td colspan="2" class="no-borders">
<button type="button" class="btn btn-info btn-small" id="btn_join_group">{% trans 'Join' %}</button>
</td>
</tr>
</form>
{% for group in user_object.groups.all %}
<tr>
<td >
<b class="bdg_group" data-gid={{ group.id }}>{{ group.name }}</b>
</td>
<td>
<button class="btn btn-danger pull-right btn-xs btn_leave_group" type="button"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %} {% endif %}
<div class="panel panel-warning">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Login confirm' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<form>
<tr>
<td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Reviewers' %}" id="id_assignees" class="users-select2" style="width: 100%" multiple="" tabindex="4">
</select>
</td>
</tr>
<tr>
<td colspan="2" class="no-borders">
<button type="button" class="btn btn-warning btn-small" id="btn_reviewer_confirm">{% trans 'Confirm' %}</button>
</td>
</tr>
</form>
{% if user_object.get_login_confirm_setting %}
{% for u in user_object.login_confirm_setting.reviewers.all %}
<tr>
<td >
<b class="bdg_reviewer">{{ u }}</b>
</td>
<td>
<button class="btn btn-danger pull-right btn-xs btn-leave-reviewer" data-uid={{ u.id }} type="button"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -263,6 +300,7 @@
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
jumpserver.nodes_selected = {}; jumpserver.nodes_selected = {};
var usersSelect2;
function updateUserGroups(groups) { function updateUserGroups(groups) {
var the_url = "{% url 'api-users:user-update-group' pk=user_object.id %}"; var the_url = "{% url 'api-users:user-update-group' pk=user_object.id %}";
@ -293,6 +331,19 @@ function updateUserGroups(groups) {
}); });
} }
function updateUserLoginReviewer(reviewers) {
var url = "{% url 'api-auth:login-confirm-setting-update' user_id=user_object.id %}";
var data = {reviewers: reviewers};
requestApi({
url: url,
data: JSON.stringify(data),
method: 'PATCH',
success: function () {
window.location.reload();
}
})
}
$(document).ready(function() { $(document).ready(function() {
$('.select2').select2() $('.select2').select2()
.on('select2:select', function(evt) { .on('select2:select', function(evt) {
@ -303,6 +354,7 @@ $(document).ready(function() {
var data = evt.params.data; var data = evt.params.data;
delete jumpserver.nodes_selected[data.id]; delete jumpserver.nodes_selected[data.id];
}); });
usersSelect2 = usersSelect2Init('.users-select2')
}) })
.on('click', '#is_active', function() { .on('click', '#is_active', function() {
var the_url = "{% url 'api-users:user-detail' pk=user_object.id %}"; var the_url = "{% url 'api-users:user-detail' pk=user_object.id %}";
@ -496,6 +548,32 @@ $(document).ready(function() {
method: "GET", method: "GET",
success_message: "{% trans 'Reset user MFA success' %}" success_message: "{% trans 'Reset user MFA success' %}"
}) })
}).on('click', '.btn-leave-reviewer', function () {
var reviewersId = [];
var removeReviewerId = $(this).data('uid');
$('.btn-leave-reviewer').each(function (i, v) {
var reviewerId = $(v).data('uid');
if (reviewerId !== removeReviewerId) {
reviewersId.push(reviewerId);
}
});
updateUserLoginReviewer(reviewersId);
}).on('click', '#btn_reviewer_confirm', function () {
var reviewersId = [];
$('.btn-leave-reviewer').each(function (i, v) {
var reviewerId = $(v).data('uid');
reviewersId.push(reviewerId);
});
var selectedId = usersSelect2.val();
if (selectedId.length === 0) {
return
}
selectedId.forEach(function (i) {
if (reviewersId.indexOf(i) === -1) {
reviewersId.push(i)
}
});
updateUserLoginReviewer(reviewersId);
}) })
</script> </script>
{% endblock %} {% endblock %}