Merge pull request #5785 from jumpserver/dev

v2.8 发版 (rc4)
pull/5813/head
老广 2021-03-17 20:15:31 +08:00 committed by GitHub
commit 776234e8cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 359 additions and 240 deletions

View File

@ -87,6 +87,9 @@ class SystemUser(BaseUser):
(PROTOCOL_POSTGRESQL, 'postgresql'), (PROTOCOL_POSTGRESQL, 'postgresql'),
(PROTOCOL_K8S, 'k8s'), (PROTOCOL_K8S, 'k8s'),
) )
SUPPORT_PUSH_PROTOCOLS = [PROTOCOL_SSH, PROTOCOL_RDP]
ASSET_CATEGORY_PROTOCOLS = [ ASSET_CATEGORY_PROTOCOLS = [
PROTOCOL_SSH, PROTOCOL_RDP, PROTOCOL_TELNET, PROTOCOL_VNC PROTOCOL_SSH, PROTOCOL_RDP, PROTOCOL_TELNET, PROTOCOL_VNC
] ]
@ -151,11 +154,15 @@ class SystemUser(BaseUser):
return self.get_login_mode_display() return self.get_login_mode_display()
def is_need_push(self): def is_need_push(self):
if self.auto_push and self.protocol in [self.PROTOCOL_SSH, self.PROTOCOL_RDP]: if self.auto_push and self.is_protocol_support_push:
return True return True
else: else:
return False return False
@property
def is_protocol_support_push(self):
return self.protocol in self.SUPPORT_PUSH_PROTOCOLS
@property @property
def is_need_cmd_filter(self): def is_need_cmd_filter(self):
return self.protocol not in [self.PROTOCOL_RDP, self.PROTOCOL_VNC] return self.protocol not in [self.PROTOCOL_RDP, self.PROTOCOL_VNC]

View File

@ -193,7 +193,8 @@ def on_asset_nodes_add(instance, action, reverse, pk_set, **kwargs):
systemuser_id=system_user_id, systemuser_id=system_user_id,
asset_id=asset_id asset_id=asset_id
)) ))
push_system_user_to_assets.delay(system_user_id, asset_ids_to_push) if asset_ids_to_push:
push_system_user_to_assets.delay(system_user_id, asset_ids_to_push)
m2m_model.objects.bulk_create(to_create) m2m_model.objects.bulk_create(to_create)

View File

@ -7,7 +7,7 @@ from django.db.models.signals import (
m2m_changed m2m_changed
) )
from orgs.utils import ensure_in_real_or_default_org from orgs.utils import ensure_in_real_or_default_org, tmp_to_org
from common.const.signals import PRE_ADD, POST_REMOVE, PRE_CLEAR from common.const.signals import PRE_ADD, POST_REMOVE, PRE_CLEAR
from common.utils import get_logger from common.utils import get_logger
from assets.models import Asset, Node, compute_parent_key from assets.models import Asset, Node, compute_parent_key
@ -34,15 +34,16 @@ def on_node_asset_change(sender, action, instance, reverse, pk_set, **kwargs):
operator = mapper[action] operator = mapper[action]
if reverse: with tmp_to_org(instance.org):
node: Node = instance if reverse:
asset_pk_set = set(pk_set) node: Node = instance
NodeAssetsAmountUtils.update_node_assets_amount(node, asset_pk_set, operator) asset_pk_set = set(pk_set)
else: NodeAssetsAmountUtils.update_node_assets_amount(node, asset_pk_set, operator)
asset_pk = instance.id else:
# 与资产直接关联的节点 asset_pk = instance.id
node_keys = set(Node.objects.filter(id__in=pk_set).values_list('key', flat=True)) # 与资产直接关联的节点
NodeAssetsAmountUtils.update_nodes_asset_amount(node_keys, asset_pk, operator) node_keys = set(Node.objects.filter(id__in=pk_set).values_list('key', flat=True))
NodeAssetsAmountUtils.update_nodes_asset_amount(node_keys, asset_pk, operator)
class NodeAssetsAmountUtils: class NodeAssetsAmountUtils:

View File

@ -25,10 +25,13 @@ def check_asset_can_run_ansible(asset):
def check_system_user_can_run_ansible(system_user): def check_system_user_can_run_ansible(system_user):
if not system_user.is_need_push(): if not system_user.auto_push:
msg = _("Push system user task skip, auto push not enable or " logger.warn(f'Push system user task skip, auto push not enable: system_user={system_user.name}')
"protocol is not ssh or rdp: {}").format(system_user.name) return False
logger.info(msg) if not system_user.is_protocol_support_push:
logger.warn(f'Push system user task skip, protocol not support: '
f'system_user={system_user.name} protocol={system_user.protocol} '
f'support_protocol={system_user.SUPPORT_PUSH_PROTOCOLS}')
return False return False
# Push root as system user is dangerous # Push root as system user is dangerous
@ -37,10 +40,6 @@ def check_system_user_can_run_ansible(system_user):
logger.info(msg) logger.info(msg)
return False return False
# if system_user.protocol != "ssh":
# msg = _("System user protocol not ssh: {}".format(system_user))
# logger.info(msg)
# return False
return True return True

View File

@ -64,6 +64,9 @@ class SessionAuditSerializer(serializers.ModelSerializer):
class CommandExecutionSerializer(serializers.ModelSerializer): class CommandExecutionSerializer(serializers.ModelSerializer):
is_success = serializers.BooleanField(read_only=True, label=_('Is success')) is_success = serializers.BooleanField(read_only=True, label=_('Is success'))
hosts_display = serializers.ListSerializer(
child=serializers.CharField(), source='hosts', read_only=True, label=_('Hosts for display')
)
class Meta: class Meta:
model = CommandExecution model = CommandExecution
@ -72,7 +75,7 @@ class CommandExecutionSerializer(serializers.ModelSerializer):
'run_as', 'command', 'user', 'is_finished', 'run_as', 'command', 'user', 'is_finished',
'date_start', 'result', 'is_success', 'org_id' 'date_start', 'result', 'is_success', 'org_id'
] ]
fields = fields_small + ['hosts', 'run_as_display', 'user_display'] fields = fields_small + ['hosts', 'hosts_display', 'run_as_display', 'user_display']
extra_kwargs = { extra_kwargs = {
'result': {'label': _('Result')}, # model 上的方法,只能在这修改 'result': {'label': _('Result')}, # model 上的方法,只能在这修改
'is_success': {'label': _('Is success')}, 'is_success': {'label': _('Is success')},

View File

@ -68,6 +68,7 @@ class LoginConfirmSetting(CommonModelMixin):
def create_confirm_ticket(self, request=None): def create_confirm_ticket(self, request=None):
from tickets import const from tickets import const
from tickets.models import Ticket from tickets.models import Ticket
from orgs.models import Organization
ticket_title = _('Login confirm') + ' {}'.format(self.user) ticket_title = _('Login confirm') + ' {}'.format(self.user)
ticket_meta = self.construct_confirm_ticket_meta(request) ticket_meta = self.construct_confirm_ticket_meta(request)
ticket_assignees = self.reviewers.all() ticket_assignees = self.reviewers.all()
@ -75,6 +76,7 @@ class LoginConfirmSetting(CommonModelMixin):
'title': ticket_title, 'title': ticket_title,
'type': const.TicketTypeChoices.login_confirm.value, 'type': const.TicketTypeChoices.login_confirm.value,
'meta': ticket_meta, 'meta': ticket_meta,
'org_id': Organization.ROOT_ID,
} }
ticket = Ticket.objects.create(**data) ticket = Ticket.objects.create(**data)
ticket.assignees.set(ticket_assignees) ticket.assignees.set(ticket_assignees)

View File

@ -170,7 +170,7 @@ class UserLoginWaitConfirmView(TemplateView):
if not ticket_id: if not ticket_id:
ticket = None ticket = None
else: else:
ticket = get_object_or_none(Ticket, pk=ticket_id) ticket = Ticket.all().filter(pk=ticket_id).first()
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
if ticket: if ticket:
timestamp_created = datetime.datetime.timestamp(ticket.date_created) timestamp_created = datetime.datetime.timestamp(ticket.date_created)

View File

@ -283,7 +283,7 @@ class Config(dict):
'SERVER_REPLAY_STORAGE': {}, 'SERVER_REPLAY_STORAGE': {},
'CONNECTION_TOKEN_ENABLED': False, 'CONNECTION_TOKEN_ENABLED': False,
'ONLY_ALLOW_EXIST_USER_AUTH': False, 'ONLY_ALLOW_EXIST_USER_AUTH': False,
'ONLY_ALLOW_AUTH_FROM_SOURCE': True, 'ONLY_ALLOW_AUTH_FROM_SOURCE': False,
'DISK_CHECK_ENABLED': True, 'DISK_CHECK_ENABLED': True,
'SESSION_SAVE_EVERY_REQUEST': True, 'SESSION_SAVE_EVERY_REQUEST': True,
'SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE': False, 'SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE': False,

