mirror of https://github.com/jumpserver/jumpserver
Merge branch 'dev' of github.com:jumpserver/jumpserver into dev
commit
2d9ce16601
|
@ -263,7 +263,7 @@ JumpServer 采纳分布式架构,支持多机房跨区域部署,支持横向
|
||||||
|
|
||||||
|
|
||||||
## 致谢
|
## 致谢
|
||||||
- [Apache Guacamole](https://guacamole.apache.org/) Web页面连接 RDP, SSH, VNC协议设备,JumpServer 图形化连接依赖
|
- [Apache Guacamole](https://guacamole.apache.org/) Web页面连接 RDP, SSH, VNC协议设备,JumpServer 图形化组件 Lion 依赖
|
||||||
- [OmniDB](https://omnidb.org/) Web页面连接使用数据库,JumpServer Web数据库依赖
|
- [OmniDB](https://omnidb.org/) Web页面连接使用数据库,JumpServer Web数据库依赖
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -98,8 +98,8 @@ class SystemUserTaskApi(generics.CreateAPIView):
|
||||||
return task
|
return task
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def do_test(system_user):
|
def do_test(system_user, asset_ids):
|
||||||
task = test_system_user_connectivity_manual.delay(system_user)
|
task = test_system_user_connectivity_manual.delay(system_user, asset_ids)
|
||||||
return task
|
return task
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
|
@ -109,16 +109,20 @@ class SystemUserTaskApi(generics.CreateAPIView):
|
||||||
def perform_create(self, serializer):
|
def perform_create(self, serializer):
|
||||||
action = serializer.validated_data["action"]
|
action = serializer.validated_data["action"]
|
||||||
asset = serializer.validated_data.get('asset')
|
asset = serializer.validated_data.get('asset')
|
||||||
assets = serializer.validated_data.get('assets') or []
|
|
||||||
|
if asset:
|
||||||
|
assets = [asset]
|
||||||
|
else:
|
||||||
|
assets = serializer.validated_data.get('assets') or []
|
||||||
|
|
||||||
|
asset_ids = [asset.id for asset in assets]
|
||||||
|
asset_ids = asset_ids if asset_ids else None
|
||||||
|
|
||||||
system_user = self.get_object()
|
system_user = self.get_object()
|
||||||
if action == 'push':
|
if action == 'push':
|
||||||
assets = [asset] if asset else assets
|
|
||||||
asset_ids = [asset.id for asset in assets]
|
|
||||||
asset_ids = asset_ids if asset_ids else None
|
|
||||||
task = self.do_push(system_user, asset_ids)
|
task = self.do_push(system_user, asset_ids)
|
||||||
else:
|
else:
|
||||||
task = self.do_test(system_user)
|
task = self.do_test(system_user, asset_ids)
|
||||||
data = getattr(serializer, '_data', {})
|
data = getattr(serializer, '_data', {})
|
||||||
data["task"] = task.id
|
data["task"] = task.id
|
||||||
setattr(serializer, '_data', data)
|
setattr(serializer, '_data', data)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import re
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from common.drf.serializers import AdaptedBulkListSerializer
|
from common.drf.serializers import AdaptedBulkListSerializer
|
||||||
from ..models import CommandFilter, CommandFilterRule, SystemUser
|
from ..models import CommandFilter, CommandFilterRule
|
||||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||||
from orgs.utils import tmp_to_root_org
|
from orgs.utils import tmp_to_root_org
|
||||||
from common.utils import get_object_or_none, lazyproperty
|
from common.utils import get_object_or_none, lazyproperty
|
||||||
|
@ -50,6 +50,20 @@ class CommandFilterRuleSerializer(BulkOrgResourceModelSerializer):
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
list_serializer_class = AdaptedBulkListSerializer
|
list_serializer_class = AdaptedBulkListSerializer
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.set_action_choices()
|
||||||
|
|
||||||
|
def set_action_choices(self):
|
||||||
|
from django.conf import settings
|
||||||
|
action = self.fields.get('action')
|
||||||
|
if not action:
|
||||||
|
return
|
||||||
|
choices = action._choices
|
||||||
|
if not settings.XPACK_ENABLED:
|
||||||
|
choices.pop(CommandFilterRule.ActionChoices.confirm, None)
|
||||||
|
action._choices = choices
|
||||||
|
|
||||||
# def validate_content(self, content):
|
# def validate_content(self, content):
|
||||||
# tp = self.initial_data.get("type")
|
# tp = self.initial_data.get("type")
|
||||||
# if tp == CommandFilterRule.TYPE_REGEX:
|
# if tp == CommandFilterRule.TYPE_REGEX:
|
||||||
|
|
|
@ -61,7 +61,9 @@ class GatewaySerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||||
fields_fk = ['domain']
|
fields_fk = ['domain']
|
||||||
fields = fields_small + fields_fk
|
fields = fields_small + fields_fk
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'password': {'validators': [NoSpecialChars()]}
|
'password': {'write_only': True, 'validators': [NoSpecialChars()]},
|
||||||
|
'private_key': {"write_only": True},
|
||||||
|
'public_key': {"write_only": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
|
@ -5,6 +5,7 @@ from collections import defaultdict
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
from assets.models import Asset
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from orgs.utils import tmp_to_org, org_aware_func
|
from orgs.utils import tmp_to_org, org_aware_func
|
||||||
from ..models import SystemUser
|
from ..models import SystemUser
|
||||||
|
@ -96,9 +97,12 @@ def test_system_user_connectivity_util(system_user, assets, task_name):
|
||||||
|
|
||||||
@shared_task(queue="ansible")
|
@shared_task(queue="ansible")
|
||||||
@org_aware_func("system_user")
|
@org_aware_func("system_user")
|
||||||
def test_system_user_connectivity_manual(system_user):
|
def test_system_user_connectivity_manual(system_user, asset_ids=None):
|
||||||
task_name = _("Test system user connectivity: {}").format(system_user)
|
task_name = _("Test system user connectivity: {}").format(system_user)
|
||||||
assets = system_user.get_related_assets()
|
if asset_ids:
|
||||||
|
assets = Asset.objects.filter(id__in=asset_ids)
|
||||||
|
else:
|
||||||
|
assets = system_user.get_related_assets()
|
||||||
test_system_user_connectivity_util(system_user, assets, task_name)
|
test_system_user_connectivity_util(system_user, assets, task_name)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ class DingTalkQRUnBindBase(APIView):
|
||||||
if not user.dingtalk_id:
|
if not user.dingtalk_id:
|
||||||
raise errors.DingTalkNotBound
|
raise errors.DingTalkNotBound
|
||||||
|
|
||||||
user.dingtalk_id = ''
|
user.dingtalk_id = None
|
||||||
user.save()
|
user.save()
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ class WeComQRUnBindBase(APIView):
|
||||||
if not user.wecom_id:
|
if not user.wecom_id:
|
||||||
raise errors.WeComNotBound
|
raise errors.WeComNotBound
|
||||||
|
|
||||||
user.wecom_id = ''
|
user.wecom_id = None
|
||||||
user.save()
|
user.save()
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.core.cache import cache
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from six import text_type
|
from six import text_type
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.backends import ModelBackend
|
from django.contrib.auth.backends import ModelBackend as DJModelBackend
|
||||||
from rest_framework import HTTP_HEADER_ENCODING
|
from rest_framework import HTTP_HEADER_ENCODING
|
||||||
from rest_framework import authentication, exceptions
|
from rest_framework import authentication, exceptions
|
||||||
from common.auth import signature
|
from common.auth import signature
|
||||||
|
@ -25,6 +25,11 @@ def get_request_date_header(request):
|
||||||
return date
|
return date
|
||||||
|
|
||||||
|
|
||||||
|
class ModelBackend(DJModelBackend):
|
||||||
|
def user_can_authenticate(self, user):
|
||||||
|
return user.is_valid
|
||||||
|
|
||||||
|
|
||||||
class AccessKeyAuthentication(authentication.BaseAuthentication):
|
class AccessKeyAuthentication(authentication.BaseAuthentication):
|
||||||
"""App使用Access key进行签名认证, 目前签名算法比较简单,
|
"""App使用Access key进行签名认证, 目前签名算法比较简单,
|
||||||
app注册或者手动建立后,会生成 access_key_id 和 access_key_secret,
|
app注册或者手动建立后,会生成 access_key_id 和 access_key_secret,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import urllib
|
||||||
|
|
||||||
from django.http.response import HttpResponseRedirect
|
from django.http.response import HttpResponseRedirect
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
from django.views import View
|
from django.views import View
|
||||||
|
|
|
@ -2,7 +2,7 @@ import urllib
|
||||||
|
|
||||||
from django.http.response import HttpResponseRedirect
|
from django.http.response import HttpResponseRedirect
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
from django.views import View
|
from django.views import View
|
||||||
|
|
|
@ -189,6 +189,7 @@ class DatesLoginMetricMixin:
|
||||||
def get_dates_login_times_top10_users(self):
|
def get_dates_login_times_top10_users(self):
|
||||||
users = self.sessions_queryset.values("user_id") \
|
users = self.sessions_queryset.values("user_id") \
|
||||||
.annotate(total=Count("user_id")) \
|
.annotate(total=Count("user_id")) \
|
||||||
|
.annotate(user=Max('user')) \
|
||||||
.annotate(last=Max("date_start")).order_by("-total")[:10]
|
.annotate(last=Max("date_start")).order_by("-total")[:10]
|
||||||
for user in users:
|
for user in users:
|
||||||
user['last'] = str(user['last'])
|
user['last'] = str(user['last'])
|
||||||
|
|
|
@ -120,7 +120,7 @@ LOGIN_CONFIRM_ENABLE = CONFIG.LOGIN_CONFIRM_ENABLE
|
||||||
OTP_IN_RADIUS = CONFIG.OTP_IN_RADIUS
|
OTP_IN_RADIUS = CONFIG.OTP_IN_RADIUS
|
||||||
|
|
||||||
|
|
||||||
AUTH_BACKEND_MODEL = 'django.contrib.auth.backends.ModelBackend'
|
AUTH_BACKEND_MODEL = 'authentication.backends.api.ModelBackend'
|
||||||
AUTH_BACKEND_PUBKEY = 'authentication.backends.pubkey.PublicKeyAuthBackend'
|
AUTH_BACKEND_PUBKEY = 'authentication.backends.pubkey.PublicKeyAuthBackend'
|
||||||
AUTH_BACKEND_LDAP = 'authentication.backends.ldap.LDAPAuthorizationBackend'
|
AUTH_BACKEND_LDAP = 'authentication.backends.ldap.LDAPAuthorizationBackend'
|
||||||
AUTH_BACKEND_OIDC_PASSWORD = 'jms_oidc_rp.backends.OIDCAuthPasswordBackend'
|
AUTH_BACKEND_OIDC_PASSWORD = 'jms_oidc_rp.backends.OIDCAuthPasswordBackend'
|
||||||
|
|
Binary file not shown.
|
@ -3,19 +3,19 @@
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-05-17 16:17+0800\n"
|
"POT-Creation-Date: 2021-05-20 14:56+0800\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
|
||||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||||
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
||||||
"Language: zh_CN\n"
|
"Language: zh_CN\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"X-Generator: Poedit 2.4.3\n"
|
||||||
|
|
||||||
#: acls/models/base.py:25 acls/serializers/login_asset_acl.py:47
|
#: acls/models/base.py:25 acls/serializers/login_asset_acl.py:47
|
||||||
#: applications/models/application.py:11 assets/models/asset.py:142
|
#: applications/models/application.py:11 assets/models/asset.py:142
|
||||||
|
@ -25,7 +25,7 @@ msgstr ""
|
||||||
#: orgs/models.py:23 perms/models/base.py:49 settings/models.py:29
|
#: orgs/models.py:23 perms/models/base.py:49 settings/models.py:29
|
||||||
#: terminal/models/storage.py:23 terminal/models/storage.py:90
|
#: terminal/models/storage.py:23 terminal/models/storage.py:90
|
||||||
#: terminal/models/task.py:16 terminal/models/terminal.py:100
|
#: terminal/models/task.py:16 terminal/models/terminal.py:100
|
||||||
#: users/forms/profile.py:32 users/models/group.py:15 users/models/user.py:558
|
#: users/forms/profile.py:32 users/models/group.py:15 users/models/user.py:550
|
||||||
#: users/templates/users/_select_user_modal.html:13
|
#: users/templates/users/_select_user_modal.html:13
|
||||||
#: users/templates/users/user_asset_permission.html:37
|
#: users/templates/users/user_asset_permission.html:37
|
||||||
#: users/templates/users/user_asset_permission.html:154
|
#: users/templates/users/user_asset_permission.html:154
|
||||||
|
@ -61,7 +61,7 @@ msgstr "激活中"
|
||||||
#: orgs/models.py:26 perms/models/base.py:57 settings/models.py:34
|
#: orgs/models.py:26 perms/models/base.py:57 settings/models.py:34
|
||||||
#: terminal/models/storage.py:29 terminal/models/storage.py:96
|
#: terminal/models/storage.py:29 terminal/models/storage.py:96
|
||||||
#: terminal/models/terminal.py:114 tickets/models/ticket.py:73
|
#: terminal/models/terminal.py:114 tickets/models/ticket.py:73
|
||||||
#: users/models/group.py:16 users/models/user.py:591
|
#: users/models/group.py:16 users/models/user.py:583
|
||||||
#: xpack/plugins/change_auth_plan/models.py:77 xpack/plugins/cloud/models.py:35
|
#: xpack/plugins/change_auth_plan/models.py:77 xpack/plugins/cloud/models.py:35
|
||||||
#: xpack/plugins/cloud/models.py:98 xpack/plugins/gathered_user/models.py:26
|
#: xpack/plugins/cloud/models.py:98 xpack/plugins/gathered_user/models.py:26
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
|
@ -98,8 +98,8 @@ msgstr "动作"
|
||||||
#: perms/models/base.py:50 templates/index.html:78
|
#: perms/models/base.py:50 templates/index.html:78
|
||||||
#: terminal/backends/command/models.py:18
|
#: terminal/backends/command/models.py:18
|
||||||
#: terminal/backends/command/serializers.py:12 terminal/models/session.py:38
|
#: terminal/backends/command/serializers.py:12 terminal/models/session.py:38
|
||||||
#: tickets/models/comment.py:17 users/models/user.py:184
|
#: tickets/models/comment.py:17 users/models/user.py:176
|
||||||
#: users/models/user.py:746 users/models/user.py:772
|
#: users/models/user.py:738 users/models/user.py:764
|
||||||
#: users/serializers/group.py:20
|
#: users/serializers/group.py:20
|
||||||
#: users/templates/users/user_asset_permission.html:38
|
#: users/templates/users/user_asset_permission.html:38
|
||||||
#: users/templates/users/user_asset_permission.html:64
|
#: users/templates/users/user_asset_permission.html:64
|
||||||
|
@ -180,11 +180,11 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. "
|
||||||
#: applications/serializers/attrs/application_type/vmware_client.py:26
|
#: applications/serializers/attrs/application_type/vmware_client.py:26
|
||||||
#: assets/models/base.py:251 assets/models/gathered_user.py:15
|
#: assets/models/base.py:251 assets/models/gathered_user.py:15
|
||||||
#: audits/models.py:100 authentication/forms.py:15 authentication/forms.py:17
|
#: audits/models.py:100 authentication/forms.py:15 authentication/forms.py:17
|
||||||
#: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:556
|
#: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:548
|
||||||
#: users/templates/users/_select_user_modal.html:14
|
#: users/templates/users/_select_user_modal.html:14
|
||||||
#: xpack/plugins/change_auth_plan/models.py:47
|
#: xpack/plugins/change_auth_plan/models.py:47
|
||||||
#: xpack/plugins/change_auth_plan/models.py:278
|
#: xpack/plugins/change_auth_plan/models.py:278
|
||||||
#: xpack/plugins/cloud/serializers.py:51
|
#: xpack/plugins/cloud/serializers.py:71
|
||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr "用户名"
|
msgstr "用户名"
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ msgid "Cluster"
|
||||||
msgstr "集群"
|
msgstr "集群"
|
||||||
|
|
||||||
#: applications/serializers/attrs/application_category/db.py:11
|
#: applications/serializers/attrs/application_category/db.py:11
|
||||||
#: ops/models/adhoc.py:146 xpack/plugins/cloud/serializers.py:49
|
#: ops/models/adhoc.py:146 xpack/plugins/cloud/serializers.py:69
|
||||||
msgid "Host"
|
msgid "Host"
|
||||||
msgstr "主机"
|
msgstr "主机"
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ msgstr "主机"
|
||||||
#: applications/serializers/attrs/application_type/oracle.py:11
|
#: applications/serializers/attrs/application_type/oracle.py:11
|
||||||
#: applications/serializers/attrs/application_type/pgsql.py:11
|
#: applications/serializers/attrs/application_type/pgsql.py:11
|
||||||
#: assets/models/asset.py:188 assets/models/domain.py:53
|
#: assets/models/asset.py:188 assets/models/domain.py:53
|
||||||
#: xpack/plugins/cloud/serializers.py:50
|
#: xpack/plugins/cloud/serializers.py:70
|
||||||
msgid "Port"
|
msgid "Port"
|
||||||
msgstr "端口"
|
msgstr "端口"
|
||||||
|
|
||||||
|
@ -325,7 +325,7 @@ msgstr "目标URL"
|
||||||
#: xpack/plugins/change_auth_plan/models.py:68
|
#: xpack/plugins/change_auth_plan/models.py:68
|
||||||
#: xpack/plugins/change_auth_plan/models.py:190
|
#: xpack/plugins/change_auth_plan/models.py:190
|
||||||
#: xpack/plugins/change_auth_plan/models.py:285
|
#: xpack/plugins/change_auth_plan/models.py:285
|
||||||
#: xpack/plugins/cloud/serializers.py:53
|
#: xpack/plugins/cloud/serializers.py:73
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "密码"
|
msgstr "密码"
|
||||||
|
|
||||||
|
@ -407,7 +407,7 @@ msgstr "激活"
|
||||||
|
|
||||||
#: assets/models/asset.py:196 assets/models/cluster.py:19
|
#: assets/models/asset.py:196 assets/models/cluster.py:19
|
||||||
#: assets/models/user.py:66 templates/_nav.html:44
|
#: assets/models/user.py:66 templates/_nav.html:44
|
||||||
#: xpack/plugins/cloud/models.py:92 xpack/plugins/cloud/serializers.py:146
|
#: xpack/plugins/cloud/models.py:92 xpack/plugins/cloud/serializers.py:166
|
||||||
msgid "Admin user"
|
msgid "Admin user"
|
||||||
msgstr "管理用户"
|
msgstr "管理用户"
|
||||||
|
|
||||||
|
@ -483,7 +483,7 @@ msgstr "标签管理"
|
||||||
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:26
|
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:26
|
||||||
#: assets/models/cmd_filter.py:67 assets/models/group.py:21
|
#: assets/models/cmd_filter.py:67 assets/models/group.py:21
|
||||||
#: common/db/models.py:70 common/mixins/models.py:49 orgs/models.py:24
|
#: common/db/models.py:70 common/mixins/models.py:49 orgs/models.py:24
|
||||||
#: orgs/models.py:422 perms/models/base.py:55 users/models/user.py:599
|
#: orgs/models.py:422 perms/models/base.py:55 users/models/user.py:591
|
||||||
#: users/serializers/group.py:35 xpack/plugins/change_auth_plan/models.py:81
|
#: users/serializers/group.py:35 xpack/plugins/change_auth_plan/models.py:81
|
||||||
#: xpack/plugins/cloud/models.py:104 xpack/plugins/gathered_user/models.py:30
|
#: xpack/plugins/cloud/models.py:104 xpack/plugins/gathered_user/models.py:30
|
||||||
msgid "Created by"
|
msgid "Created by"
|
||||||
|
@ -497,7 +497,7 @@ msgstr "创建者"
|
||||||
#: assets/models/label.py:25 common/db/models.py:72 common/mixins/models.py:50
|
#: assets/models/label.py:25 common/db/models.py:72 common/mixins/models.py:50
|
||||||
#: ops/models/adhoc.py:38 ops/models/command.py:29 orgs/models.py:25
|
#: ops/models/adhoc.py:38 ops/models/command.py:29 orgs/models.py:25
|
||||||
#: orgs/models.py:420 perms/models/base.py:56 users/models/group.py:18
|
#: orgs/models.py:420 perms/models/base.py:56 users/models/group.py:18
|
||||||
#: users/models/user.py:773 xpack/plugins/cloud/models.py:107
|
#: users/models/user.py:765 xpack/plugins/cloud/models.py:107
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "创建日期"
|
msgstr "创建日期"
|
||||||
|
|
||||||
|
@ -543,7 +543,7 @@ msgstr "带宽"
|
||||||
msgid "Contact"
|
msgid "Contact"
|
||||||
msgstr "联系人"
|
msgstr "联系人"
|
||||||
|
|
||||||
#: assets/models/cluster.py:22 users/models/user.py:577
|
#: assets/models/cluster.py:22 users/models/user.py:569
|
||||||
msgid "Phone"
|
msgid "Phone"
|
||||||
msgstr "手机"
|
msgstr "手机"
|
||||||
|
|
||||||
|
@ -569,7 +569,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:758
|
#: users/models/user.py:750
|
||||||
msgid "System"
|
msgid "System"
|
||||||
msgstr "系统"
|
msgstr "系统"
|
||||||
|
|
||||||
|
@ -678,7 +678,7 @@ msgstr "ssh私钥"
|
||||||
#: users/templates/users/user_asset_permission.html:41
|
#: users/templates/users/user_asset_permission.html:41
|
||||||
#: users/templates/users/user_asset_permission.html:73
|
#: users/templates/users/user_asset_permission.html:73
|
||||||
#: users/templates/users/user_asset_permission.html:158
|
#: users/templates/users/user_asset_permission.html:158
|
||||||
#: xpack/plugins/cloud/models.py:89 xpack/plugins/cloud/serializers.py:147
|
#: xpack/plugins/cloud/models.py:89 xpack/plugins/cloud/serializers.py:167
|
||||||
msgid "Node"
|
msgid "Node"
|
||||||
msgstr "节点"
|
msgstr "节点"
|
||||||
|
|
||||||
|
@ -814,11 +814,11 @@ msgid "Backend"
|
||||||
msgstr "后端"
|
msgstr "后端"
|
||||||
|
|
||||||
#: assets/serializers/asset_user.py:80 users/forms/profile.py:160
|
#: assets/serializers/asset_user.py:80 users/forms/profile.py:160
|
||||||
#: users/models/user.py:588 users/templates/users/user_password_update.html:48
|
#: users/models/user.py:580 users/templates/users/user_password_update.html:48
|
||||||
msgid "Public key"
|
msgid "Public key"
|
||||||
msgstr "SSH公钥"
|
msgstr "SSH公钥"
|
||||||
|
|
||||||
#: assets/serializers/asset_user.py:84 users/models/user.py:585
|
#: assets/serializers/asset_user.py:84 users/models/user.py:577
|
||||||
msgid "Private key"
|
msgid "Private key"
|
||||||
msgstr "ssh私钥"
|
msgstr "ssh私钥"
|
||||||
|
|
||||||
|
@ -949,7 +949,7 @@ msgid ""
|
||||||
msgstr "自检程序已经在运行,不能重复启动"
|
msgstr "自检程序已经在运行,不能重复启动"
|
||||||
|
|
||||||
#: assets/tasks/push_system_user.py:193
|
#: assets/tasks/push_system_user.py:193
|
||||||
#: assets/tasks/system_user_connectivity.py:89
|
#: assets/tasks/system_user_connectivity.py:90
|
||||||
msgid "System user is dynamic: {}"
|
msgid "System user is dynamic: {}"
|
||||||
msgstr "系统用户是动态的: {}"
|
msgstr "系统用户是动态的: {}"
|
||||||
|
|
||||||
|
@ -958,7 +958,7 @@ msgid "Start push system user for platform: [{}]"
|
||||||
msgstr "推送系统用户到平台: [{}]"
|
msgstr "推送系统用户到平台: [{}]"
|
||||||
|
|
||||||
#: assets/tasks/push_system_user.py:234
|
#: assets/tasks/push_system_user.py:234
|
||||||
#: assets/tasks/system_user_connectivity.py:81
|
#: assets/tasks/system_user_connectivity.py:82
|
||||||
msgid "Hosts count: {}"
|
msgid "Hosts count: {}"
|
||||||
msgstr "主机数量: {}"
|
msgstr "主机数量: {}"
|
||||||
|
|
||||||
|
@ -970,19 +970,19 @@ msgstr "推送系统用户到入资产: {}"
|
||||||
msgid "Push system users to asset: {}({}) => {}"
|
msgid "Push system users to asset: {}({}) => {}"
|
||||||
msgstr "推送系统用户到入资产: {}({}) => {}"
|
msgstr "推送系统用户到入资产: {}({}) => {}"
|
||||||
|
|
||||||
#: assets/tasks/system_user_connectivity.py:80
|
#: assets/tasks/system_user_connectivity.py:81
|
||||||
msgid "Start test system user connectivity for platform: [{}]"
|
msgid "Start test system user connectivity for platform: [{}]"
|
||||||
msgstr "开始测试系统用户在该系统平台的可连接性: [{}]"
|
msgstr "开始测试系统用户在该系统平台的可连接性: [{}]"
|
||||||
|
|
||||||
#: assets/tasks/system_user_connectivity.py:100
|
#: assets/tasks/system_user_connectivity.py:101
|
||||||
msgid "Test system user connectivity: {}"
|
msgid "Test system user connectivity: {}"
|
||||||
msgstr "测试系统用户可连接性: {}"
|
msgstr "测试系统用户可连接性: {}"
|
||||||
|
|
||||||
#: assets/tasks/system_user_connectivity.py:108
|
#: assets/tasks/system_user_connectivity.py:112
|
||||||
msgid "Test system user connectivity: {} => {}"
|
msgid "Test system user connectivity: {} => {}"
|
||||||
msgstr "测试系统用户可连接性: {} => {}"
|
msgstr "测试系统用户可连接性: {} => {}"
|
||||||
|
|
||||||
#: assets/tasks/system_user_connectivity.py:121
|
#: assets/tasks/system_user_connectivity.py:125
|
||||||
msgid "Test system user connectivity period: {}"
|
msgid "Test system user connectivity period: {}"
|
||||||
msgstr "定期测试系统用户可连接性: {}"
|
msgstr "定期测试系统用户可连接性: {}"
|
||||||
|
|
||||||
|
@ -1127,8 +1127,8 @@ msgstr "用户代理"
|
||||||
#: audits/models.py:105
|
#: audits/models.py:105
|
||||||
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
|
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
|
||||||
#: authentication/templates/authentication/login_otp.html:6
|
#: authentication/templates/authentication/login_otp.html:6
|
||||||
#: users/forms/profile.py:64 users/models/user.py:580
|
#: users/forms/profile.py:64 users/models/user.py:572
|
||||||
#: users/serializers/profile.py:104
|
#: users/serializers/profile.py:102
|
||||||
msgid "MFA"
|
msgid "MFA"
|
||||||
msgstr "多因子认证"
|
msgstr "多因子认证"
|
||||||
|
|
||||||
|
@ -1218,54 +1218,54 @@ msgstr "钉钉"
|
||||||
msgid "Code is invalid"
|
msgid "Code is invalid"
|
||||||
msgstr "Code无效"
|
msgstr "Code无效"
|
||||||
|
|
||||||
#: authentication/backends/api.py:52
|
#: authentication/backends/api.py:57
|
||||||
msgid "Invalid signature header. No credentials provided."
|
msgid "Invalid signature header. No credentials provided."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentication/backends/api.py:55
|
#: authentication/backends/api.py:60
|
||||||
msgid "Invalid signature header. Signature string should not contain spaces."
|
msgid "Invalid signature header. Signature string should not contain spaces."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentication/backends/api.py:62
|
#: authentication/backends/api.py:67
|
||||||
msgid "Invalid signature header. Format like AccessKeyId:Signature"
|
msgid "Invalid signature header. Format like AccessKeyId:Signature"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentication/backends/api.py:66
|
#: authentication/backends/api.py:71
|
||||||
msgid ""
|
msgid ""
|
||||||
"Invalid signature header. Signature string should not contain invalid "
|
"Invalid signature header. Signature string should not contain invalid "
|
||||||
"characters."
|
"characters."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentication/backends/api.py:86 authentication/backends/api.py:102
|
#: authentication/backends/api.py:91 authentication/backends/api.py:107
|
||||||
msgid "Invalid signature."
|
msgid "Invalid signature."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentication/backends/api.py:93
|
#: authentication/backends/api.py:98
|
||||||
msgid "HTTP header: Date not provide or not %a, %d %b %Y %H:%M:%S GMT"
|
msgid "HTTP header: Date not provide or not %a, %d %b %Y %H:%M:%S GMT"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentication/backends/api.py:98
|
#: authentication/backends/api.py:103
|
||||||
msgid "Expired, more than 15 minutes"
|
msgid "Expired, more than 15 minutes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentication/backends/api.py:105
|
#: authentication/backends/api.py:110
|
||||||
msgid "User disabled."
|
msgid "User disabled."
|
||||||
msgstr "用户已禁用"
|
msgstr "用户已禁用"
|
||||||
|
|
||||||
#: authentication/backends/api.py:123
|
#: authentication/backends/api.py:128
|
||||||
msgid "Invalid token header. No credentials provided."
|
msgid "Invalid token header. No credentials provided."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentication/backends/api.py:126
|
#: authentication/backends/api.py:131
|
||||||
msgid "Invalid token header. Sign string should not contain spaces."
|
msgid "Invalid token header. Sign string should not contain spaces."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentication/backends/api.py:133
|
#: authentication/backends/api.py:138
|
||||||
msgid ""
|
msgid ""
|
||||||
"Invalid token header. Sign string should not contain invalid characters."
|
"Invalid token header. Sign string should not contain invalid characters."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentication/backends/api.py:144
|
#: authentication/backends/api.py:149
|
||||||
msgid "Invalid token or cache refreshed."
|
msgid "Invalid token or cache refreshed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1437,13 +1437,13 @@ msgid "Show"
|
||||||
msgstr "显示"
|
msgstr "显示"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_access_key_modal.html:66
|
#: authentication/templates/authentication/_access_key_modal.html:66
|
||||||
#: users/models/user.py:470 users/serializers/profile.py:101
|
#: users/models/user.py:462 users/serializers/profile.py:99
|
||||||
#: users/templates/users/user_verify_mfa.html:32
|
#: users/templates/users/user_verify_mfa.html:32
|
||||||
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:471 users/serializers/profile.py:102
|
#: users/models/user.py:463 users/serializers/profile.py:100
|
||||||
msgid "Enable"
|
msgid "Enable"
|
||||||
msgstr "启用"
|
msgstr "启用"
|
||||||
|
|
||||||
|
@ -1547,48 +1547,56 @@ msgstr "返回"
|
||||||
msgid "Copy success"
|
msgid "Copy success"
|
||||||
msgstr "复制成功"
|
msgstr "复制成功"
|
||||||
|
|
||||||
#: authentication/views/dingtalk.py:41 authentication/views/wecom.py:41
|
#: authentication/views/dingtalk.py:41
|
||||||
|
msgid "DingTalk Error, Please contact your system administrator"
|
||||||
|
msgstr "钉钉错误,请联系系统管理员"
|
||||||
|
|
||||||
|
#: authentication/views/dingtalk.py:44
|
||||||
|
msgid "DingTalk Error"
|
||||||
|
msgstr "钉钉错误"
|
||||||
|
|
||||||
|
#: authentication/views/dingtalk.py:56 authentication/views/wecom.py:56
|
||||||
msgid "You've been hacked"
|
msgid "You've been hacked"
|
||||||
msgstr "你被攻击了"
|
msgstr "你被攻击了"
|
||||||
|
|
||||||
#: authentication/views/dingtalk.py:77
|
#: authentication/views/dingtalk.py:92
|
||||||
msgid "DingTalk is already bound"
|
msgid "DingTalk is already bound"
|
||||||
msgstr "钉钉已经绑定"
|
msgstr "钉钉已经绑定"
|
||||||
|
|
||||||
#: authentication/views/dingtalk.py:90 authentication/views/wecom.py:89
|
#: authentication/views/dingtalk.py:105 authentication/views/wecom.py:104
|
||||||
msgid "Please verify your password first"
|
msgid "Please verify your password first"
|
||||||
msgstr "请检查密码"
|
msgstr "请检查密码"
|
||||||
|
|
||||||
#: authentication/views/dingtalk.py:114 authentication/views/wecom.py:113
|
#: authentication/views/dingtalk.py:129 authentication/views/wecom.py:128
|
||||||
msgid "Invalid user_id"
|
msgid "Invalid user_id"
|
||||||
msgstr "无效的 user_id"
|
msgstr "无效的 user_id"
|
||||||
|
|
||||||
#: authentication/views/dingtalk.py:130
|
#: authentication/views/dingtalk.py:145
|
||||||
msgid "DingTalk query user failed"
|
msgid "DingTalk query user failed"
|
||||||
msgstr "钉钉查询用户失败"
|
msgstr "钉钉查询用户失败"
|
||||||
|
|
||||||
#: authentication/views/dingtalk.py:139
|
#: authentication/views/dingtalk.py:154
|
||||||
msgid "The DingTalk is already bound to another user"
|
msgid "The DingTalk is already bound to another user"
|
||||||
msgstr "该钉钉已经绑定其他用户"
|
msgstr "该钉钉已经绑定其他用户"
|
||||||
|
|
||||||
#: authentication/views/dingtalk.py:144 authentication/views/dingtalk.py:227
|
#: authentication/views/dingtalk.py:159 authentication/views/dingtalk.py:242
|
||||||
#: authentication/views/dingtalk.py:228
|
#: authentication/views/dingtalk.py:243
|
||||||
msgid "Binding DingTalk successfully"
|
msgid "Binding DingTalk successfully"
|
||||||
msgstr "绑定 钉钉 成功"
|
msgstr "绑定 钉钉 成功"
|
||||||
|
|
||||||
#: authentication/views/dingtalk.py:196
|
#: authentication/views/dingtalk.py:211
|
||||||
msgid "Failed to get user from DingTalk"
|
msgid "Failed to get user from DingTalk"
|
||||||
msgstr "从钉钉获取用户失败"
|
msgstr "从钉钉获取用户失败"
|
||||||
|
|
||||||
#: authentication/views/dingtalk.py:202
|
#: authentication/views/dingtalk.py:217
|
||||||
msgid "DingTalk is not bound"
|
msgid "DingTalk is not bound"
|
||||||
msgstr "钉钉没有绑定"
|
msgstr "钉钉没有绑定"
|
||||||
|
|
||||||
#: authentication/views/dingtalk.py:203 authentication/views/wecom.py:201
|
#: authentication/views/dingtalk.py:218 authentication/views/wecom.py:216
|
||||||
msgid "Please login with a password and then bind the WeCom"
|
msgid "Please login with a password and then bind the WeCom"
|
||||||
msgstr "请使用密码登录,然后绑定企业微信"
|
msgstr "请使用密码登录,然后绑定企业微信"
|
||||||
|
|
||||||
#: authentication/views/dingtalk.py:245 authentication/views/dingtalk.py:246
|
#: authentication/views/dingtalk.py:260 authentication/views/dingtalk.py:261
|
||||||
msgid "Binding DingTalk failed"
|
msgid "Binding DingTalk failed"
|
||||||
msgstr "绑定钉钉失败"
|
msgstr "绑定钉钉失败"
|
||||||
|
|
||||||
|
@ -1624,32 +1632,40 @@ msgstr "退出登录成功"
|
||||||
msgid "Logout success, return login page"
|
msgid "Logout success, return login page"
|
||||||
msgstr "退出登录成功,返回到登录页面"
|
msgstr "退出登录成功,返回到登录页面"
|
||||||
|
|
||||||
#: authentication/views/wecom.py:76
|
#: authentication/views/wecom.py:41
|
||||||
|
msgid "WeCom Error, Please contact your system administrator"
|
||||||
|
msgstr "企业微信错误,请联系系统管理员"
|
||||||
|
|
||||||
|
#: authentication/views/wecom.py:44
|
||||||
|
msgid "WeCom Error"
|
||||||
|
msgstr "企业微信错误"
|
||||||
|
|
||||||
|
#: authentication/views/wecom.py:91
|
||||||
msgid "WeCom is already bound"
|
msgid "WeCom is already bound"
|
||||||
msgstr "企业微信已经绑定"
|
msgstr "企业微信已经绑定"
|
||||||
|
|
||||||
#: authentication/views/wecom.py:128
|
#: authentication/views/wecom.py:143
|
||||||
msgid "WeCom query user failed"
|
msgid "WeCom query user failed"
|
||||||
msgstr "企业微信查询用户失败"
|
msgstr "企业微信查询用户失败"
|
||||||
|
|
||||||
#: authentication/views/wecom.py:137
|
#: authentication/views/wecom.py:152
|
||||||
msgid "The WeCom is already bound to another user"
|
msgid "The WeCom is already bound to another user"
|
||||||
msgstr "该企业微信已经绑定其他用户"
|
msgstr "该企业微信已经绑定其他用户"
|
||||||
|
|
||||||
#: authentication/views/wecom.py:142 authentication/views/wecom.py:225
|
#: authentication/views/wecom.py:157 authentication/views/wecom.py:240
|
||||||
#: authentication/views/wecom.py:226
|
#: authentication/views/wecom.py:241
|
||||||
msgid "Binding WeCom successfully"
|
msgid "Binding WeCom successfully"
|
||||||
msgstr "绑定 企业微信 成功"
|
msgstr "绑定 企业微信 成功"
|
||||||
|
|
||||||
#: authentication/views/wecom.py:194
|
#: authentication/views/wecom.py:209
|
||||||
msgid "Failed to get user from WeCom"
|
msgid "Failed to get user from WeCom"
|
||||||
msgstr "从企业微信获取用户失败"
|
msgstr "从企业微信获取用户失败"
|
||||||
|
|
||||||
#: authentication/views/wecom.py:200
|
#: authentication/views/wecom.py:215
|
||||||
msgid "WeCom is not bound"
|
msgid "WeCom is not bound"
|
||||||
msgstr "没有绑定企业微信"
|
msgstr "没有绑定企业微信"
|
||||||
|
|
||||||
#: authentication/views/wecom.py:243 authentication/views/wecom.py:244
|
#: authentication/views/wecom.py:258 authentication/views/wecom.py:259
|
||||||
msgid "Binding WeCom failed"
|
msgid "Binding WeCom failed"
|
||||||
msgstr "绑定企业微信失败"
|
msgstr "绑定企业微信失败"
|
||||||
|
|
||||||
|
@ -1675,7 +1691,7 @@ msgstr "对象"
|
||||||
msgid "The file content overflowed (The maximum length `{}` bytes)"
|
msgid "The file content overflowed (The maximum length `{}` bytes)"
|
||||||
msgstr "文件内容太大 (最大长度 `{}` 字节)"
|
msgstr "文件内容太大 (最大长度 `{}` 字节)"
|
||||||
|
|
||||||
#: common/drf/parsers/base.py:146
|
#: common/drf/parsers/base.py:148
|
||||||
msgid "Parse file error: {}"
|
msgid "Parse file error: {}"
|
||||||
msgstr "解析文件错误: {}"
|
msgstr "解析文件错误: {}"
|
||||||
|
|
||||||
|
@ -1811,36 +1827,36 @@ msgstr "没有该主机 {} 权限"
|
||||||
msgid "Operations"
|
msgid "Operations"
|
||||||
msgstr "运维"
|
msgstr "运维"
|
||||||
|
|
||||||
#: ops/mixin.py:29 ops/mixin.py:92 ops/mixin.py:160
|
#: ops/mixin.py:29 ops/mixin.py:92 ops/mixin.py:162
|
||||||
msgid "Cycle perform"
|
msgid "Cycle perform"
|
||||||
msgstr "周期执行"
|
msgstr "周期执行"
|
||||||
|
|
||||||
#: ops/mixin.py:33 ops/mixin.py:90 ops/mixin.py:109 ops/mixin.py:148
|
#: ops/mixin.py:33 ops/mixin.py:90 ops/mixin.py:109 ops/mixin.py:150
|
||||||
msgid "Regularly perform"
|
msgid "Regularly perform"
|
||||||
msgstr "定期执行"
|
msgstr "定期执行"
|
||||||
|
|
||||||
#: ops/mixin.py:106 ops/mixin.py:145
|
#: ops/mixin.py:106 ops/mixin.py:147
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:53
|
#: xpack/plugins/change_auth_plan/serializers.py:53
|
||||||
msgid "Periodic perform"
|
msgid "Periodic perform"
|
||||||
msgstr "定时执行"
|
msgstr "定时执行"
|
||||||
|
|
||||||
#: ops/mixin.py:111
|
#: ops/mixin.py:112
|
||||||
msgid "Interval"
|
msgid "Interval"
|
||||||
msgstr "间隔"
|
msgstr "间隔"
|
||||||
|
|
||||||
#: ops/mixin.py:120
|
#: ops/mixin.py:122
|
||||||
msgid "* Please enter a valid crontab expression"
|
msgid "* Please enter a valid crontab expression"
|
||||||
msgstr "* 请输入有效的 crontab 表达式"
|
msgstr "* 请输入有效的 crontab 表达式"
|
||||||
|
|
||||||
#: ops/mixin.py:127
|
#: ops/mixin.py:129
|
||||||
msgid "Range {} to {}"
|
msgid "Range {} to {}"
|
||||||
msgstr "输入在 {} - {} 范围之间"
|
msgstr "输入在 {} - {} 范围之间"
|
||||||
|
|
||||||
#: ops/mixin.py:138
|
#: ops/mixin.py:140
|
||||||
msgid "Require periodic or regularly perform setting"
|
msgid "Require periodic or regularly perform setting"
|
||||||
msgstr "需要周期或定期设置"
|
msgstr "需要周期或定期设置"
|
||||||
|
|
||||||
#: ops/mixin.py:149
|
#: ops/mixin.py:151
|
||||||
msgid ""
|
msgid ""
|
||||||
"eg: Every Sunday 03:05 run <5 3 * * 0> <br> Tips: Using 5 digits linux "
|
"eg: Every Sunday 03:05 run <5 3 * * 0> <br> Tips: Using 5 digits linux "
|
||||||
"crontab expressions <min hour day month week> (<a href='https://tool.lu/"
|
"crontab expressions <min hour day month week> (<a href='https://tool.lu/"
|
||||||
|
@ -1851,7 +1867,7 @@ msgstr ""
|
||||||
"分 时 日 月 星期> (<a href='https://tool.lu/crontab/' target='_blank'>在线工"
|
"分 时 日 月 星期> (<a href='https://tool.lu/crontab/' target='_blank'>在线工"
|
||||||
"具</a>) <br>注意: 如果同时设置了定期执行和周期执行,优先使用定期执行"
|
"具</a>) <br>注意: 如果同时设置了定期执行和周期执行,优先使用定期执行"
|
||||||
|
|
||||||
#: ops/mixin.py:160
|
#: ops/mixin.py:162
|
||||||
msgid "Tips: (Units: hour)"
|
msgid "Tips: (Units: hour)"
|
||||||
msgstr "提示:(单位: 时)"
|
msgstr "提示:(单位: 时)"
|
||||||
|
|
||||||
|
@ -1962,12 +1978,11 @@ msgstr "更新任务内容: {}"
|
||||||
msgid "Disk used more than 80%: {} => {}"
|
msgid "Disk used more than 80%: {} => {}"
|
||||||
msgstr "磁盘使用率超过 80%: {} => {}"
|
msgstr "磁盘使用率超过 80%: {} => {}"
|
||||||
|
|
||||||
#: orgs/api.py:76
|
#: orgs/api.py:79
|
||||||
#, python-brace-format
|
msgid "Have {} exists, Please delete"
|
||||||
msgid "Have `{model._meta.verbose_name}` exists, Please delete"
|
msgstr "{} 存在数据, 请先删除"
|
||||||
msgstr "`{model._meta.verbose_name}` 存在数据, 请先删除"
|
|
||||||
|
|
||||||
#: orgs/api.py:80
|
#: orgs/api.py:83
|
||||||
msgid "The current organization cannot be deleted"
|
msgid "The current organization cannot be deleted"
|
||||||
msgstr "当前组织不能被删除"
|
msgstr "当前组织不能被删除"
|
||||||
|
|
||||||
|
@ -1989,7 +2004,7 @@ msgstr "组织审计员"
|
||||||
msgid "GLOBAL"
|
msgid "GLOBAL"
|
||||||
msgstr "全局组织"
|
msgstr "全局组织"
|
||||||
|
|
||||||
#: orgs/models.py:419 users/models/user.py:568
|
#: orgs/models.py:419 users/models/user.py:560
|
||||||
#: users/templates/users/_select_user_modal.html:15
|
#: users/templates/users/_select_user_modal.html:15
|
||||||
msgid "Role"
|
msgid "Role"
|
||||||
msgstr "角色"
|
msgstr "角色"
|
||||||
|
@ -2002,7 +2017,7 @@ msgstr "管理员正在修改授权,请稍等"
|
||||||
msgid "The authorization cannot be revoked for the time being"
|
msgid "The authorization cannot be revoked for the time being"
|
||||||
msgstr "该授权暂时不能撤销"
|
msgstr "该授权暂时不能撤销"
|
||||||
|
|
||||||
#: perms/models/application_permission.py:27 users/models/user.py:185
|
#: perms/models/application_permission.py:27 users/models/user.py:177
|
||||||
msgid "Application"
|
msgid "Application"
|
||||||
msgstr "应用程序"
|
msgstr "应用程序"
|
||||||
|
|
||||||
|
@ -2061,7 +2076,7 @@ msgid "Favorite"
|
||||||
msgstr "收藏夹"
|
msgstr "收藏夹"
|
||||||
|
|
||||||
#: perms/models/base.py:51 templates/_nav.html:21 users/models/group.py:31
|
#: perms/models/base.py:51 templates/_nav.html:21 users/models/group.py:31
|
||||||
#: users/models/user.py:564 users/templates/users/_select_user_modal.html:16
|
#: users/models/user.py:556 users/templates/users/_select_user_modal.html:16
|
||||||
#: users/templates/users/user_asset_permission.html:39
|
#: users/templates/users/user_asset_permission.html:39
|
||||||
#: users/templates/users/user_asset_permission.html:67
|
#: users/templates/users/user_asset_permission.html:67
|
||||||
#: users/templates/users/user_database_app_permission.html:38
|
#: users/templates/users/user_database_app_permission.html:38
|
||||||
|
@ -2074,7 +2089,7 @@ msgstr "用户组"
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:77
|
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:77
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:43
|
#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:43
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:81
|
#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:81
|
||||||
#: users/models/user.py:596
|
#: users/models/user.py:588
|
||||||
msgid "Date expired"
|
msgid "Date expired"
|
||||||
msgstr "失效日期"
|
msgstr "失效日期"
|
||||||
|
|
||||||
|
@ -2096,15 +2111,15 @@ msgstr "用户名"
|
||||||
|
|
||||||
#: perms/serializers/asset/permission.py:47
|
#: perms/serializers/asset/permission.py:47
|
||||||
msgid "User groups name"
|
msgid "User groups name"
|
||||||
msgstr "用户组数量"
|
msgstr "用户组名称"
|
||||||
|
|
||||||
#: perms/serializers/asset/permission.py:48
|
#: perms/serializers/asset/permission.py:48
|
||||||
msgid "Assets name"
|
msgid "Assets name"
|
||||||
msgstr "资产名字"
|
msgstr "资产名称"
|
||||||
|
|
||||||
#: perms/serializers/asset/permission.py:50
|
#: perms/serializers/asset/permission.py:50
|
||||||
msgid "System users name"
|
msgid "System users name"
|
||||||
msgstr "系统用户名字"
|
msgstr "系统用户名称"
|
||||||
|
|
||||||
#: perms/serializers/asset/permission.py:70 users/serializers/user.py:81
|
#: perms/serializers/asset/permission.py:70 users/serializers/user.py:81
|
||||||
msgid "Is valid"
|
msgid "Is valid"
|
||||||
|
@ -2131,13 +2146,9 @@ msgstr "邮件已经发送{}, 请检查"
|
||||||
msgid "Welcome to the JumpServer open source Bastion Host"
|
msgid "Welcome to the JumpServer open source Bastion Host"
|
||||||
msgstr "欢迎使用JumpServer开源堡垒机"
|
msgstr "欢迎使用JumpServer开源堡垒机"
|
||||||
|
|
||||||
#: settings/api/dingtalk.py:29
|
#: settings/api/dingtalk.py:36 settings/api/wecom.py:36
|
||||||
msgid "AppSecret is required"
|
msgid "Test success"
|
||||||
msgstr "AppSecret 是必须的"
|
msgstr "测试成功"
|
||||||
|
|
||||||
#: settings/api/dingtalk.py:35 settings/api/wecom.py:35
|
|
||||||
msgid "OK"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: settings/api/ldap.py:189
|
#: settings/api/ldap.py:189
|
||||||
msgid "Get ldap users is None"
|
msgid "Get ldap users is None"
|
||||||
|
@ -2147,10 +2158,6 @@ msgstr "获取 LDAP 用户为 None"
|
||||||
msgid "Imported {} users successfully"
|
msgid "Imported {} users successfully"
|
||||||
msgstr "导入 {} 个用户成功"
|
msgstr "导入 {} 个用户成功"
|
||||||
|
|
||||||
#: settings/api/wecom.py:29
|
|
||||||
msgid "Secret is required"
|
|
||||||
msgstr "Secret 是必须的"
|
|
||||||
|
|
||||||
#: settings/models.py:123 users/templates/users/reset_password.html:29
|
#: settings/models.py:123 users/templates/users/reset_password.html:29
|
||||||
msgid "Setting"
|
msgid "Setting"
|
||||||
msgstr "设置"
|
msgstr "设置"
|
||||||
|
@ -2435,16 +2442,13 @@ msgstr ""
|
||||||
|
|
||||||
#: settings/serializers/settings.py:172
|
#: settings/serializers/settings.py:172
|
||||||
msgid "Number of repeated historical passwords"
|
msgid "Number of repeated historical passwords"
|
||||||
msgstr "历史密码可重复次数"
|
msgstr "不能设置近几次密码"
|
||||||
|
|
||||||
#: settings/serializers/settings.py:173
|
#: settings/serializers/settings.py:173
|
||||||
msgid ""
|
msgid ""
|
||||||
"Tip: When the user resets the password, it cannot be the previous n "
|
"Tip: When the user resets the password, it cannot be the previous n "
|
||||||
"historical passwords of the user (the value of n here is the value filled in "
|
"historical passwords of the user"
|
||||||
"the input box)"
|
msgstr "提示:用户重置密码时,不能为该用户前几次使用过的密码"
|
||||||
msgstr ""
|
|
||||||
"提示:用户重置密码时,不能为该用户前n次历史密码 (此处的n值即为输入框中填写的"
|
|
||||||
"值)"
|
|
||||||
|
|
||||||
#: settings/serializers/settings.py:177
|
#: settings/serializers/settings.py:177
|
||||||
msgid "Password minimum length"
|
msgid "Password minimum length"
|
||||||
|
@ -3040,19 +3044,19 @@ msgstr "登录了"
|
||||||
msgid "Filters"
|
msgid "Filters"
|
||||||
msgstr "过滤"
|
msgstr "过滤"
|
||||||
|
|
||||||
#: terminal/api/session.py:189
|
#: terminal/api/session.py:185
|
||||||
msgid "Session does not exist: {}"
|
msgid "Session does not exist: {}"
|
||||||
msgstr "会话不存在: {}"
|
msgstr "会话不存在: {}"
|
||||||
|
|
||||||
#: terminal/api/session.py:192
|
#: terminal/api/session.py:188
|
||||||
msgid "Session is finished or the protocol not supported"
|
msgid "Session is finished or the protocol not supported"
|
||||||
msgstr "会话已经完成或协议不支持"
|
msgstr "会话已经完成或协议不支持"
|
||||||
|
|
||||||
#: terminal/api/session.py:197
|
#: terminal/api/session.py:193
|
||||||
msgid "User does not exist: {}"
|
msgid "User does not exist: {}"
|
||||||
msgstr "用户不存在: {}"
|
msgstr "用户不存在: {}"
|
||||||
|
|
||||||
#: terminal/api/session.py:201
|
#: terminal/api/session.py:197
|
||||||
msgid "User does not have permission"
|
msgid "User does not have permission"
|
||||||
msgstr "用户没有权限"
|
msgstr "用户没有权限"
|
||||||
|
|
||||||
|
@ -3084,6 +3088,10 @@ msgstr "测试成功"
|
||||||
msgid "Test failure: Account invalid"
|
msgid "Test failure: Account invalid"
|
||||||
msgstr "测试失败: 账户无效"
|
msgstr "测试失败: 账户无效"
|
||||||
|
|
||||||
|
#: terminal/api/terminal.py:39
|
||||||
|
msgid "Have online sessions"
|
||||||
|
msgstr "有在线会话"
|
||||||
|
|
||||||
#: terminal/backends/command/es.py:27
|
#: terminal/backends/command/es.py:27
|
||||||
msgid "Invalid elasticsearch config"
|
msgid "Invalid elasticsearch config"
|
||||||
msgstr "无效的 Elasticsearch 配置"
|
msgstr "无效的 Elasticsearch 配置"
|
||||||
|
@ -3820,7 +3828,7 @@ msgstr "确认密码"
|
||||||
msgid "Password does not match"
|
msgid "Password does not match"
|
||||||
msgstr "密码不一致"
|
msgstr "密码不一致"
|
||||||
|
|
||||||
#: users/forms/profile.py:101 users/models/user.py:560
|
#: users/forms/profile.py:101 users/models/user.py:552
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "邮件"
|
msgstr "邮件"
|
||||||
|
|
||||||
|
@ -3852,48 +3860,48 @@ msgstr "复制你的公钥到这里"
|
||||||
msgid "Public key should not be the same as your old one."
|
msgid "Public key should not be the same as your old one."
|
||||||
msgstr "不能和原来的密钥相同"
|
msgstr "不能和原来的密钥相同"
|
||||||
|
|
||||||
#: users/forms/profile.py:149 users/serializers/profile.py:76
|
#: users/forms/profile.py:149 users/serializers/profile.py:74
|
||||||
#: users/serializers/profile.py:150 users/serializers/profile.py:163
|
#: users/serializers/profile.py:148 users/serializers/profile.py:161
|
||||||
msgid "Not a valid ssh public key"
|
msgid "Not a valid ssh public key"
|
||||||
msgstr "SSH密钥不合法"
|
msgstr "SSH密钥不合法"
|
||||||
|
|
||||||
#: users/models/user.py:182
|
#: users/models/user.py:174
|
||||||
msgid "System administrator"
|
msgid "System administrator"
|
||||||
msgstr "系统管理员"
|
msgstr "系统管理员"
|
||||||
|
|
||||||
#: users/models/user.py:183
|
#: users/models/user.py:175
|
||||||
msgid "System auditor"
|
msgid "System auditor"
|
||||||
msgstr "系统审计员"
|
msgstr "系统审计员"
|
||||||
|
|
||||||
#: users/models/user.py:472
|
#: users/models/user.py:464
|
||||||
msgid "Force enable"
|
msgid "Force enable"
|
||||||
msgstr "强制启用"
|
msgstr "强制启用"
|
||||||
|
|
||||||
#: users/models/user.py:537
|
#: users/models/user.py:529
|
||||||
msgid "Local"
|
msgid "Local"
|
||||||
msgstr "数据库"
|
msgstr "数据库"
|
||||||
|
|
||||||
#: users/models/user.py:571
|
#: users/models/user.py:563
|
||||||
msgid "Avatar"
|
msgid "Avatar"
|
||||||
msgstr "头像"
|
msgstr "头像"
|
||||||
|
|
||||||
#: users/models/user.py:574
|
#: users/models/user.py:566
|
||||||
msgid "Wechat"
|
msgid "Wechat"
|
||||||
msgstr "微信"
|
msgstr "微信"
|
||||||
|
|
||||||
#: users/models/user.py:604
|
#: users/models/user.py:596
|
||||||
msgid "Source"
|
msgid "Source"
|
||||||
msgstr "用户来源"
|
msgstr "用户来源"
|
||||||
|
|
||||||
#: users/models/user.py:608
|
#: users/models/user.py:600
|
||||||
msgid "Date password last updated"
|
msgid "Date password last updated"
|
||||||
msgstr "最后更新密码日期"
|
msgstr "最后更新密码日期"
|
||||||
|
|
||||||
#: users/models/user.py:754
|
#: users/models/user.py:746
|
||||||
msgid "Administrator"
|
msgid "Administrator"
|
||||||
msgstr "管理员"
|
msgstr "管理员"
|
||||||
|
|
||||||
#: users/models/user.py:757
|
#: users/models/user.py:749
|
||||||
msgid "Administrator is the super user of system"
|
msgid "Administrator is the super user of system"
|
||||||
msgstr "Administrator是初始的超级管理员"
|
msgstr "Administrator是初始的超级管理员"
|
||||||
|
|
||||||
|
@ -3909,11 +3917,11 @@ msgstr "密码不满足安全规则"
|
||||||
msgid "The new password cannot be the last {} passwords"
|
msgid "The new password cannot be the last {} passwords"
|
||||||
msgstr "新密码不能是最近 {} 次的密码"
|
msgstr "新密码不能是最近 {} 次的密码"
|
||||||
|
|
||||||
#: users/serializers/profile.py:48
|
#: users/serializers/profile.py:46
|
||||||
msgid "The newly set password is inconsistent"
|
msgid "The newly set password is inconsistent"
|
||||||
msgstr "两次密码不一致"
|
msgstr "两次密码不一致"
|
||||||
|
|
||||||
#: users/serializers/profile.py:121 users/serializers/user.py:80
|
#: users/serializers/profile.py:119 users/serializers/user.py:80
|
||||||
msgid "Is first login"
|
msgid "Is first login"
|
||||||
msgstr "首次登录"
|
msgstr "首次登录"
|
||||||
|
|
||||||
|
@ -3991,7 +3999,7 @@ msgid "Security token validation"
|
||||||
msgstr "安全令牌验证"
|
msgstr "安全令牌验证"
|
||||||
|
|
||||||
#: users/templates/users/_base_otp.html:14 xpack/plugins/cloud/models.py:78
|
#: users/templates/users/_base_otp.html:14 xpack/plugins/cloud/models.py:78
|
||||||
#: xpack/plugins/cloud/serializers.py:145
|
#: xpack/plugins/cloud/serializers.py:165
|
||||||
msgid "Account"
|
msgid "Account"
|
||||||
msgstr "账户"
|
msgstr "账户"
|
||||||
|
|
||||||
|
@ -4281,7 +4289,7 @@ msgstr ""
|
||||||
" <br>\n"
|
" <br>\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: users/utils.py:116 users/views/profile/reset.py:126
|
#: users/utils.py:116 users/views/profile/reset.py:124
|
||||||
msgid "Reset password success"
|
msgid "Reset password success"
|
||||||
msgstr "重置密码成功"
|
msgstr "重置密码成功"
|
||||||
|
|
||||||
|
@ -4553,7 +4561,7 @@ msgstr "用户认证源来自 {}, 请去相应系统修改密码"
|
||||||
msgid "* The new password cannot be the last {} passwords"
|
msgid "* The new password cannot be the last {} passwords"
|
||||||
msgstr "* 新密码不能是最近 {} 次的密码"
|
msgstr "* 新密码不能是最近 {} 次的密码"
|
||||||
|
|
||||||
#: users/views/profile/reset.py:127
|
#: users/views/profile/reset.py:125
|
||||||
msgid "Reset password success, return to login page"
|
msgid "Reset password success, return to login page"
|
||||||
msgstr "重置密码成功,返回到登录页面"
|
msgstr "重置密码成功,返回到登录页面"
|
||||||
|
|
||||||
|
@ -4732,7 +4740,7 @@ msgstr "云服务商"
|
||||||
msgid "Cloud account"
|
msgid "Cloud account"
|
||||||
msgstr "云账号"
|
msgstr "云账号"
|
||||||
|
|
||||||
#: xpack/plugins/cloud/models.py:81 xpack/plugins/cloud/serializers.py:126
|
#: xpack/plugins/cloud/models.py:81 xpack/plugins/cloud/serializers.py:146
|
||||||
msgid "Regions"
|
msgid "Regions"
|
||||||
msgstr "地域"
|
msgstr "地域"
|
||||||
|
|
||||||
|
@ -4740,7 +4748,7 @@ msgstr "地域"
|
||||||
msgid "Hostname strategy"
|
msgid "Hostname strategy"
|
||||||
msgstr "主机名策略"
|
msgstr "主机名策略"
|
||||||
|
|
||||||
#: xpack/plugins/cloud/models.py:95 xpack/plugins/cloud/serializers.py:149
|
#: xpack/plugins/cloud/models.py:95 xpack/plugins/cloud/serializers.py:169
|
||||||
msgid "Always update"
|
msgid "Always update"
|
||||||
msgstr "总是更新"
|
msgstr "总是更新"
|
||||||
|
|
||||||
|
@ -4932,20 +4940,24 @@ msgstr ""
|
||||||
msgid "Subscription ID"
|
msgid "Subscription ID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: xpack/plugins/cloud/serializers.py:124
|
#: xpack/plugins/cloud/serializers.py:55
|
||||||
|
msgid "{} is required"
|
||||||
|
msgstr "{} 字段是必填项"
|
||||||
|
|
||||||
|
#: xpack/plugins/cloud/serializers.py:144
|
||||||
msgid "History count"
|
msgid "History count"
|
||||||
msgstr "执行次数"
|
msgstr "执行次数"
|
||||||
|
|
||||||
#: xpack/plugins/cloud/serializers.py:125
|
#: xpack/plugins/cloud/serializers.py:145
|
||||||
msgid "Instance count"
|
msgid "Instance count"
|
||||||
msgstr "实例个数"
|
msgstr "实例个数"
|
||||||
|
|
||||||
#: xpack/plugins/cloud/serializers.py:148
|
#: xpack/plugins/cloud/serializers.py:168
|
||||||
#: xpack/plugins/gathered_user/serializers.py:20
|
#: xpack/plugins/gathered_user/serializers.py:20
|
||||||
msgid "Periodic display"
|
msgid "Periodic display"
|
||||||
msgstr "定时执行"
|
msgstr "定时执行"
|
||||||
|
|
||||||
#: xpack/plugins/cloud/utils.py:64
|
#: xpack/plugins/cloud/utils.py:65
|
||||||
msgid "Account unavailable"
|
msgid "Account unavailable"
|
||||||
msgstr "账户无效"
|
msgstr "账户无效"
|
||||||
|
|
||||||
|
@ -5033,6 +5045,9 @@ msgstr "旗舰版"
|
||||||
msgid "Community edition"
|
msgid "Community edition"
|
||||||
msgstr "社区版"
|
msgstr "社区版"
|
||||||
|
|
||||||
|
#~ msgid "AppSecret is required"
|
||||||
|
#~ msgstr "AppSecret 是必须的"
|
||||||
|
|
||||||
#~ msgid "Corporation ID(corpid)"
|
#~ msgid "Corporation ID(corpid)"
|
||||||
#~ msgstr "企业 ID(CorpId)"
|
#~ msgstr "企业 ID(CorpId)"
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,10 @@ class OrgViewSet(BulkModelViewSet):
|
||||||
@tmp_to_root_org()
|
@tmp_to_root_org()
|
||||||
def get_data_from_model(self, model):
|
def get_data_from_model(self, model):
|
||||||
if model == User:
|
if model == User:
|
||||||
data = model.objects.filter(orgs__id=self.org.id, m2m_org_members__role=ROLE.USER)
|
data = model.objects.filter(
|
||||||
|
orgs__id=self.org.id,
|
||||||
|
m2m_org_members__role__in=[ROLE.USER, ROLE.ADMIN, ROLE.AUDITOR]
|
||||||
|
)
|
||||||
elif model == Node:
|
elif model == Node:
|
||||||
# 跟节点不能手动删除,所以排除检查
|
# 跟节点不能手动删除,所以排除检查
|
||||||
data = model.objects.filter(org_id=self.org.id).exclude(parent_key='', key__regex=r'^[0-9]+$')
|
data = model.objects.filter(org_id=self.org.id).exclude(parent_key='', key__regex=r'^[0-9]+$')
|
||||||
|
@ -73,7 +76,7 @@ class OrgViewSet(BulkModelViewSet):
|
||||||
for model in org_related_models:
|
for model in org_related_models:
|
||||||
data = self.get_data_from_model(model)
|
data = self.get_data_from_model(model)
|
||||||
if data:
|
if data:
|
||||||
msg = _(f'Have `{model._meta.verbose_name}` exists, Please delete')
|
msg = _('Have {} exists, Please delete').format(model._meta.verbose_name)
|
||||||
return Response(data={'error': msg}, status=status.HTTP_403_FORBIDDEN)
|
return Response(data={'error': msg}, status=status.HTTP_403_FORBIDDEN)
|
||||||
else:
|
else:
|
||||||
if str(current_org) == str(self.org):
|
if str(current_org) == str(self.org):
|
||||||
|
|
|
@ -79,7 +79,7 @@ class OrgResourceStatisticsCache(OrgRelatedCache):
|
||||||
|
|
||||||
def compute_users_amount(self):
|
def compute_users_amount(self):
|
||||||
if self.org.is_root():
|
if self.org.is_root():
|
||||||
users_amount = User.objects.all().count()
|
users_amount = User.objects.exclude(role='App').count()
|
||||||
else:
|
else:
|
||||||
users_amount = OrganizationMember.objects.values(
|
users_amount = OrganizationMember.objects.values(
|
||||||
'user_id'
|
'user_id'
|
||||||
|
|
|
@ -25,13 +25,18 @@ class DingTalkTestingAPI(GenericAPIView):
|
||||||
|
|
||||||
if not dingtalk_appsecret:
|
if not dingtalk_appsecret:
|
||||||
secret = Setting.objects.filter(name='DINGTALK_APPSECRET').first()
|
secret = Setting.objects.filter(name='DINGTALK_APPSECRET').first()
|
||||||
if not secret:
|
if secret:
|
||||||
return Response(status=status.HTTP_400_BAD_REQUEST, data={'error': _('AppSecret is required')})
|
dingtalk_appsecret = secret.cleaned_value
|
||||||
dingtalk_appsecret = secret.cleaned_value
|
|
||||||
|
dingtalk_appsecret = dingtalk_appsecret or ''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
dingtalk = DingTalk(appid=dingtalk_appkey, appsecret=dingtalk_appsecret, agentid=dingtalk_agentid)
|
dingtalk = DingTalk(appid=dingtalk_appkey, appsecret=dingtalk_appsecret, agentid=dingtalk_agentid)
|
||||||
dingtalk.send_text(['test'], 'test')
|
dingtalk.send_text(['test'], 'test')
|
||||||
return Response(status=status.HTTP_200_OK, data={'msg': _('OK')})
|
return Response(status=status.HTTP_200_OK, data={'msg': _('Test success')})
|
||||||
except APIException as e:
|
except APIException as e:
|
||||||
return Response(status=status.HTTP_400_BAD_REQUEST, data={'error': e.detail})
|
try:
|
||||||
|
error = e.detail['errmsg']
|
||||||
|
except:
|
||||||
|
error = e.detail
|
||||||
|
return Response(status=status.HTTP_400_BAD_REQUEST, data={'error': error})
|
||||||
|
|
|
@ -25,13 +25,18 @@ class WeComTestingAPI(GenericAPIView):
|
||||||
|
|
||||||
if not wecom_corpsecret:
|
if not wecom_corpsecret:
|
||||||
secret = Setting.objects.filter(name='WECOM_SECRET').first()
|
secret = Setting.objects.filter(name='WECOM_SECRET').first()
|
||||||
if not secret:
|
if secret:
|
||||||
return Response(status=status.HTTP_400_BAD_REQUEST, data={'error': _('Secret is required')})
|
wecom_corpsecret = secret.cleaned_value
|
||||||
wecom_corpsecret = secret.cleaned_value
|
|
||||||
|
wecom_corpsecret = wecom_corpsecret or ''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
wecom = WeCom(corpid=wecom_corpid, corpsecret=wecom_corpsecret, agentid=wecom_agentid)
|
wecom = WeCom(corpid=wecom_corpid, corpsecret=wecom_corpsecret, agentid=wecom_agentid)
|
||||||
wecom.send_text(['test'], 'test')
|
wecom.send_text(['test'], 'test')
|
||||||
return Response(status=status.HTTP_200_OK, data={'msg': _('OK')})
|
return Response(status=status.HTTP_200_OK, data={'msg': _('Test success')})
|
||||||
except APIException as e:
|
except APIException as e:
|
||||||
return Response(status=status.HTTP_400_BAD_REQUEST, data={'error': e.detail})
|
try:
|
||||||
|
error = e.detail['errmsg']
|
||||||
|
except:
|
||||||
|
error = e.detail
|
||||||
|
return Response(status=status.HTTP_400_BAD_REQUEST, data={'error': error})
|
||||||
|
|
|
@ -170,7 +170,7 @@ class SecuritySettingSerializer(serializers.Serializer):
|
||||||
OLD_PASSWORD_HISTORY_LIMIT_COUNT = serializers.IntegerField(
|
OLD_PASSWORD_HISTORY_LIMIT_COUNT = serializers.IntegerField(
|
||||||
min_value=0, max_value=99999, required=True,
|
min_value=0, max_value=99999, required=True,
|
||||||
label=_('Number of repeated historical passwords'),
|
label=_('Number of repeated historical passwords'),
|
||||||
help_text=_('Tip: When the user resets the password, it cannot be the previous n historical passwords of the user (the value of n here is the value filled in the input box)')
|
help_text=_('Tip: When the user resets the password, it cannot be the previous n historical passwords of the user')
|
||||||
)
|
)
|
||||||
SECURITY_PASSWORD_MIN_LENGTH = serializers.IntegerField(
|
SECURITY_PASSWORD_MIN_LENGTH = serializers.IntegerField(
|
||||||
min_value=6, max_value=30, required=True,
|
min_value=6, max_value=30, required=True,
|
||||||
|
|
|
@ -8,8 +8,9 @@ from rest_framework import generics
|
||||||
from rest_framework.views import APIView, Response
|
from rest_framework.views import APIView, Response
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from common.exceptions import JMSException
|
||||||
from common.drf.api import JMSBulkModelViewSet
|
from common.drf.api import JMSBulkModelViewSet
|
||||||
from common.utils import get_object_or_none
|
from common.utils import get_object_or_none
|
||||||
from common.permissions import IsAppUser, IsSuperUser, WithBootstrapToken
|
from common.permissions import IsAppUser, IsSuperUser, WithBootstrapToken
|
||||||
|
@ -30,6 +31,17 @@ class TerminalViewSet(JMSBulkModelViewSet):
|
||||||
permission_classes = (IsSuperUser,)
|
permission_classes = (IsSuperUser,)
|
||||||
filterset_fields = ['name', 'remote_addr', 'type']
|
filterset_fields = ['name', 'remote_addr', 'type']
|
||||||
|
|
||||||
|
def destroy(self, request, *args, **kwargs):
|
||||||
|
instance = self.get_object()
|
||||||
|
if instance.get_online_session_count() > 0:
|
||||||
|
raise JMSException(
|
||||||
|
code='have_online_session',
|
||||||
|
detail=_('Have online sessions')
|
||||||
|
)
|
||||||
|
|
||||||
|
self.perform_destroy(instance)
|
||||||
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
if isinstance(request.data, list):
|
if isinstance(request.data, list):
|
||||||
raise exceptions.BulkCreateNotSupport()
|
raise exceptions.BulkCreateNotSupport()
|
||||||
|
|
|
@ -7,8 +7,6 @@ import string
|
||||||
import random
|
import random
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.contrib.auth.hashers import check_password, make_password
|
from django.contrib.auth.hashers import check_password, make_password
|
||||||
|
@ -30,7 +28,7 @@ from users.exceptions import MFANotEnabled
|
||||||
from ..signals import post_user_change_password
|
from ..signals import post_user_change_password
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['User']
|
__all__ = ['User', 'UserPasswordHistory']
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
@ -83,12 +81,6 @@ class AuthMixin:
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def save_history_password(self, password):
|
|
||||||
UserPasswordHistory.objects.create(
|
|
||||||
user=self, password=make_password(password),
|
|
||||||
date_created=self.date_password_last_updated
|
|
||||||
)
|
|
||||||
|
|
||||||
def is_public_key_valid(self):
|
def is_public_key_valid(self):
|
||||||
"""
|
"""
|
||||||
Check if the user's ssh public key is valid.
|
Check if the user's ssh public key is valid.
|
||||||
|
@ -771,3 +763,9 @@ class UserPasswordHistory(models.Model):
|
||||||
user = models.ForeignKey("users.User", related_name='history_passwords',
|
user = models.ForeignKey("users.User", related_name='history_passwords',
|
||||||
on_delete=models.CASCADE, verbose_name=_('User'))
|
on_delete=models.CASCADE, verbose_name=_('User'))
|
||||||
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_("Date created"))
|
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_("Date created"))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.user} set at {self.date_created}'
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return self.__str__()
|
||||||
|
|
|
@ -39,8 +39,6 @@ class UserUpdatePasswordSerializer(serializers.ModelSerializer):
|
||||||
limit_count = settings.OLD_PASSWORD_HISTORY_LIMIT_COUNT
|
limit_count = settings.OLD_PASSWORD_HISTORY_LIMIT_COUNT
|
||||||
msg = _('The new password cannot be the last {} passwords').format(limit_count)
|
msg = _('The new password cannot be the last {} passwords').format(limit_count)
|
||||||
raise serializers.ValidationError(msg)
|
raise serializers.ValidationError(msg)
|
||||||
else:
|
|
||||||
self.instance.save_history_password(value)
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def validate_new_password_again(self, value):
|
def validate_new_password_again(self, value):
|
||||||
|
|
|
@ -6,17 +6,33 @@ from django_auth_ldap.backend import populate_user
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django_cas_ng.signals import cas_user_authenticated
|
from django_cas_ng.signals import cas_user_authenticated
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
|
||||||
from jms_oidc_rp.signals import openid_create_or_update_user
|
from jms_oidc_rp.signals import openid_create_or_update_user
|
||||||
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from .signals import post_user_create
|
from .signals import post_user_create
|
||||||
from .models import User
|
from .models import User, UserPasswordHistory
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=User)
|
||||||
|
def save_passwd_change(sender, instance: User, **kwargs):
|
||||||
|
passwds = UserPasswordHistory.objects.filter(user=instance).order_by('-date_created')\
|
||||||
|
.values_list('password', flat=True)[:int(settings.OLD_PASSWORD_HISTORY_LIMIT_COUNT)]
|
||||||
|
|
||||||
|
for p in passwds:
|
||||||
|
if instance.password == p:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
UserPasswordHistory.objects.create(
|
||||||
|
user=instance, password=instance.password,
|
||||||
|
date_created=instance.date_password_last_updated
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_user_create)
|
@receiver(post_user_create)
|
||||||
def on_user_create(sender, user=None, **kwargs):
|
def on_user_create(sender, user=None, **kwargs):
|
||||||
logger.debug("Receive user `{}` create signal".format(user.name))
|
logger.debug("Receive user `{}` create signal".format(user.name))
|
||||||
|
|
|
@ -111,8 +111,6 @@ class UserResetPasswordView(FormView):
|
||||||
error = _('* The new password cannot be the last {} passwords').format(limit_count)
|
error = _('* The new password cannot be the last {} passwords').format(limit_count)
|
||||||
form.add_error('new_password', error)
|
form.add_error('new_password', error)
|
||||||
return self.form_invalid(form)
|
return self.form_invalid(form)
|
||||||
else:
|
|
||||||
user.save_history_password(password)
|
|
||||||
|
|
||||||
user.reset_password(password)
|
user.reset_password(password)
|
||||||
User.expired_reset_password_token(token)
|
User.expired_reset_password_token(token)
|
||||||
|
|
Loading…
Reference in New Issue