View File

@ -12,7 +12,7 @@ XPACK_CONTEXT_PROCESSOR = []
if XPACK_ENABLED: if XPACK_ENABLED:
from xpack.utils import get_xpack_templates_dir, get_xpack_context_processor from xpack.utils import get_xpack_templates_dir, get_xpack_context_processor
INSTALLED_APPS.append('xpack.apps.XpackConfig') INSTALLED_APPS.insert(0, 'xpack.apps.XpackConfig')
XPACK_TEMPLATES_DIR = get_xpack_templates_dir(const.BASE_DIR) XPACK_TEMPLATES_DIR = get_xpack_templates_dir(const.BASE_DIR)
XPACK_CONTEXT_PROCESSOR = get_xpack_context_processor() XPACK_CONTEXT_PROCESSOR = get_xpack_context_processor()
TEMPLATES[0]['DIRS'].extend(XPACK_TEMPLATES_DIR) TEMPLATES[0]['DIRS'].extend(XPACK_TEMPLATES_DIR)

View File

@ -42,13 +42,13 @@ INSTALLED_APPS = [
'perms.apps.PermsConfig', 'perms.apps.PermsConfig',
'ops.apps.OpsConfig', 'ops.apps.OpsConfig',
'settings.apps.SettingsConfig', 'settings.apps.SettingsConfig',
'common.apps.CommonConfig',
'terminal.apps.TerminalConfig', 'terminal.apps.TerminalConfig',
'audits.apps.AuditsConfig', 'audits.apps.AuditsConfig',
'authentication.apps.AuthenticationConfig', # authentication 'authentication.apps.AuthenticationConfig', # authentication
'applications.apps.ApplicationsConfig', 'applications.apps.ApplicationsConfig',
'tickets.apps.TicketsConfig', 'tickets.apps.TicketsConfig',
'acls.apps.AclsConfig', 'acls.apps.AclsConfig',
'common.apps.CommonConfig',
'jms_oidc_rp', 'jms_oidc_rp',
'rest_framework', 'rest_framework',
'rest_framework_swagger', 'rest_framework_swagger',

View File

@ -2,6 +2,8 @@
# #
from functools import partial from functools import partial
from werkzeug.local import LocalProxy from werkzeug.local import LocalProxy
from django.conf import settings
from common.local import thread_local from common.local import thread_local
@ -17,4 +19,11 @@ def get_current_request():
return _find('current_request') return _find('current_request')
def has_valid_xpack_license():
if not settings.XPACK_ENABLED:
return False
from xpack.plugins.license.models import License
return License.has_valid_license()
current_request = LocalProxy(partial(_find, 'current_request')) current_request = LocalProxy(partial(_find, 'current_request'))

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: 2021-03-11 17:54+0800\n" "POT-Creation-Date: 2021-03-17 18:17+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"
@ -35,7 +35,7 @@ msgstr ""
#: assets/models/cmd_filter.py:21 assets/models/domain.py:21 #: assets/models/cmd_filter.py:21 assets/models/domain.py:21
#: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24 #: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24
#: 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:75 #: terminal/models/storage.py:23 terminal/models/storage.py:81
#: terminal/models/task.py:16 terminal/models/terminal.py:139 #: terminal/models/task.py:16 terminal/models/terminal.py:139
#: users/forms/profile.py:32 users/models/group.py:15 users/models/user.py:530 #: users/forms/profile.py:32 users/models/group.py:15 users/models/user.py:530
#: users/templates/users/_select_user_modal.html:13 #: users/templates/users/_select_user_modal.html:13
@ -56,12 +56,12 @@ msgid "Name"
msgstr "名称" msgstr "名称"
#: acls/models/base.py:27 assets/models/cmd_filter.py:53 #: acls/models/base.py:27 assets/models/cmd_filter.py:53
#: assets/models/user.py:119 #: assets/models/user.py:122
msgid "Priority" msgid "Priority"
msgstr "优先级" msgstr "优先级"
#: acls/models/base.py:28 assets/models/cmd_filter.py:53 #: acls/models/base.py:28 assets/models/cmd_filter.py:53
#: assets/models/user.py:119 #: assets/models/user.py:122
msgid "1-100, the lower the value will be match first" msgid "1-100, the lower the value will be match first"
msgstr "优先级可选范围为 1-100 (数值越小越优先)" msgstr "优先级可选范围为 1-100 (数值越小越优先)"
@ -82,7 +82,7 @@ msgstr "激活中"
#: assets/models/domain.py:22 assets/models/domain.py:56 #: assets/models/domain.py:22 assets/models/domain.py:56
#: assets/models/group.py:23 assets/models/label.py:23 ops/models/adhoc.py:37 #: assets/models/group.py:23 assets/models/label.py:23 ops/models/adhoc.py:37
#: 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:81 #: terminal/models/storage.py:29 terminal/models/storage.py:87
#: terminal/models/terminal.py:153 tickets/models/ticket.py:73 #: terminal/models/terminal.py:153 tickets/models/ticket.py:73
#: users/models/group.py:16 users/models/user.py:563 #: users/models/group.py:16 users/models/user.py:563
#: users/templates/users/user_detail.html:115 #: users/templates/users/user_detail.html:115
@ -125,13 +125,13 @@ msgstr "动作"
#: acls/models/login_acl.py:28 acls/models/login_asset_acl.py:20 #: acls/models/login_acl.py:28 acls/models/login_asset_acl.py:20
#: acls/serializers/login_acl.py:28 assets/models/label.py:15 #: acls/serializers/login_acl.py:28 assets/models/label.py:15
#: audits/models.py:36 audits/models.py:56 audits/models.py:69 #: audits/models.py:36 audits/models.py:56 audits/models.py:69
#: audits/serializers.py:81 authentication/models.py:44 #: audits/serializers.py:84 authentication/models.py:44
#: authentication/models.py:95 orgs/models.py:18 orgs/models.py:403 #: authentication/models.py:97 orgs/models.py:18 orgs/models.py:417
#: 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:37 #: terminal/backends/command/serializers.py:12 terminal/models/session.py:37
#: tickets/models/comment.py:17 users/models/user.py:159 #: tickets/models/comment.py:17 users/models/user.py:159
#: users/models/user.py:677 users/serializers/group.py:20 #: users/models/user.py:699 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
#: users/templates/users/user_database_app_permission.html:37 #: users/templates/users/user_database_app_permission.html:37
@ -144,7 +144,7 @@ msgstr "动作"
msgid "User" msgid "User"
msgstr "用户" msgstr "用户"
#: acls/models/login_asset_acl.py:17 authentication/models.py:71 #: acls/models/login_asset_acl.py:17 authentication/models.py:72
#: tickets/const.py:9 users/templates/users/user_detail.html:250 #: tickets/const.py:9 users/templates/users/user_detail.html:250
msgid "Login confirm" msgid "Login confirm"
msgstr "登录复核" msgstr "登录复核"
@ -156,9 +156,9 @@ msgstr "系统用户"
#: acls/models/login_asset_acl.py:22 #: acls/models/login_asset_acl.py:22
#: applications/serializers/attrs/application_category/remote_app.py:33 #: applications/serializers/attrs/application_category/remote_app.py:33
#: assets/models/asset.py:355 assets/models/authbook.py:26 #: assets/models/asset.py:355 assets/models/authbook.py:26
#: assets/models/gathered_user.py:14 assets/serializers/admin_user.py:29 #: assets/models/gathered_user.py:14 assets/serializers/admin_user.py:30
#: assets/serializers/asset_user.py:47 assets/serializers/asset_user.py:84 #: assets/serializers/asset_user.py:47 assets/serializers/asset_user.py:84
#: assets/serializers/system_user.py:191 audits/models.py:38 #: assets/serializers/system_user.py:192 audits/models.py:38
#: perms/models/asset_permission.py:99 templates/index.html:82 #: perms/models/asset_permission.py:99 templates/index.html:82
#: terminal/backends/command/models.py:19 #: terminal/backends/command/models.py:19
#: terminal/backends/command/serializers.py:13 terminal/models/session.py:39 #: terminal/backends/command/serializers.py:13 terminal/models/session.py:39
@ -192,7 +192,7 @@ msgstr "IP 地址无效: `{}`"
msgid "IP" msgid "IP"
msgstr "IP" msgstr "IP"
#: acls/serializers/login_acl.py:41 #: acls/serializers/login_acl.py:45
msgid "The user `{}` is not in the current organization: `{}`" msgid "The user `{}` is not in the current organization: `{}`"
msgstr "用户 `{}` 不在当前组织: `{}`" msgstr "用户 `{}` 不在当前组织: `{}`"
@ -228,7 +228,7 @@ msgid "Hostname"
msgstr "主机名" msgstr "主机名"
#: acls/serializers/login_asset_acl.py:41 assets/models/asset.py:187 #: acls/serializers/login_asset_acl.py:41 assets/models/asset.py:187
#: assets/models/domain.py:54 assets/models/user.py:120 #: assets/models/domain.py:54 assets/models/user.py:123
#: terminal/serializers/session.py:29 terminal/serializers/storage.py:69 #: terminal/serializers/session.py:29 terminal/serializers/storage.py:69
msgid "Protocol" msgid "Protocol"
msgstr "协议" msgstr "协议"
@ -241,12 +241,12 @@ msgstr "协议选项: {}"
msgid "Unsupported protocols: {}" msgid "Unsupported protocols: {}"
msgstr "不支持的协议: {}" msgstr "不支持的协议: {}"
#: acls/serializers/login_asset_acl.py:78 #: acls/serializers/login_asset_acl.py:80
#: tickets/serializers/ticket/ticket.py:109 #: tickets/serializers/ticket/ticket.py:109
msgid "The organization `{}` does not exist" msgid "The organization `{}` does not exist"
msgstr "组织 `{}` 不存在" msgstr "组织 `{}` 不存在"
#: acls/serializers/login_asset_acl.py:83 #: acls/serializers/login_asset_acl.py:85
msgid "None of the reviewers belong to Organization `{}`" msgid "None of the reviewers belong to Organization `{}`"
msgstr "所有复核人都不属于组织 `{}`" msgstr "所有复核人都不属于组织 `{}`"
@ -279,7 +279,7 @@ msgstr "类别"
#: perms/models/application_permission.py:23 #: perms/models/application_permission.py:23
#: perms/serializers/application/permission.py:17 #: perms/serializers/application/permission.py:17
#: perms/serializers/application/user_permission.py:34 #: perms/serializers/application/user_permission.py:34
#: terminal/models/storage.py:26 terminal/models/storage.py:78 #: terminal/models/storage.py:26 terminal/models/storage.py:84
#: tickets/models/ticket.py:38 #: tickets/models/ticket.py:38
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:27 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:27
#: users/templates/users/user_granted_database_app.html:35 #: users/templates/users/user_granted_database_app.html:35
@ -335,7 +335,7 @@ msgstr "目标URL"
#: applications/serializers/attrs/application_type/vmware_client.py:30 #: applications/serializers/attrs/application_type/vmware_client.py:30
#: assets/models/base.py:252 assets/serializers/asset_user.py:71 #: assets/models/base.py:252 assets/serializers/asset_user.py:71
#: audits/signals_handler.py:46 authentication/forms.py:22 #: audits/signals_handler.py:46 authentication/forms.py:22
#: authentication/templates/authentication/login.html:148 #: authentication/templates/authentication/login.html:155
#: settings/serializers/settings.py:89 users/forms/profile.py:21 #: settings/serializers/settings.py:89 users/forms/profile.py:21
#: users/templates/users/user_otp_check_password.html:13 #: users/templates/users/user_otp_check_password.html:13
#: users/templates/users/user_password_update.html:43 #: users/templates/users/user_password_update.html:43
@ -394,7 +394,8 @@ msgstr "基础"
msgid "Charset" msgid "Charset"
msgstr "编码" msgstr "编码"
#: assets/models/asset.py:145 tickets/models/ticket.py:40 #: assets/models/asset.py:145 assets/serializers/asset.py:171
#: tickets/models/ticket.py:40
msgid "Meta" msgid "Meta"
msgstr "元数据" msgstr "元数据"
@ -412,7 +413,7 @@ msgstr "系统平台"
msgid "Protocols" msgid "Protocols"
msgstr "协议组" msgstr "协议组"
#: assets/models/asset.py:192 assets/models/user.py:115 #: assets/models/asset.py:192 assets/models/user.py:118
#: perms/models/asset_permission.py:100 #: perms/models/asset_permission.py:100
#: xpack/plugins/change_auth_plan/models.py:56 #: xpack/plugins/change_auth_plan/models.py:56
#: xpack/plugins/gathered_user/models.py:24 #: xpack/plugins/gathered_user/models.py:24
@ -503,7 +504,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:60 assets/models/group.py:21 #: assets/models/cmd_filter.py:60 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:407 perms/models/base.py:55 users/models/user.py:571 #: orgs/models.py:421 perms/models/base.py:55 users/models/user.py:571
#: users/serializers/group.py:35 users/templates/users/user_detail.html:97 #: users/serializers/group.py:35 users/templates/users/user_detail.html:97
#: xpack/plugins/change_auth_plan/models.py:81 #: 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
@ -517,7 +518,7 @@ msgstr "创建者"
#: assets/models/gathered_user.py:19 assets/models/group.py:22 #: assets/models/gathered_user.py:19 assets/models/group.py:22
#: 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:405 perms/models/base.py:56 users/models/group.py:18 #: orgs/models.py:419 perms/models/base.py:56 users/models/group.py:18
#: users/templates/users/user_group_detail.html:58 #: users/templates/users/user_group_detail.html:58
#: xpack/plugins/cloud/models.py:107 #: xpack/plugins/cloud/models.py:107
msgid "Date created" msgid "Date created"
@ -553,7 +554,7 @@ msgstr "SSH公钥"
#: assets/models/base.py:257 assets/models/gathered_user.py:20 #: assets/models/base.py:257 assets/models/gathered_user.py:20
#: common/db/models.py:73 common/mixins/models.py:51 ops/models/adhoc.py:39 #: common/db/models.py:73 common/mixins/models.py:51 ops/models/adhoc.py:39
#: orgs/models.py:406 #: orgs/models.py:420
msgid "Date updated" msgid "Date updated"
msgstr "更新日期" msgstr "更新日期"
@ -591,7 +592,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:689 #: users/models/user.py:711
msgid "System" msgid "System"
msgstr "系统" msgstr "系统"
@ -599,7 +600,7 @@ msgstr "系统"
msgid "Default Cluster" msgid "Default Cluster"
msgstr "默认Cluster" msgstr "默认Cluster"
#: assets/models/cmd_filter.py:33 assets/models/user.py:125 #: assets/models/cmd_filter.py:33 assets/models/user.py:128
msgid "Command filter" msgid "Command filter"
msgstr "命令过滤器" msgstr "命令过滤器"
@ -664,7 +665,7 @@ msgstr "资产组"
msgid "Default asset group" msgid "Default asset group"
msgstr "默认资产组" msgstr "默认资产组"
#: assets/models/label.py:19 assets/models/node.py:575 settings/models.py:30 #: assets/models/label.py:19 assets/models/node.py:538 settings/models.py:30
msgid "Value" msgid "Value"
msgstr "值" msgstr "值"
@ -672,23 +673,23 @@ msgstr "值"
msgid "New node" msgid "New node"
msgstr "新节点" msgstr "新节点"
#: assets/models/node.py:467 users/templates/users/_granted_assets.html:130 #: assets/models/node.py:466 users/templates/users/_granted_assets.html:130
msgid "empty" msgid "empty"
msgstr "空" msgstr "空"
#: assets/models/node.py:574 perms/models/asset_permission.py:156 #: assets/models/node.py:537 perms/models/asset_permission.py:156
msgid "Key" msgid "Key"
msgstr "键" msgstr "键"
#: assets/models/node.py:576 #: assets/models/node.py:539
msgid "Full value" msgid "Full value"
msgstr "全称" msgstr "全称"
#: assets/models/node.py:579 perms/models/asset_permission.py:157 #: assets/models/node.py:542 perms/models/asset_permission.py:157
msgid "Parent key" msgid "Parent key"
msgstr "ssh私钥" msgstr "ssh私钥"
#: assets/models/node.py:588 assets/serializers/system_user.py:190 #: assets/models/node.py:551 assets/serializers/system_user.py:191
#: 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
@ -696,66 +697,66 @@ msgstr "ssh私钥"
msgid "Node" msgid "Node"
msgstr "节点" msgstr "节点"
#: assets/models/user.py:111 #: assets/models/user.py:114
msgid "Automatic login" msgid "Automatic login"
msgstr "自动登录" msgstr "自动登录"
#: assets/models/user.py:112 #: assets/models/user.py:115
msgid "Manually login" msgid "Manually login"
msgstr "手动登录" msgstr "手动登录"
#: assets/models/user.py:114 #: assets/models/user.py:117
msgid "Username same with user" msgid "Username same with user"
msgstr "用户名与用户相同" msgstr "用户名与用户相同"
#: assets/models/user.py:116 assets/serializers/domain.py:30 #: assets/models/user.py:119 assets/serializers/domain.py:30
#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:52 #: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:52
msgid "Assets" msgid "Assets"
msgstr "资产" msgstr "资产"
#: assets/models/user.py:117 templates/_nav.html:17 #: assets/models/user.py:120 templates/_nav.html:17
#: users/views/profile/password.py:42 users/views/profile/pubkey.py:36 #: users/views/profile/password.py:42 users/views/profile/pubkey.py:36
msgid "Users" msgid "Users"
msgstr "用户管理" msgstr "用户管理"
#: assets/models/user.py:118 users/templates/users/user_group_list.html:90 #: assets/models/user.py:121 users/templates/users/user_group_list.html:90
#: users/templates/users/user_profile.html:124 #: users/templates/users/user_profile.html:124
msgid "User groups" msgid "User groups"
msgstr "用户组" msgstr "用户组"
#: assets/models/user.py:121 #: assets/models/user.py:124
msgid "Auto push" msgid "Auto push"
msgstr "自动推送" msgstr "自动推送"
#: assets/models/user.py:122 #: assets/models/user.py:125
msgid "Sudo" msgid "Sudo"
msgstr "Sudo" msgstr "Sudo"
#: assets/models/user.py:123 #: assets/models/user.py:126
msgid "Shell" msgid "Shell"
msgstr "Shell" msgstr "Shell"
#: assets/models/user.py:124 #: assets/models/user.py:127
msgid "Login mode" msgid "Login mode"
msgstr "登录模式" msgstr "登录模式"
#: assets/models/user.py:126 #: assets/models/user.py:129
msgid "SFTP Root" msgid "SFTP Root"
msgstr "SFTP根路径" msgstr "SFTP根路径"
#: assets/models/user.py:127 authentication/models.py:93 #: assets/models/user.py:130 authentication/models.py:95
msgid "Token" msgid "Token"
msgstr "" msgstr ""
#: assets/models/user.py:128 #: assets/models/user.py:131
msgid "Home" msgid "Home"
msgstr "家目录" msgstr "家目录"
#: assets/models/user.py:129 #: assets/models/user.py:132
msgid "System groups" msgid "System groups"
msgstr "用户组" msgstr "用户组"
#: assets/models/user.py:221 audits/models.py:39 #: assets/models/user.py:228 audits/models.py:39
#: perms/models/application_permission.py:31 #: perms/models/application_permission.py:31
#: perms/models/asset_permission.py:101 templates/_nav.html:45 #: perms/models/asset_permission.py:101 templates/_nav.html:45
#: terminal/backends/command/models.py:20 #: terminal/backends/command/models.py:20
@ -858,6 +859,17 @@ msgstr "应用数量"
msgid "Gateways count" msgid "Gateways count"
msgstr "网关数量" msgstr "网关数量"
#: assets/serializers/label.py:13 assets/serializers/system_user.py:45
#: assets/serializers/system_user.py:166
#: perms/serializers/asset/permission.py:66
msgid "Assets amount"
msgstr "资产数量"
#: assets/serializers/label.py:14
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:24
msgid "Category display"
msgstr "类别 (显示名称)"
#: assets/serializers/node.py:18 #: assets/serializers/node.py:18
msgid "value" msgid "value"
msgstr "值" msgstr "值"
@ -870,22 +882,17 @@ msgstr "不能包含: /"
msgid "The same level node name cannot be the same" msgid "The same level node name cannot be the same"
msgstr "同级别节点名字不能重复" msgstr "同级别节点名字不能重复"
#: assets/serializers/system_user.py:44 assets/serializers/system_user.py:164 #: assets/serializers/system_user.py:44 assets/serializers/system_user.py:165
#: perms/serializers/asset/permission.py:67 #: perms/serializers/asset/permission.py:67
msgid "Nodes amount" msgid "Nodes amount"
msgstr "节点数量" msgstr "节点数量"
#: assets/serializers/system_user.py:45 assets/serializers/system_user.py:165 #: assets/serializers/system_user.py:46 assets/serializers/system_user.py:167
#: perms/serializers/asset/permission.py:66 #: assets/serializers/system_user.py:193
msgid "Assets amount"
msgstr "资产数量"
#: assets/serializers/system_user.py:46 assets/serializers/system_user.py:166
#: assets/serializers/system_user.py:192
msgid "Login mode display" msgid "Login mode display"
msgstr "登录模式(显示名称)" msgstr "登录模式(显示名称)"
#: assets/serializers/system_user.py:48 assets/serializers/system_user.py:168 #: assets/serializers/system_user.py:48 assets/serializers/system_user.py:169
msgid "Ad domain" msgid "Ad domain"
msgstr "Ad 网域" msgstr "Ad 网域"
@ -1008,17 +1015,11 @@ msgstr "资产已经被禁用, 跳过: {}"
msgid "Asset may not be support ansible, skipped: {}" msgid "Asset may not be support ansible, skipped: {}"
msgstr "资产或许不支持ansible, 跳过: {}" msgstr "资产或许不支持ansible, 跳过: {}"
#: assets/tasks/utils.py:29 #: assets/tasks/utils.py:39
msgid ""
"Push system user task skip, auto push not enable or protocol is not ssh or "
"rdp: {}"
msgstr "推送系统用户任务跳过自动推送没有打开或协议不是ssh或rdp: {}"
#: assets/tasks/utils.py:36
msgid "For security, do not push user {}" msgid "For security, do not push user {}"
msgstr "为了安全,禁止推送用户 {}" msgstr "为了安全,禁止推送用户 {}"
#: assets/tasks/utils.py:56 #: assets/tasks/utils.py:55
msgid "No assets matched, stop task" msgid "No assets matched, stop task"
msgstr "没有匹配到资产,结束任务" msgstr "没有匹配到资产,结束任务"
@ -1165,7 +1166,7 @@ msgstr "用户代理"
#: 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:552 #: users/forms/profile.py:64 users/models/user.py:552
#: users/serializers/profile.py:102 users/templates/users/user_detail.html:77 #: users/serializers/profile.py:99 users/templates/users/user_detail.html:77
#: users/templates/users/user_profile.html:87 #: users/templates/users/user_profile.html:87
msgid "MFA" msgid "MFA"
msgstr "多因子认证" msgstr "多因子认证"
@ -1204,29 +1205,33 @@ msgstr "状态(显示名称)"
msgid "MFA for display" msgid "MFA for display"
msgstr "多因子认证状态(显示名称)" msgstr "多因子认证状态(显示名称)"
#: audits/serializers.py:66 audits/serializers.py:78 ops/models/adhoc.py:247 #: audits/serializers.py:66 audits/serializers.py:81 ops/models/adhoc.py:247
#: terminal/serializers/session.py:34 #: terminal/serializers/session.py:34
msgid "Is success" msgid "Is success"
msgstr "是否成功" msgstr "是否成功"
#: audits/serializers.py:77 ops/models/command.py:26 #: audits/serializers.py:68
msgid "Hosts for display"
msgstr "主机 (显示名称)"
#: audits/serializers.py:80 ops/models/command.py:26
#: xpack/plugins/cloud/models.py:155 #: xpack/plugins/cloud/models.py:155
msgid "Result" msgid "Result"
msgstr "结果" msgstr "结果"
#: audits/serializers.py:79 terminal/serializers/storage.py:178 #: audits/serializers.py:82 terminal/serializers/storage.py:178
msgid "Hosts" msgid "Hosts"
msgstr "主机" msgstr "主机"
#: audits/serializers.py:80 #: audits/serializers.py:83
msgid "Run as" msgid "Run as"
msgstr "运行用户" msgstr "运行用户"
#: audits/serializers.py:82 #: audits/serializers.py:85
msgid "Run as for display" msgid "Run as for display"
msgstr "运行用户(显示名称)" msgstr "运行用户(显示名称)"
#: audits/serializers.py:83 #: audits/serializers.py:86
msgid "User for display" msgid "User for display"
msgstr "用户(显示名称)" msgstr "用户(显示名称)"
@ -1349,8 +1354,8 @@ msgid ""
"after {} minutes)" "after {} minutes)"
msgstr "账号已被锁定(请联系管理员解锁 或 {}分钟后重试)" msgstr "账号已被锁定(请联系管理员解锁 或 {}分钟后重试)"
#: authentication/errors.py:55 users/views/profile/otp.py:110 #: authentication/errors.py:55 users/views/profile/otp.py:107
#: users/views/profile/otp.py:149 users/views/profile/otp.py:169 #: users/views/profile/otp.py:146 users/views/profile/otp.py:166
msgid "MFA code invalid, or ntp sync server time" msgid "MFA code invalid, or ntp sync server time"
msgstr "MFA验证码不正确或者服务器端时间不对" msgstr "MFA验证码不正确或者服务器端时间不对"
@ -1399,7 +1404,7 @@ msgstr "多因子认证验证码"
msgid "Private Token" msgid "Private Token"
msgstr "SSH密钥" msgstr "SSH密钥"
#: authentication/models.py:94 #: authentication/models.py:96
msgid "Expired" msgid "Expired"
msgstr "过期时间" msgstr "过期时间"
@ -1429,7 +1434,7 @@ msgid "Show"
msgstr "显示" msgstr "显示"
#: authentication/templates/authentication/_access_key_modal.html:66 #: authentication/templates/authentication/_access_key_modal.html:66
#: users/models/user.py:445 users/serializers/profile.py:99 #: users/models/user.py:445 users/serializers/profile.py:96
#: users/templates/users/user_profile.html:94 #: 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
@ -1438,7 +1443,7 @@ msgid "Disable"
msgstr "禁用" msgstr "禁用"
#: authentication/templates/authentication/_access_key_modal.html:67 #: authentication/templates/authentication/_access_key_modal.html:67
#: users/models/user.py:446 users/serializers/profile.py:100 #: users/models/user.py:446 users/serializers/profile.py:97
#: users/templates/users/user_profile.html:92 #: 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"
@ -1487,30 +1492,30 @@ msgstr "确认"
msgid "Code error" msgid "Code error"
msgstr "代码错误" msgstr "代码错误"
#: authentication/templates/authentication/login.html:141 #: authentication/templates/authentication/login.html:148
msgid "Welcome back, please enter username and password to login" msgid "Welcome back, please enter username and password to login"
msgstr "欢迎回来,请输入用户名和密码登录" msgstr "欢迎回来,请输入用户名和密码登录"
#: authentication/templates/authentication/login.html:167 #: authentication/templates/authentication/login.html:174
#: users/templates/users/forgot_password.html:15 #: users/templates/users/forgot_password.html:15
#: users/templates/users/forgot_password.html:16 #: users/templates/users/forgot_password.html:16
msgid "Forgot password" msgid "Forgot password"
msgstr "忘记密码" msgstr "忘记密码"
#: authentication/templates/authentication/login.html:174 #: authentication/templates/authentication/login.html:181
#: templates/_header_bar.html:83 #: templates/_header_bar.html:83
msgid "Login" msgid "Login"
msgstr "登录" msgstr "登录"
#: authentication/templates/authentication/login.html:181 #: authentication/templates/authentication/login.html:188
msgid "More login options" msgid "More login options"
msgstr "更多登录方式" msgstr "更多登录方式"
#: authentication/templates/authentication/login.html:184 #: authentication/templates/authentication/login.html:191
msgid "OpenID" msgid "OpenID"
msgstr "OpenID" msgstr "OpenID"
#: authentication/templates/authentication/login.html:189 #: authentication/templates/authentication/login.html:196
msgid "CAS" msgid "CAS"
msgstr "" msgstr ""
@ -1833,15 +1838,15 @@ msgstr "{} 任务结束"
msgid "Date finished" msgid "Date finished"
msgstr "结束日期" msgstr "结束日期"
#: ops/models/command.py:74 #: ops/models/command.py:78
msgid "Task start" msgid "Task start"
msgstr "任务开始" msgstr "任务开始"
#: ops/models/command.py:96 #: ops/models/command.py:100
msgid "Command `{}` is forbidden ........" msgid "Command `{}` is forbidden ........"
msgstr "命令 `{}` 不允许被执行 ......." msgstr "命令 `{}` 不允许被执行 ......."
#: ops/models/command.py:109 #: ops/models/command.py:113
msgid "Task end" msgid "Task end"
msgstr "任务结束" msgstr "任务结束"
@ -1865,16 +1870,21 @@ msgstr "更新任务内容: {}"
msgid "Disk used more than 80%: {} => {}" msgid "Disk used more than 80%: {} => {}"
msgstr "磁盘使用率超过 80%: {} => {}" msgstr "磁盘使用率超过 80%: {} => {}"
#: orgs/api.py:64 #: orgs/api.py:76
msgid "Organization contains undeleted resources" #, python-brace-format
msgstr "组织包含未删除的资源" msgid "Have `{model._meta.verbose_name}` exists, Please delete"
msgstr "`{model._meta.verbose_name}` 存在数据, 请先删除"
#: orgs/api.py:68 #: orgs/api.py:80
msgid "The current organization cannot be deleted" msgid "The current organization cannot be deleted"
msgstr "当前组织不能被删除" msgstr "当前组织不能被删除"
#: orgs/mixins/api.py:46
msgid "Root organization only allow view and delete"
msgstr "全局组织仅支持 查看和删除"
#: orgs/mixins/models.py:45 orgs/mixins/serializers.py:25 orgs/models.py:36 #: orgs/mixins/models.py:45 orgs/mixins/serializers.py:25 orgs/models.py:36
#: orgs/models.py:402 orgs/serializers.py:101 #: orgs/models.py:416 orgs/serializers.py:101
#: tickets/serializers/ticket/ticket.py:81 #: tickets/serializers/ticket/ticket.py:81
msgid "Organization" msgid "Organization"
msgstr "组织" msgstr "组织"
@ -1891,7 +1901,7 @@ msgstr "组织审计员"
msgid "GLOBAL" msgid "GLOBAL"
msgstr "全局组织" msgstr "全局组织"
#: orgs/models.py:404 users/models/user.py:540 #: orgs/models.py:418 users/models/user.py:540
#: users/templates/users/_select_user_modal.html:15 #: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:73 #: users/templates/users/user_detail.html:73
#: users/templates/users/user_list.html:16 #: users/templates/users/user_list.html:16
@ -1899,14 +1909,6 @@ msgstr "全局组织"
msgid "Role" msgid "Role"
msgstr "角色" msgstr "角色"
#: perms/const.py:7 perms/models/asset_permission.py:189
msgid "Ungrouped"
msgstr "未分组"
#: perms/const.py:10
msgid "Empty"
msgstr "空"
#: perms/exceptions.py:9 #: perms/exceptions.py:9
msgid "The administrator is modifying permissions. Please wait" msgid "The administrator is modifying permissions. Please wait"
msgstr "管理员正在修改授权,请稍等" msgstr "管理员正在修改授权,请稍等"
@ -1965,6 +1967,10 @@ msgstr "动作"
msgid "Asset permission" msgid "Asset permission"
msgstr "资产授权" msgstr "资产授权"
#: perms/models/asset_permission.py:189
msgid "Ungrouped"
msgstr "未分组"
#: perms/models/asset_permission.py:191 #: perms/models/asset_permission.py:191
msgid "Favorite" msgid "Favorite"
msgstr "收藏夹" msgstr "收藏夹"
@ -1998,11 +2004,13 @@ msgid ""
"permission type. ({})" "permission type. ({})"
msgstr "应用列表中包含与授权类型不同的应用。({})" msgstr "应用列表中包含与授权类型不同的应用。({})"
#: perms/serializers/asset/permission.py:61 users/serializers/user.py:67 #: perms/serializers/asset/permission.py:43
#: perms/serializers/asset/permission.py:61 users/serializers/user.py:34
#: users/serializers/user.py:69
msgid "Is expired" msgid "Is expired"
msgstr "是否过期" msgstr "是否过期"
#: perms/serializers/asset/permission.py:62 users/serializers/user.py:66 #: perms/serializers/asset/permission.py:62 users/serializers/user.py:68
msgid "Is valid" msgid "Is valid"
msgstr "账户是否有效" msgstr "账户是否有效"
@ -2018,11 +2026,11 @@ msgstr "用户组数量"
msgid "System users amount" msgid "System users amount"
msgstr "系统用户数量" msgstr "系统用户数量"
#: settings/api/common.py:24 #: settings/api/common.py:25
msgid "Test mail sent to {}, please check" msgid "Test mail sent to {}, please check"
msgstr "邮件已经发送{}, 请检查" msgstr "邮件已经发送{}, 请检查"
#: settings/api/common.py:110 xpack/plugins/interface/api.py:18 #: settings/api/common.py:100 xpack/plugins/interface/api.py:18
#: xpack/plugins/interface/models.py:36 #: xpack/plugins/interface/models.py:36
msgid "Welcome to the JumpServer open source Bastion Host" msgid "Welcome to the JumpServer open source Bastion Host"
msgstr "欢迎使用JumpServer开源堡垒机" msgstr "欢迎使用JumpServer开源堡垒机"
@ -2910,19 +2918,23 @@ msgstr "不允许删除默认存储配置"
msgid "Cannot delete storage that is being used" msgid "Cannot delete storage that is being used"
msgstr "不允许删除正在使用的存储配置" msgstr "不允许删除正在使用的存储配置"
#: terminal/api/storage.py:66 terminal/api/storage.py:67 #: terminal/api/storage.py:72 terminal/api/storage.py:73
msgid "Command storages" msgid "Command storages"
msgstr "命令存储" msgstr "命令存储"
#: terminal/api/storage.py:104 #: terminal/api/storage.py:79
msgid "Invalid"
msgstr "无效"
#: terminal/api/storage.py:122
msgid "Test failure: {}" msgid "Test failure: {}"
msgstr "测试失败: {}" msgstr "测试失败: {}"
#: terminal/api/storage.py:107 #: terminal/api/storage.py:125
msgid "Test successful" msgid "Test successful"
msgstr "测试成功" msgstr "测试成功"
#: terminal/api/storage.py:109 #: terminal/api/storage.py:127
msgid "Test failure: Account invalid" msgid "Test failure: Account invalid"
msgstr "测试失败: 账户无效" msgstr "测试失败: 账户无效"
@ -2983,6 +2995,10 @@ msgstr "正常"
msgid "Bulk create not support" msgid "Bulk create not support"
msgstr "不支持批量创建" msgstr "不支持批量创建"
#: terminal/exceptions.py:13
msgid "Storage is invalid"
msgstr "存储无效"
#: terminal/models/session.py:43 #: terminal/models/session.py:43
msgid "Login from" msgid "Login from"
msgstr "登录来源" msgstr "登录来源"
@ -3423,10 +3439,6 @@ msgstr "受理人"
msgid "Assignees display" msgid "Assignees display"
msgstr "受理人 (显示名称)" msgstr "受理人 (显示名称)"
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:24
msgid "Category display"
msgstr "类别 (显示名称)"
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:31 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:31
#: tickets/serializers/ticket/ticket.py:19 #: tickets/serializers/ticket/ticket.py:19
msgid "Type display" msgid "Type display"
@ -3558,7 +3570,7 @@ msgstr "工单已处理 - {} ({})"
msgid "Your ticket has been processed, processor - {}" msgid "Your ticket has been processed, processor - {}"
msgstr "你的工单已被处理, 处理人 - {}" msgstr "你的工单已被处理, 处理人 - {}"
#: users/api/user.py:200 #: users/api/user.py:212
msgid "Could not reset self otp, use profile reset instead" msgid "Could not reset self otp, use profile reset instead"
msgstr "不能在该页面重置多因子认证, 请去个人信息页面重置" msgstr "不能在该页面重置多因子认证, 请去个人信息页面重置"
@ -3638,8 +3650,8 @@ 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:74 #: users/forms/profile.py:149 users/serializers/profile.py:71
#: users/serializers/profile.py:147 users/serializers/profile.py:160 #: users/serializers/profile.py:144 users/serializers/profile.py:157
msgid "Not a valid ssh public key" msgid "Not a valid ssh public key"
msgstr "SSH密钥不合法" msgstr "SSH密钥不合法"
@ -3677,27 +3689,27 @@ msgstr "用户来源"
msgid "Date password last updated" msgid "Date password last updated"
msgstr "最后更新密码日期" msgstr "最后更新密码日期"
#: users/models/user.py:685 #: users/models/user.py:707
msgid "Administrator" msgid "Administrator"
msgstr "管理员" msgstr "管理员"
#: users/models/user.py:688 #: users/models/user.py:710
msgid "Administrator is the super user of system" msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员" msgstr "Administrator是初始的超级管理员"
#: users/serializers/profile.py:32 #: users/serializers/profile.py:29
msgid "The old password is incorrect" msgid "The old password is incorrect"
msgstr "旧密码错误" msgstr "旧密码错误"
#: users/serializers/profile.py:40 users/serializers/user.py:112 #: users/serializers/profile.py:37 users/serializers/user.py:112
msgid "Password does not match security rules" msgid "Password does not match security rules"
msgstr "密码不满足安全规则" msgstr "密码不满足安全规则"
#: users/serializers/profile.py:46 #: users/serializers/profile.py:43
msgid "The newly set password is inconsistent" msgid "The newly set password is inconsistent"
msgstr "两次密码不一致" msgstr "两次密码不一致"
#: users/serializers/profile.py:118 users/serializers/user.py:65 #: users/serializers/profile.py:115 users/serializers/user.py:67
msgid "Is first login" msgid "Is first login"
msgstr "首次登录" msgstr "首次登录"
@ -3715,58 +3727,58 @@ msgid "Password strategy"
msgstr "密码策略" msgstr "密码策略"
#: users/serializers/user.py:30 #: users/serializers/user.py:30
msgid "MFA level for display"
msgstr "多因子认证等级(显示名称)"
#: users/serializers/user.py:31
msgid "Login blocked"
msgstr "登录被阻塞"
#: users/serializers/user.py:32
msgid "Can update"
msgstr "是否可更新"
#: users/serializers/user.py:33
msgid "Can delete"
msgstr "是否可删除"
#: users/serializers/user.py:35 users/serializers/user.py:72
msgid "Organization role name"
msgstr "组织角色名称"
#: users/serializers/user.py:68
msgid "Avatar url"
msgstr "头像路径"
#: users/serializers/user.py:70
msgid "Groups name"
msgstr "用户组名"
#: users/serializers/user.py:71
msgid "Source name"
msgstr "用户来源名"
#: users/serializers/user.py:73
msgid "Super role name"
msgstr "超级角色名称"
#: users/serializers/user.py:74
msgid "Total role name"
msgstr "汇总角色名称"
#: users/serializers/user.py:75
msgid "MFA enabled" msgid "MFA enabled"
msgstr "是否开启多因子认证" msgstr "是否开启多因子认证"
#: users/serializers/user.py:76 #: users/serializers/user.py:31
msgid "MFA force enabled" msgid "MFA force enabled"
msgstr "强制启用多因子认证" msgstr "强制启用多因子认证"
#: users/serializers/user.py:32
msgid "MFA level for display"
msgstr "多因子认证等级(显示名称)"
#: users/serializers/user.py:33
msgid "Login blocked"
msgstr "登录被阻塞"
#: users/serializers/user.py:35
msgid "Can update"
msgstr "是否可更新"
#: users/serializers/user.py:36
msgid "Can delete"
msgstr "是否可删除"
#: users/serializers/user.py:38 users/serializers/user.py:74
msgid "Organization role name"
msgstr "组织角色名称"
#: users/serializers/user.py:70
msgid "Avatar url"
msgstr "头像路径"
#: users/serializers/user.py:72
msgid "Groups name"
msgstr "用户组名"
#: users/serializers/user.py:73
msgid "Source name"
msgstr "用户来源名"
#: users/serializers/user.py:75
msgid "Super role name"
msgstr "超级角色名称"
#: users/serializers/user.py:76
msgid "Total role name"
msgstr "汇总角色名称"
#: users/serializers/user.py:100 #: users/serializers/user.py:100
msgid "Role limit to {}" msgid "Role limit to {}"
msgstr "角色只能为 {}" msgstr "角色只能为 {}"
#: users/serializers/user.py:202 #: users/serializers/user.py:197
msgid "name not unique" msgid "name not unique"
msgstr "名称重复" msgstr "名称重复"
@ -4591,19 +4603,19 @@ msgstr ""
" <br>\n" " <br>\n"
" " " "
#: users/views/profile/otp.py:193 #: users/views/profile/otp.py:190
msgid "MFA enable success" msgid "MFA enable success"
msgstr "多因子认证启用成功" msgstr "多因子认证启用成功"
#: users/views/profile/otp.py:194 #: users/views/profile/otp.py:191
msgid "MFA enable success, return login page" msgid "MFA enable success, return login page"
msgstr "多因子认证启用成功,返回到登录页面" msgstr "多因子认证启用成功,返回到登录页面"
#: users/views/profile/otp.py:196 #: users/views/profile/otp.py:193
msgid "MFA disable success" msgid "MFA disable success"
msgstr "多因子认证禁用成功" msgstr "多因子认证禁用成功"
#: users/views/profile/otp.py:197 #: users/views/profile/otp.py:194
msgid "MFA disable success, return login page" msgid "MFA disable success, return login page"
msgstr "多因子认证禁用成功,返回登录页面" msgstr "多因子认证禁用成功,返回登录页面"
@ -5098,7 +5110,7 @@ msgstr "许可证导入成功"
msgid "License is invalid" msgid "License is invalid"
msgstr "无效的许可证" msgstr "无效的许可证"
#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:124 #: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:127
msgid "License" msgid "License"
msgstr "许可证" msgstr "许可证"
@ -5117,3 +5129,14 @@ msgstr "旗舰版"
#: xpack/plugins/license/models.py:77 #: xpack/plugins/license/models.py:77
msgid "Community edition" msgid "Community edition"
msgstr "社区版" msgstr "社区版"
#~ msgid ""
#~ "Push system user task skip, auto push not enable or protocol is not ssh "
#~ "or rdp: {}"
#~ msgstr "推送系统用户任务跳过自动推送没有打开或协议不是ssh或rdp: {}"
#~ msgid "Empty"
#~ msgstr "空"
#~ msgid "Organization contains undeleted resources"
#~ msgstr "组织包含未删除的资源"

View File

@ -53,7 +53,7 @@ class AdHocDisplay(Display, metaclass=UnSingleton):
# 这里先不 flushlog 文件不需要那么及时。 # 这里先不 flushlog 文件不需要那么及时。
self.log_file.write(msg) self.log_file.write(msg)
def display(self, msg, color=None, stderr=False, screen_only=False, log_only=False): def display(self, msg, color=None, stderr=False, screen_only=False, log_only=False, newline=True):
if color: if color:
msg = stringc(msg, color) msg = stringc(msg, color)
@ -62,5 +62,7 @@ class AdHocDisplay(Display, metaclass=UnSingleton):
else: else:
msg2 = msg msg2 = msg
self._write_to_screen(msg2, stderr) if log_only:
self._write_to_log_file(msg2) self._write_to_log_file(msg2)
else:
self._write_to_screen(msg2, stderr)

View File

@ -11,7 +11,7 @@ default_id = '00000000-0000-0000-0000-000000000002'
def add_default_org(apps, schema_editor): def add_default_org(apps, schema_editor):
org_cls = apps.get_model('orgs', 'Organization') org_cls = apps.get_model('orgs', 'Organization')
defaults = {'name': 'DEFAULT', 'id': default_id} defaults = {'name': 'Default', 'id': default_id}
org_cls.objects.get_or_create(defaults=defaults, id=default_id) org_cls.objects.get_or_create(defaults=defaults, id=default_id)

View File

@ -2,6 +2,9 @@
# #
from rest_framework.viewsets import ModelViewSet, GenericViewSet from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework_bulk import BulkModelViewSet from rest_framework_bulk import BulkModelViewSet
from rest_framework.exceptions import MethodNotAllowed
from django.utils.translation import ugettext_lazy as _
from common.mixins import CommonApiMixin, RelationMixin from common.mixins import CommonApiMixin, RelationMixin
from orgs.utils import current_org from orgs.utils import current_org
@ -39,15 +42,29 @@ class OrgQuerySetMixin:
return queryset return queryset
class OrgModelViewSet(CommonApiMixin, OrgQuerySetMixin, ModelViewSet): class OrgViewSetMixin(OrgQuerySetMixin):
root_org_readonly_msg = _("Root organization only allow view and delete")
def update(self, request, *args, **kwargs):
if current_org.is_root():
raise MethodNotAllowed('put', self.root_org_readonly_msg)
return super().update(request, *args, **kwargs)
def create(self, request, *args, **kwargs):
if current_org.is_root():
raise MethodNotAllowed('post', self.root_org_readonly_msg)
return super().update(request, *args, **kwargs)
class OrgModelViewSet(CommonApiMixin, OrgViewSetMixin, ModelViewSet):
pass pass
class OrgGenericViewSet(CommonApiMixin, OrgQuerySetMixin, GenericViewSet): class OrgGenericViewSet(CommonApiMixin, OrgViewSetMixin, GenericViewSet):
pass pass
class OrgBulkModelViewSet(CommonApiMixin, OrgQuerySetMixin, BulkModelViewSet): class OrgBulkModelViewSet(CommonApiMixin, OrgViewSetMixin, BulkModelViewSet):
def allow_bulk_destroy(self, qs, filtered): def allow_bulk_destroy(self, qs, filtered):
qs_count = qs.count() qs_count = qs.count()
filtered_count = filtered.count() filtered_count = filtered.count()

View File

@ -5,7 +5,7 @@ from django.dispatch import receiver
from users.models import User from users.models import User
from assets.models import Asset from assets.models import Asset
from orgs.utils import current_org from orgs.utils import current_org, tmp_to_org
from common.utils import get_logger from common.utils import get_logger
from common.exceptions import M2MReverseNotAllowed from common.exceptions import M2MReverseNotAllowed
from common.const.signals import POST_ADD, POST_REMOVE, POST_CLEAR from common.const.signals import POST_ADD, POST_REMOVE, POST_CLEAR
@ -18,24 +18,28 @@ logger = get_logger(__file__)
@receiver(m2m_changed, sender=User.groups.through) @receiver(m2m_changed, sender=User.groups.through)
def on_user_groups_change(sender, instance, action, reverse, pk_set, **kwargs): def on_user_groups_change(sender, instance, action, reverse, pk_set, **kwargs):
if action.startswith('post'): if not action.startswith('post'):
if reverse: return
group_ids = [instance.id] if reverse:
user_ids = pk_set group_ids = [instance.id]
else: user_ids = pk_set
group_ids = pk_set else:
user_ids = [instance.id] group_ids = pk_set
user_ids = [instance.id]
exists = AssetPermission.user_groups.through.objects.filter(usergroup_id__in=group_ids).exists() exists = AssetPermission.user_groups.through.objects.filter(usergroup_id__in=group_ids).exists()
if exists: if not exists:
org_ids = [current_org.id] return
UserGrantedTreeRefreshController.add_need_refresh_orgs_for_users(org_ids, user_ids) with tmp_to_org(instance.org):
org_ids = [current_org.id]
UserGrantedTreeRefreshController.add_need_refresh_orgs_for_users(org_ids, user_ids)
@receiver([pre_delete], sender=AssetPermission) @receiver([pre_delete], sender=AssetPermission)
def on_asset_perm_pre_delete(sender, instance, **kwargs): def on_asset_perm_pre_delete(sender, instance, **kwargs):
# 授权删除之前,查出所有相关用户 # 授权删除之前,查出所有相关用户
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id]) with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id])
@receiver([pre_save], sender=AssetPermission) @receiver([pre_save], sender=AssetPermission)
@ -44,14 +48,17 @@ def on_asset_perm_pre_save(sender, instance, **kwargs):
old = AssetPermission.objects.get(id=instance.id) old = AssetPermission.objects.get(id=instance.id)
if old.is_valid != instance.is_valid: if old.is_valid != instance.is_valid:
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id]) with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id])
except AssetPermission.DoesNotExist: except AssetPermission.DoesNotExist:
pass pass
@receiver([post_save], sender=AssetPermission) @receiver([post_save], sender=AssetPermission)
def on_asset_perm_post_save(sender, instance, created, **kwargs): def on_asset_perm_post_save(sender, instance, created, **kwargs):
if created: if not created:
return
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id]) UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id])
@ -64,7 +71,10 @@ def on_permission_nodes_changed(sender, instance, action, reverse, **kwargs):
if reverse: if reverse:
raise M2MReverseNotAllowed raise M2MReverseNotAllowed
if need_rebuild_mapping_node(action): if not need_rebuild_mapping_node(action):
return
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id]) UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id])
@ -73,28 +83,38 @@ def on_permission_assets_changed(sender, instance, action, reverse, pk_set, mode
if reverse: if reverse:
raise M2MReverseNotAllowed raise M2MReverseNotAllowed
if need_rebuild_mapping_node(action): if not need_rebuild_mapping_node(action):
return
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id]) UserGrantedTreeRefreshController.add_need_refresh_by_asset_perm_ids([instance.id])
@receiver(m2m_changed, sender=AssetPermission.users.through) @receiver(m2m_changed, sender=AssetPermission.users.through)
def on_asset_permission_users_changed(sender, action, reverse, pk_set, **kwargs): def on_asset_permission_users_changed(sender, action, reverse, instance, pk_set, **kwargs):
if reverse: if reverse:
raise M2MReverseNotAllowed raise M2MReverseNotAllowed
if need_rebuild_mapping_node(action): if not need_rebuild_mapping_node(action):
return
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_orgs_for_users( UserGrantedTreeRefreshController.add_need_refresh_orgs_for_users(
[current_org.id], pk_set [current_org.id], pk_set
) )
@receiver(m2m_changed, sender=AssetPermission.user_groups.through) @receiver(m2m_changed, sender=AssetPermission.user_groups.through)
def on_asset_permission_user_groups_changed(sender, action, pk_set, reverse, **kwargs): def on_asset_permission_user_groups_changed(sender, instance, action, pk_set, reverse, **kwargs):
if reverse: if reverse:
raise M2MReverseNotAllowed raise M2MReverseNotAllowed
if need_rebuild_mapping_node(action): if not need_rebuild_mapping_node(action):
user_ids = User.groups.through.objects.filter(usergroup_id__in=pk_set).distinct().values_list('user_id', flat=True) return
user_ids = User.groups.through.objects.filter(usergroup_id__in=pk_set) \
.values_list('user_id', flat=True) \
.distinct()
with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_orgs_for_users( UserGrantedTreeRefreshController.add_need_refresh_orgs_for_users(
[current_org.id], user_ids [current_org.id], user_ids
) )
@ -112,4 +132,5 @@ def on_node_asset_change(action, instance, reverse, pk_set, **kwargs):
asset_pk_set = [instance.id] asset_pk_set = [instance.id]
node_pk_set = pk_set node_pk_set = pk_set
UserGrantedTreeRefreshController.add_need_refresh_on_nodes_assets_relate_change(node_pk_set, asset_pk_set) with tmp_to_org(instance.org):
UserGrantedTreeRefreshController.add_need_refresh_on_nodes_assets_relate_change(node_pk_set, asset_pk_set)

View File

@ -10,6 +10,7 @@ from django.core.mail import send_mail, get_connection
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.templatetags.static import static from django.templatetags.static import static
from jumpserver.utils import has_valid_xpack_license
from common.permissions import IsSuperUser from common.permissions import IsSuperUser
from common.utils import get_logger from common.utils import get_logger
from .. import serializers from .. import serializers
@ -94,14 +95,6 @@ class PublicSettingApi(generics.RetrieveAPIView):
logo_urls.update({attr: getattr(obj, attr).url}) logo_urls.update({attr: getattr(obj, attr).url})
return logo_urls return logo_urls
@staticmethod
def get_xpack_license_is_valid():
if not settings.XPACK_ENABLED:
return False
from xpack.plugins.license.models import License
return License.has_valid_license()
@staticmethod @staticmethod
def get_login_title(): def get_login_title():
default_title = _('Welcome to the JumpServer open source Bastion Host') default_title = _('Welcome to the JumpServer open source Bastion Host')
@ -121,7 +114,7 @@ class PublicSettingApi(generics.RetrieveAPIView):
"SECURITY_MFA_VERIFY_TTL": settings.SECURITY_MFA_VERIFY_TTL, "SECURITY_MFA_VERIFY_TTL": settings.SECURITY_MFA_VERIFY_TTL,
"SECURITY_COMMAND_EXECUTION": settings.SECURITY_COMMAND_EXECUTION, "SECURITY_COMMAND_EXECUTION": settings.SECURITY_COMMAND_EXECUTION,
"SECURITY_PASSWORD_EXPIRATION_TIME": settings.SECURITY_PASSWORD_EXPIRATION_TIME, "SECURITY_PASSWORD_EXPIRATION_TIME": settings.SECURITY_PASSWORD_EXPIRATION_TIME,
"XPACK_LICENSE_IS_VALID": self.get_xpack_license_is_valid(), "XPACK_LICENSE_IS_VALID": has_valid_xpack_license(),
"LOGIN_TITLE": self.get_login_title(), "LOGIN_TITLE": self.get_login_title(),
"LOGO_URLS": self.get_logo_urls(), "LOGO_URLS": self.get_logo_urls(),
"TICKETS_ENABLED": settings.TICKETS_ENABLED, "TICKETS_ENABLED": settings.TICKETS_ENABLED,

View File

@ -11,7 +11,7 @@ from rest_framework.response import Response
from rest_framework.decorators import action from rest_framework.decorators import action
from django.template import loader from django.template import loader
from terminal.models import CommandStorage from terminal.models import CommandStorage, Command
from terminal.filters import CommandFilter from terminal.filters import CommandFilter
from orgs.utils import current_org from orgs.utils import current_org
from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor, IsAppUser from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor, IsAppUser
@ -19,6 +19,7 @@ from common.const.http import GET
from common.utils import get_logger from common.utils import get_logger
from terminal.utils import send_command_alert_mail from terminal.utils import send_command_alert_mail
from terminal.serializers import InsecureCommandAlertSerializer from terminal.serializers import InsecureCommandAlertSerializer
from terminal.exceptions import StorageInvalid
from ..backends import ( from ..backends import (
get_command_storage, get_multi_command_storage, get_command_storage, get_multi_command_storage,
SessionCommandSerializer, SessionCommandSerializer,
@ -116,9 +117,12 @@ class CommandViewSet(viewsets.ModelViewSet):
storages = CommandStorage.objects.all() storages = CommandStorage.objects.all()
for storage in storages: for storage in storages:
if not storage.is_valid():
continue
qs = storage.get_command_queryset() qs = storage.get_command_queryset()
commands = self.filter_queryset(qs) commands = self.filter_queryset(qs)
merged_commands.extend(commands) merged_commands.extend(commands[:]) # ES 默认只取 10 条数据
merged_commands.sort(key=lambda command: command.timestamp, reverse=True) merged_commands.sort(key=lambda command: command.timestamp, reverse=True)
page = self.paginate_queryset(merged_commands) page = self.paginate_queryset(merged_commands)
@ -126,7 +130,7 @@ class CommandViewSet(viewsets.ModelViewSet):
serializer = self.get_serializer(page, many=True) serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data) return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True) serializer = self.get_serializer(merged_commands, many=True)
return Response(serializer.data) return Response(serializer.data)
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
@ -141,7 +145,10 @@ class CommandViewSet(viewsets.ModelViewSet):
def get_queryset(self): def get_queryset(self):
command_storage_id = self.request.query_params.get('command_storage_id') command_storage_id = self.request.query_params.get('command_storage_id')
storage = CommandStorage.objects.get(id=command_storage_id) storage = CommandStorage.objects.get(id=command_storage_id)
qs = storage.get_command_queryset() if not storage.is_valid():
raise StorageInvalid
else:
qs = storage.get_command_queryset()
return qs return qs
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):

View File

@ -46,7 +46,13 @@ class CommandStorageViewSet(BaseStorageViewSetMixin, viewsets.ModelViewSet):
def tree(self, request: Request): def tree(self, request: Request):
storage_qs = self.get_queryset().exclude(name='null') storage_qs = self.get_queryset().exclude(name='null')
storages_with_count = [] storages_with_count = []
invalid_storages = []
for storage in storage_qs: for storage in storage_qs:
if not storage.is_valid():
invalid_storages.append(storage)
continue
command_qs = storage.get_command_queryset() command_qs = storage.get_command_queryset()
filterset = CommandFilter( filterset = CommandFilter(
data=request.query_params, queryset=command_qs, data=request.query_params, queryset=command_qs,
@ -70,6 +76,7 @@ class CommandStorageViewSet(BaseStorageViewSetMixin, viewsets.ModelViewSet):
'open': True, 'open': True,
} }
invalid = _('Invalid')
nodes = [ nodes = [
{ {
'id': storage.id, 'id': storage.id,
@ -78,7 +85,18 @@ class CommandStorageViewSet(BaseStorageViewSetMixin, viewsets.ModelViewSet):
'pId': 'root', 'pId': 'root',
'isParent': False, 'isParent': False,
'open': False, 'open': False,
'valid': True,
} for storage, command_count in storages_with_count } for storage, command_count in storages_with_count
] + [
{
'id': storage.id,
'name': f'{storage.name}({storage.type}) *{invalid}',
'title': f'{storage.name}({storage.type})',
'pId': 'root',
'isParent': False,
'open': False,
'valid': False,
} for storage in invalid_storages
] ]
nodes.append(root) nodes.append(root)
return Response(data=nodes) return Response(data=nodes)

View File

@ -25,7 +25,7 @@ class CommandStore():
kwargs = config.get("OTHER", {}) kwargs = config.get("OTHER", {})
self.index = config.get("INDEX") or 'jumpserver' self.index = config.get("INDEX") or 'jumpserver'
self.doc_type = config.get("DOC_TYPE") or 'command_store' self.doc_type = config.get("DOC_TYPE") or 'command_store'
self.es = Elasticsearch(hosts=hosts, **kwargs) self.es = Elasticsearch(hosts=hosts, max_retries=0, **kwargs)
@staticmethod @staticmethod
def make_data(command): def make_data(command):
@ -81,9 +81,9 @@ class CommandStore():
"""返回所有数据""" """返回所有数据"""
raise NotImplementedError("Not support") raise NotImplementedError("Not support")
def ping(self): def ping(self, timeout=None):
try: try:
return self.es.ping() return self.es.ping(request_timeout=timeout)
except Exception: except Exception:
return False return False
@ -121,7 +121,11 @@ class CommandStore():
org_id = match.get('org_id') org_id = match.get('org_id')
real_default_org_id = '00000000-0000-0000-0000-000000000002' real_default_org_id = '00000000-0000-0000-0000-000000000002'
if org_id in (real_default_org_id, ''): root_org_id = '00000000-0000-0000-0000-000000000000'
if org_id == root_org_id:
match.pop('org_id')
elif org_id in (real_default_org_id, ''):
match.pop('org_id') match.pop('org_id')
should.append({ should.append({
'bool':{ 'bool':{
@ -256,7 +260,7 @@ class QuerySet(DJQuerySet):
clone = self.__clone() clone = self.__clone()
from_ = item.start or 0 from_ = item.start or 0
if item.stop is None: if item.stop is None:
size = 10 size = self.max_result_window - from_
else: else:
size = item.stop - from_ size = item.stop - from_

View File

@ -6,3 +6,9 @@ from common.exceptions import JMSException
class BulkCreateNotSupport(JMSException): class BulkCreateNotSupport(JMSException):
default_code = 'bulk_create_not_support' default_code = 'bulk_create_not_support'
default_detail = _('Bulk create not support') default_detail = _('Bulk create not support')
class StorageInvalid(JMSException):
default_code = 'storage_invalid'
default_detail = _('Storage is invalid')

View File

@ -52,8 +52,14 @@ class CommandStorage(CommonModelMixin):
def is_valid(self): def is_valid(self):
if self.type_null_or_server: if self.type_null_or_server:
return True return True
storage = jms_storage.get_log_storage(self.config)
return storage.ping() if self.type not in TYPE_ENGINE_MAPPING:
logger.error(f'Command storage `{self.type}` not support')
return False
engine_mod = import_module(TYPE_ENGINE_MAPPING[self.type])
store = engine_mod.CommandStore(self.config)
return store.ping(timeout=3)
def is_use(self): def is_use(self):
return Terminal.objects.filter(command_storage=self.name, is_deleted=False).exists() return Terminal.objects.filter(command_storage=self.name, is_deleted=False).exists()