diff --git a/.github/ISSUE_TEMPLATE/----.md b/.github/ISSUE_TEMPLATE/----.md index 147f42db4..47b19f79e 100644 --- a/.github/ISSUE_TEMPLATE/----.md +++ b/.github/ISSUE_TEMPLATE/----.md @@ -6,8 +6,7 @@ labels: 类型:需求 assignees: - ibuler - baijiangjie - - + - wojiushixiaobai --- **请描述您的需求或者改进建议.** diff --git a/.github/workflows/issue-comment.yml b/.github/workflows/issue-comment.yml index 5388111d7..980d701cb 100644 --- a/.github/workflows/issue-comment.yml +++ b/.github/workflows/issue-comment.yml @@ -21,17 +21,44 @@ jobs: actions: 'remove-labels' labels: '状态:待反馈' - add-label-if-not-author: + add-label-if-is-member: runs-on: ubuntu-latest - if: (github.event.issue.user.id != github.event.comment.user.id) && !github.event.issue.pull_request && (github.event.issue.state == 'open') steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Get Organization name + id: org_name + run: echo "data=$(echo '${{ github.repository }}' | cut -d '/' -f 1)" >> $GITHUB_OUTPUT + + - name: Get Organization public members + uses: octokit/request-action@v2.x + id: members + with: + route: GET /orgs/${{ steps.org_name.outputs.data }}/public_members + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Process public members data + # 将 members 中的数据转化为 login 字段的拼接字符串 + id: member_names + run: echo "data=$(echo '${{ steps.members.outputs.data }}' | jq '[.[].login] | join(",")')" >> $GITHUB_OUTPUT + + + - run: "echo members: '${{ steps.members.outputs.data }}'" + - run: "echo member names: '${{ steps.member_names.outputs.data }}'" + - run: "echo comment user: '${{ github.event.comment.user.login }}'" + - run: "echo contains? : '${{ contains(steps.member_names.outputs.data, github.event.comment.user.login) }}'" + - name: Add require replay label + if: contains(steps.member_names.outputs.data, github.event.comment.user.login) uses: actions-cool/issues-helper@v2 with: actions: 'add-labels' labels: '状态:待反馈' - name: Remove require handle label + if: contains(steps.member_names.outputs.data, github.event.comment.user.login) uses: actions-cool/issues-helper@v2 with: actions: 'remove-labels' diff --git a/apps/accounts/filters.py b/apps/accounts/filters.py index 67e243e1c..be2cf1dfd 100644 --- a/apps/accounts/filters.py +++ b/apps/accounts/filters.py @@ -45,7 +45,7 @@ class AccountFilterSet(BaseFilterSet): class Meta: model = Account - fields = ['id', 'asset_id', 'source_id'] + fields = ['id', 'asset_id', 'source_id', 'secret_type'] class GatheredAccountFilterSet(BaseFilterSet): diff --git a/apps/accounts/models/__init__.py b/apps/accounts/models/__init__.py index c40ee786d..df686a50b 100644 --- a/apps/accounts/models/__init__.py +++ b/apps/accounts/models/__init__.py @@ -1,3 +1,3 @@ -from .base import * from .account import * from .automations import * +from .base import * diff --git a/apps/accounts/serializers/account/base.py b/apps/accounts/serializers/account/base.py index b79dd51be..2f9660bd5 100644 --- a/apps/accounts/serializers/account/base.py +++ b/apps/accounts/serializers/account/base.py @@ -78,5 +78,8 @@ class BaseAccountSerializer(AuthValidateMixin, BulkOrgResourceModelSerializer): ] extra_kwargs = { 'spec_info': {'label': _('Spec info')}, - 'username': {'help_text': _("Tip: If no username is required for authentication, fill in `null`")} + 'username': {'help_text': _( + "Tip: If no username is required for authentication, fill in `null`, " + "If AD account, like `username@domain`" + )}, } diff --git a/apps/assets/api/asset/asset.py b/apps/assets/api/asset/asset.py index 81b2b8fca..affd28f03 100644 --- a/apps/assets/api/asset/asset.py +++ b/apps/assets/api/asset/asset.py @@ -121,6 +121,10 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet): NodeFilterBackend, AttrRulesFilterBackend ] + def get_queryset(self): + return super().get_queryset().prefetch_related('nodes', 'protocols')\ + .select_related('platform', 'domain') + def get_serializer_class(self): cls = super().get_serializer_class() if self.action == "retrieve": diff --git a/apps/assets/api/platform.py b/apps/assets/api/platform.py index fc32a3b5f..a6e34b38b 100644 --- a/apps/assets/api/platform.py +++ b/apps/assets/api/platform.py @@ -4,20 +4,20 @@ from rest_framework.decorators import action from rest_framework.response import Response from assets.const import AllTypes -from assets.models import Platform, Node, Asset -from assets.serializers import PlatformSerializer +from assets.models import Platform, Node, Asset, PlatformProtocol +from assets.serializers import PlatformSerializer, PlatformProtocolSerializer from common.api import JMSModelViewSet from common.permissions import IsValidUser from common.serializers import GroupedChoiceSerializer -__all__ = ['AssetPlatformViewSet', 'PlatformAutomationMethodsApi'] +__all__ = ['AssetPlatformViewSet', 'PlatformAutomationMethodsApi', 'PlatformProtocolViewSet'] class AssetPlatformViewSet(JMSModelViewSet): queryset = Platform.objects.all() serializer_classes = { 'default': PlatformSerializer, - 'categories': GroupedChoiceSerializer + 'categories': GroupedChoiceSerializer, } filterset_fields = ['name', 'category', 'type'] search_fields = ['name'] @@ -25,7 +25,7 @@ class AssetPlatformViewSet(JMSModelViewSet): 'categories': 'assets.view_platform', 'type_constraints': 'assets.view_platform', 'ops_methods': 'assets.view_platform', - 'filter_nodes_assets': 'assets.view_platform' + 'filter_nodes_assets': 'assets.view_platform', } def get_queryset(self): @@ -61,6 +61,15 @@ class AssetPlatformViewSet(JMSModelViewSet): return Response(serializer.data) +class PlatformProtocolViewSet(JMSModelViewSet): + queryset = PlatformProtocol.objects.all() + serializer_class = PlatformProtocolSerializer + filterset_fields = ['name', 'platform__name'] + rbac_perms = { + '*': 'assets.add_platform' + } + + class PlatformAutomationMethodsApi(generics.ListAPIView): permission_classes = (IsValidUser,) diff --git a/apps/assets/const/base.py b/apps/assets/const/base.py index 99ff06314..5aea334d4 100644 --- a/apps/assets/const/base.py +++ b/apps/assets/const/base.py @@ -1,7 +1,8 @@ +from django.db import models from django.db.models import TextChoices +from django.utils.translation import gettext_lazy as _ from jumpserver.utils import has_valid_xpack_license -from .protocol import Protocol class Type: @@ -28,6 +29,12 @@ class Type: ) +class FillType(models.TextChoices): + no = 'no', _('Disabled') + basic = 'basic', _('Basic') + script = 'script', _('Script') + + class BaseType(TextChoices): """ 约束应该考虑代是对平台对限制,避免多余对选项,如: mysql 开启 ssh, @@ -57,6 +64,7 @@ class BaseType(TextChoices): @classmethod def _parse_protocols(cls, protocol, tp): + from .protocol import Protocol settings = Protocol.settings() choices = protocol.get('choices', []) if choices == '__self__': diff --git a/apps/assets/const/protocol.py b/apps/assets/const/protocol.py index a0b7b7ec7..e66dde209 100644 --- a/apps/assets/const/protocol.py +++ b/apps/assets/const/protocol.py @@ -1,6 +1,8 @@ from django.db import models +from django.utils.translation import gettext_lazy as _ from common.db.models import ChoicesMixin +from .base import FillType __all__ = ['Protocol'] @@ -22,8 +24,7 @@ class Protocol(ChoicesMixin, models.TextChoices): mongodb = 'mongodb', 'MongoDB' k8s = 'k8s', 'K8S' - http = 'http', 'HTTP' - _settings = None + http = 'http', 'HTTP(s)' @classmethod def device_protocols(cls): @@ -32,16 +33,40 @@ class Protocol(ChoicesMixin, models.TextChoices): 'port': 22, 'secret_types': ['password', 'ssh_key'], 'setting': { - 'sftp_enabled': True, - 'sftp_home': '/tmp', + 'sftp_enabled': { + 'type': 'bool', + 'default': True, + 'label': _('SFTP enabled') + }, + 'sftp_home': { + 'type': 'str', + 'default': '/tmp', + 'label': _('SFTP home') + }, } }, cls.rdp: { 'port': 3389, 'secret_types': ['password'], 'setting': { - 'console': False, - 'security': 'any', + 'console': { + 'type': 'bool', + 'default': False, + 'label': _('Console'), + 'help_text': _("Connect to console session") + }, + 'security': { + 'type': 'choice', + 'choices': [('any', _('Any')), ('rdp', 'RDP'), ('tls', 'TLS'), ('nla', 'NLA')], + 'default': 'any', + 'label': _('Security'), + 'help_text': _("Security layer to use for the connection") + }, + # 'ad_domain': { + # 'type': 'str', + # "required": False, + # 'label': _('AD domain') + # } } }, cls.vnc: { @@ -56,7 +81,11 @@ class Protocol(ChoicesMixin, models.TextChoices): 'port': 5985, 'secret_types': ['password'], 'setting': { - 'use_ssl': False, + 'use_ssl': { + 'type': 'bool', + 'default': False, + 'label': _('Use SSL') + }, } }, } @@ -105,7 +134,11 @@ class Protocol(ChoicesMixin, models.TextChoices): 'required': True, 'secret_types': ['password'], 'setting': { - 'auth_username': True, + 'auth_username': { + 'type': 'bool', + 'default': False, + 'label': _('Auth username') + }, } }, } @@ -121,10 +154,28 @@ class Protocol(ChoicesMixin, models.TextChoices): cls.http: { 'port': 80, 'secret_types': ['password'], + 'label': 'HTTP(s)', 'setting': { - 'username_selector': 'name=username', - 'password_selector': 'name=password', - 'submit_selector': 'id=login_button', + 'autofill': { + 'type': 'choice', + 'choices': FillType.choices, + 'default': 'basic', + }, + 'username_selector': { + 'type': 'str', + 'default': 'name=username', + 'label': _('Username selector') + }, + 'password_selector': { + 'type': 'str', + 'default': 'name=password', + 'label': _('Password selector') + }, + 'submit_selector': { + 'type': 'str', + 'default': 'type=submit', + 'label': _('Submit selector') + } } }, } diff --git a/apps/assets/const/web.py b/apps/assets/const/web.py index bf9d9e3c8..42ea995ac 100644 --- a/apps/assets/const/web.py +++ b/apps/assets/const/web.py @@ -1,4 +1,3 @@ -from django.db import models from django.utils.translation import gettext_lazy as _ from .base import BaseType @@ -53,9 +52,3 @@ class WebTypes(BaseType): return [ cls.WEBSITE, ] - - -class FillType(models.TextChoices): - no = 'no', _('Disabled') - basic = 'basic', _('Basic') - script = 'script', _('Script') diff --git a/apps/assets/models/asset/web.py b/apps/assets/models/asset/web.py index a12965334..d46ce00c4 100644 --- a/apps/assets/models/asset/web.py +++ b/apps/assets/models/asset/web.py @@ -1,7 +1,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from assets.const.web import FillType +from assets.const import FillType from .common import Asset diff --git a/apps/assets/serializers/asset/info/spec.py b/apps/assets/serializers/asset/info/spec.py index 72be7edec..9a3dab960 100644 --- a/apps/assets/serializers/asset/info/spec.py +++ b/apps/assets/serializers/asset/info/spec.py @@ -1,7 +1,7 @@ from django.utils.translation import gettext_lazy as _ from rest_framework import serializers -from assets.const.web import FillType +from assets.const import FillType from assets.models import Database, Web from common.serializers.fields import LabeledChoiceField @@ -14,6 +14,7 @@ class DatabaseSpecSerializer(serializers.ModelSerializer): class WebSpecSerializer(serializers.ModelSerializer): autofill = LabeledChoiceField(choices=FillType.choices, label=_('Autofill')) + class Meta: model = Web fields = [ diff --git a/apps/assets/serializers/platform.py b/apps/assets/serializers/platform.py index b78e134f4..1915adcdb 100644 --- a/apps/assets/serializers/platform.py +++ b/apps/assets/serializers/platform.py @@ -1,48 +1,17 @@ +from django.db.models import QuerySet from django.utils.translation import gettext_lazy as _ from rest_framework import serializers -from assets.const.web import FillType -from common.serializers import WritableNestedModelSerializer, type_field_map +from common.serializers import ( + WritableNestedModelSerializer, type_field_map, MethodSerializer, + DictSerializer, create_serializer_class +) from common.serializers.fields import LabeledChoiceField from common.utils import lazyproperty -from ..const import Category, AllTypes +from ..const import Category, AllTypes, Protocol from ..models import Platform, PlatformProtocol, PlatformAutomation -__all__ = ["PlatformSerializer", "PlatformOpsMethodSerializer"] - - -class ProtocolSettingSerializer(serializers.Serializer): - SECURITY_CHOICES = [ - ("any", "Any"), - ("rdp", "RDP"), - ("tls", "TLS"), - ("nla", "NLA"), - ] - # RDP - console = serializers.BooleanField(required=False, default=False) - security = serializers.ChoiceField(choices=SECURITY_CHOICES, default="any") - - # SFTP - sftp_enabled = serializers.BooleanField(default=True, label=_("SFTP enabled")) - sftp_home = serializers.CharField(default="/tmp", label=_("SFTP home")) - - # HTTP - autofill = serializers.ChoiceField(default='basic', choices=FillType.choices, label=_("Autofill")) - username_selector = serializers.CharField( - default="", allow_blank=True, label=_("Username selector") - ) - password_selector = serializers.CharField( - default="", allow_blank=True, label=_("Password selector") - ) - submit_selector = serializers.CharField( - default="", allow_blank=True, label=_("Submit selector") - ) - script = serializers.JSONField(default=list, label=_("Script")) - # Redis - auth_username = serializers.BooleanField(default=False, label=_("Auth with username")) - - # WinRM - use_ssl = serializers.BooleanField(default=False, label=_("Use SSL")) +__all__ = ["PlatformSerializer", "PlatformOpsMethodSerializer", "PlatformProtocolSerializer"] class PlatformAutomationSerializer(serializers.ModelSerializer): @@ -76,7 +45,7 @@ class PlatformAutomationSerializer(serializers.ModelSerializer): class PlatformProtocolSerializer(serializers.ModelSerializer): - setting = ProtocolSettingSerializer(required=False, allow_null=True) + setting = MethodSerializer(required=False, label=_("Setting")) class Meta: model = PlatformProtocol @@ -85,6 +54,47 @@ class PlatformProtocolSerializer(serializers.ModelSerializer): "required", "default", "public", "secret_types", "setting", ] + extra_kwargs = { + "primary": { + "help_text": _( + "This protocol is primary, and it must be set when adding assets. " + "Additionally, there can only be one primary protocol." + ) + }, + "required": { + "help_text": _("This protocol is required, and it must be set when adding assets.") + }, + "default": { + "help_text": _("This protocol is default, when adding assets, it will be displayed by default.") + }, + "public": { + "help_text": _("This protocol is public, asset will show this protocol to user") + }, + } + + def get_setting_serializer(self): + request = self.context.get('request') + default_field = DictSerializer() + + if not request: + return default_field + + if self.instance and isinstance(self.instance, (QuerySet, list)): + instance = self.instance[0] + else: + instance = self.instance + + protocol = request.query_params.get('name', '') + if instance and not protocol: + protocol = instance.name + + protocol_settings = Protocol.settings() + setting_fields = protocol_settings.get(protocol, {}).get('setting') + if not setting_fields: + return default_field + setting_fields = [{'name': k, **v} for k, v in setting_fields.items()] + name = '{}ProtocolSettingSerializer'.format(protocol.capitalize()) + return create_serializer_class(name, setting_fields)() def to_file_representation(self, data): return '{name}/{port}'.format(**data) diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py index 6b5f469d0..1a1384fdf 100644 --- a/apps/assets/urls/api_urls.py +++ b/apps/assets/urls/api_urls.py @@ -21,6 +21,7 @@ router.register(r'nodes', api.NodeViewSet, 'node') router.register(r'domains', api.DomainViewSet, 'domain') router.register(r'gateways', api.GatewayViewSet, 'gateway') router.register(r'favorite-assets', api.FavoriteAssetViewSet, 'favorite-asset') +router.register(r'protocol-settings', api.PlatformProtocolViewSet, 'protocol-setting') urlpatterns = [ # path('assets//gateways/', api.AssetGatewayListApi.as_view(), name='asset-gateway-list'), @@ -46,7 +47,8 @@ urlpatterns = [ path('nodes//tasks/', api.NodeTaskCreateApi.as_view(), name='node-task-create'), path('gateways//test-connective/', api.GatewayTestConnectionApi.as_view(), name='test-gateway-connective'), - path('platform-automation-methods/', api.PlatformAutomationMethodsApi.as_view(), name='platform-automation-methods'), + path('platform-automation-methods/', api.PlatformAutomationMethodsApi.as_view(), + name='platform-automation-methods'), ] urlpatterns += router.urls diff --git a/apps/authentication/views/login.py b/apps/authentication/views/login.py index acc8ed51c..8b5696dc9 100644 --- a/apps/authentication/views/login.py +++ b/apps/authentication/views/login.py @@ -11,7 +11,7 @@ from django.conf import settings from django.contrib.auth import BACKEND_SESSION_KEY from django.contrib.auth import login as auth_login, logout as auth_logout from django.db import IntegrityError -from django.http import HttpRequest, HttpResponse +from django.http import HttpRequest from django.shortcuts import reverse, redirect from django.templatetags.static import static from django.urls import reverse_lazy @@ -204,7 +204,9 @@ class UserLoginView(mixins.AuthMixin, UserLoginContextMixin, FormView): def form_valid(self, form): if not self.request.session.test_cookie_worked(): - return HttpResponse(_("Please enable cookies and try again.")) + form.add_error(None, _("Login timeout, please try again.")) + return self.form_invalid(form) + # https://docs.djangoproject.com/en/3.1/topics/http/sessions/#setting-test-cookies self.request.session.delete_test_cookie() diff --git a/apps/jumpserver/api.py b/apps/jumpserver/api.py index b5ebd9ebc..5b26a0532 100644 --- a/apps/jumpserver/api.py +++ b/apps/jumpserver/api.py @@ -50,6 +50,10 @@ class DateTimeMixin: t = local_now() - timezone.timedelta(days=days) return t + @lazyproperty + def date_start_end(self): + return self.days_to_datetime.date(), local_now().date() + @lazyproperty def dates_list(self): now = local_now() @@ -143,101 +147,40 @@ class DatesLoginMetricMixin: operate_logs_queryset: OperateLog.objects password_change_logs_queryset: PasswordChangeLog.objects - @staticmethod - def get_cache_key(date, tp): - date_str = date.strftime("%Y%m%d") - key = "SESSION_DATE_{}_{}_{}".format(current_org.id, tp, date_str) - return key - - def __get_data_from_cache(self, date, tp): - if date == timezone.now().date(): - return None - cache_key = self.get_cache_key(date, tp) - count = cache.get(cache_key) - return count - - def __set_data_to_cache(self, date, tp, count): - cache_key = self.get_cache_key(date, tp) - cache.set(cache_key, count, 3600) - - @staticmethod - def get_date_start_2_end(d): - time_min = timezone.datetime.min.time() - time_max = timezone.datetime.max.time() - tz = timezone.get_current_timezone() - ds = timezone.datetime.combine(d, time_min).replace(tzinfo=tz) - de = timezone.datetime.combine(d, time_max).replace(tzinfo=tz) - return ds, de - - def get_date_login_count(self, date): - tp = "LOGIN-USER" - count = self.__get_data_from_cache(date, tp) - if count is not None: - return count - ds, de = self.get_date_start_2_end(date) - count = UserLoginLog.objects.filter(datetime__range=(ds, de)).count() - self.__set_data_to_cache(date, tp, count) - return count - def get_dates_metrics_total_count_login(self): - data = [] - for d in self.dates_list: - count = self.get_date_login_count(d) - data.append(count) - if len(data) == 0: - data = [0] - return data - - def get_date_user_count(self, date): - tp = "USER" - count = self.__get_data_from_cache(date, tp) - if count is not None: - return count - ds, de = self.get_date_start_2_end(date) - count = len(set(Session.objects.filter(date_start__range=(ds, de)).values_list('user_id', flat=True))) - self.__set_data_to_cache(date, tp, count) - return count + queryset = UserLoginLog.objects \ + .filter(datetime__range=(self.date_start_end)) \ + .values('datetime__date').annotate(id__count=Count(id)) \ + .order_by('datetime__date') + map_date_logincount = {i['datetime__date']: i['id__count'] for i in queryset} + return [map_date_logincount.get(d, 0) for d in self.dates_list] def get_dates_metrics_total_count_active_users(self): - data = [] - for d in self.dates_list: - count = self.get_date_user_count(d) - data.append(count) - return data - - def get_date_asset_count(self, date): - tp = "ASSET" - count = self.__get_data_from_cache(date, tp) - if count is not None: - return count - ds, de = self.get_date_start_2_end(date) - count = len(set(Session.objects.filter(date_start__range=(ds, de)).values_list('asset', flat=True))) - self.__set_data_to_cache(date, tp, count) - return count + queryset = Session.objects \ + .filter(date_start__range=(self.date_start_end)) \ + .values('date_start__date') \ + .annotate(id__count=Count('user_id', distinct=True)) \ + .order_by('date_start__date') + map_date_usercount = {i['date_start__date']: i['id__count'] for i in queryset} + return [map_date_usercount.get(d, 0) for d in self.dates_list] def get_dates_metrics_total_count_active_assets(self): - data = [] - for d in self.dates_list: - count = self.get_date_asset_count(d) - data.append(count) - return data - - def get_date_session_count(self, date): - tp = "SESSION" - count = self.__get_data_from_cache(date, tp) - if count is not None: - return count - ds, de = self.get_date_start_2_end(date) - count = Session.objects.filter(date_start__range=(ds, de)).count() - self.__set_data_to_cache(date, tp, count) - return count + queryset = Session.objects \ + .filter(date_start__range=(self.date_start_end)) \ + .values('date_start__date') \ + .annotate(id__count=Count('asset_id', distinct=True)) \ + .order_by('date_start__date') + map_date_assetcount = {i['date_start__date']: i['id__count'] for i in queryset} + return [map_date_assetcount.get(d, 0) for d in self.dates_list] def get_dates_metrics_total_count_sessions(self): - data = [] - for d in self.dates_list: - count = self.get_date_session_count(d) - data.append(count) - return data + queryset = Session.objects \ + .filter(date_start__range=(self.date_start_end)) \ + .values('date_start__date') \ + .annotate(id__count=Count(id)) \ + .order_by('date_start__date') + map_date_usercount = {i['date_start__date']: i['id__count'] for i in queryset} + return [map_date_usercount.get(d, 0) for d in self.dates_list] @lazyproperty def get_type_to_assets(self): diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 7f7ecfb1f..546a6a635 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -315,7 +315,7 @@ msgstr "理由" #: accounts/models/automations/backup_account.py:99 #: accounts/serializers/automations/change_secret.py:111 #: accounts/serializers/automations/change_secret.py:134 -#: ops/serializers/job.py:56 terminal/serializers/session.py:46 +#: ops/serializers/job.py:56 terminal/serializers/session.py:43 msgid "Is success" msgstr "成功は" @@ -485,8 +485,8 @@ msgstr "アカウントの確認" #: assets/models/cmd_filter.py:21 assets/models/domain.py:18 #: assets/models/group.py:17 assets/models/label.py:18 #: assets/models/platform.py:13 assets/models/platform.py:81 -#: assets/serializers/asset/common.py:145 assets/serializers/platform.py:99 -#: assets/serializers/platform.py:199 +#: assets/serializers/asset/common.py:145 assets/serializers/platform.py:109 +#: assets/serializers/platform.py:209 #: authentication/serializers/connect_token_secret.py:110 ops/mixin.py:21 #: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57 #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 @@ -566,7 +566,7 @@ msgstr "アカウントの存在ポリシー" #: accounts/serializers/account/account.py:180 applications/models.py:11 #: assets/models/label.py:21 assets/models/platform.py:82 #: assets/serializers/asset/common.py:121 assets/serializers/cagegory.py:8 -#: assets/serializers/platform.py:117 assets/serializers/platform.py:200 +#: assets/serializers/platform.py:127 assets/serializers/platform.py:210 #: perms/serializers/user_permission.py:26 settings/models.py:35 #: tickets/models/ticket/apply_application.py:13 msgid "Category" @@ -577,13 +577,13 @@ msgstr "カテゴリ" #: acls/serializers/command_acl.py:18 applications/models.py:14 #: assets/models/_user.py:50 assets/models/automations/base.py:20 #: assets/models/cmd_filter.py:74 assets/models/platform.py:83 -#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:101 -#: assets/serializers/platform.py:116 audits/serializers.py:48 +#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:111 +#: assets/serializers/platform.py:126 audits/serializers.py:48 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 #: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:38 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 -#: terminal/serializers/session.py:23 terminal/serializers/storage.py:224 +#: terminal/serializers/session.py:20 terminal/serializers/storage.py:224 #: terminal/serializers/storage.py:236 tickets/models/comment.py:26 #: tickets/models/flow.py:56 tickets/models/ticket/apply_application.py:16 #: tickets/models/ticket/general.py:275 tickets/serializers/flow.py:53 @@ -693,9 +693,13 @@ msgstr "キーパスワード" msgid "Spec info" msgstr "特別情報" -#: accounts/serializers/account/base.py:81 -msgid "Tip: If no username is required for authentication, fill in `null`" -msgstr "ヒント: 認証にユーザー名が必要ない場合は、null を入力してください" +#: accounts/serializers/account/base.py:82 +msgid "" +"Tip: If no username is required for authentication, fill in `null`, If AD " +"account, like `username@domain`" +msgstr "" +"ヒント: 認証にユーザー名が必要ない場合は、`null`を入力します。ADアカウントの" +"場合は、`username@domain`のようになります。" #: accounts/serializers/automations/base.py:23 #: assets/models/asset/common.py:155 assets/models/automations/base.py:18 @@ -969,7 +973,7 @@ msgstr "アプリケーション" msgid "Can match application" msgstr "アプリケーションを一致させることができます" -#: assets/api/asset/asset.py:149 +#: assets/api/asset/asset.py:153 msgid "Cannot create asset directly, you should create a host or other" msgstr "" "資産を直接作成することはできません。ホストまたはその他を作成する必要がありま" @@ -1049,6 +1053,19 @@ msgstr "テストゲートウェイ" msgid "Gather facts" msgstr "資産情報の収集" +#: assets/const/base.py:33 audits/const.py:47 +#: terminal/serializers/applet_host.py:32 +msgid "Disabled" +msgstr "無効" + +#: assets/const/base.py:34 settings/serializers/basic.py:27 +msgid "Basic" +msgstr "基本" + +#: assets/const/base.py:35 assets/models/asset/web.py:13 +msgid "Script" +msgstr "脚本" + #: assets/const/category.py:10 assets/models/asset/host.py:8 #: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:67 #: terminal/models/component/endpoint.py:13 terminal/serializers/applet.py:17 @@ -1111,28 +1128,65 @@ msgstr "ファイアウォール" msgid "Other" msgstr "その他" +#: assets/const/protocol.py:39 +msgid "SFTP enabled" +msgstr "SFTP が有効" + +#: assets/const/protocol.py:44 +msgid "SFTP home" +msgstr "SFTP ルート パス" + +#: assets/const/protocol.py:55 +msgid "Console" +msgstr "Console" + +#: assets/const/protocol.py:56 +msgid "Connect to console session" +msgstr "コンソールセッションに接続" + +#: assets/const/protocol.py:60 +msgid "Any" +msgstr "任意" + +#: assets/const/protocol.py:62 settings/serializers/security.py:151 +msgid "Security" +msgstr "セキュリティ" + +#: assets/const/protocol.py:63 +msgid "Security layer to use for the connection" +msgstr "接続に使用するセキュリティ レイヤー" + +#: assets/const/protocol.py:87 assets/models/asset/database.py:10 +#: settings/serializers/email.py:37 +msgid "Use SSL" +msgstr "SSLの使用" + +#: assets/const/protocol.py:140 +#, fuzzy +#| msgid "Auth with username" +msgid "Auth username" +msgstr "ユーザー名で認証する" + +#: assets/const/protocol.py:167 assets/models/asset/web.py:10 +msgid "Username selector" +msgstr "ユーザー名ピッカー" + +#: assets/const/protocol.py:172 assets/models/asset/web.py:11 +msgid "Password selector" +msgstr "パスワードセレクター" + +#: assets/const/protocol.py:177 assets/models/asset/web.py:12 +msgid "Submit selector" +msgstr "ボタンセレクターを確認する" + #: assets/const/types.py:222 msgid "All types" msgstr "いろんなタイプ" -#: assets/const/web.py:8 +#: assets/const/web.py:7 msgid "Website" msgstr "Webサイト" -#: assets/const/web.py:59 audits/const.py:47 -#: terminal/serializers/applet_host.py:32 -msgid "Disabled" -msgstr "無効" - -#: assets/const/web.py:60 settings/serializers/basic.py:27 -msgid "Basic" -msgstr "基本" - -#: assets/const/web.py:61 assets/models/asset/web.py:13 -#: assets/serializers/platform.py:40 -msgid "Script" -msgstr "脚本" - #: assets/exceptions.py:12 msgid "This function is not supported temporarily" msgstr "この機能は一時的にサポートされていません" @@ -1199,8 +1253,8 @@ msgstr "ユーザーと同じユーザー名" #: assets/models/_user.py:52 authentication/models/connection_token.py:41 #: authentication/serializers/connect_token_secret.py:111 -#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:21 -#: terminal/serializers/session.py:42 terminal/serializers/storage.py:68 +#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:18 +#: terminal/serializers/session.py:39 terminal/serializers/storage.py:68 msgid "Protocol" msgstr "プロトコル" @@ -1308,11 +1362,6 @@ msgstr "資産ノードを変更できます" msgid "Custom asset" msgstr "カスタム アセット" -#: assets/models/asset/database.py:10 assets/serializers/platform.py:45 -#: settings/serializers/email.py:37 -msgid "Use SSL" -msgstr "SSLの使用" - #: assets/models/asset/database.py:11 msgid "CA cert" msgstr "CA 証明書" @@ -1330,22 +1379,9 @@ msgid "Allow invalid cert" msgstr "証明書チェックを無視" #: assets/models/asset/web.py:9 assets/serializers/asset/info/spec.py:16 -#: assets/serializers/platform.py:30 msgid "Autofill" msgstr "自動充填" -#: assets/models/asset/web.py:10 assets/serializers/platform.py:32 -msgid "Username selector" -msgstr "ユーザー名ピッカー" - -#: assets/models/asset/web.py:11 assets/serializers/platform.py:35 -msgid "Password selector" -msgstr "パスワードセレクター" - -#: assets/models/asset/web.py:12 assets/serializers/platform.py:38 -msgid "Submit selector" -msgstr "ボタンセレクターを確認する" - #: assets/models/automations/base.py:22 ops/models/job.py:187 #: settings/serializers/auth/sms.py:99 msgid "Parameters" @@ -1428,7 +1464,7 @@ msgstr "ゲートウェイ" msgid "Asset group" msgstr "資産グループ" -#: assets/models/group.py:31 assets/models/platform.py:17 +#: assets/models/group.py:34 assets/models/platform.py:17 #: assets/serializers/platform.py:102 #: xpack/plugins/cloud/providers/nutanix.py:30 msgid "Default" @@ -1452,7 +1488,7 @@ msgstr "値" #: assets/models/label.py:40 assets/serializers/asset/common.py:123 #: assets/serializers/cagegory.py:6 assets/serializers/cagegory.py:13 -#: assets/serializers/platform.py:100 +#: assets/serializers/platform.py:110 #: authentication/serializers/connect_token_secret.py:121 #: common/serializers/common.py:85 perms/serializers/user_permission.py:28 #: settings/serializers/sms.py:7 @@ -1500,7 +1536,8 @@ msgstr "必要" msgid "Public" msgstr "開ける" -#: assets/models/platform.py:19 settings/serializers/settings.py:67 +#: assets/models/platform.py:19 assets/serializers/platform.py:48 +#: settings/serializers/settings.py:67 #: users/templates/users/reset_password.html:29 msgid "Setting" msgstr "設定" @@ -1514,11 +1551,11 @@ msgstr "有効化" msgid "Ansible config" msgstr "Ansible 構成" -#: assets/models/platform.py:34 assets/serializers/platform.py:63 +#: assets/models/platform.py:34 assets/serializers/platform.py:32 msgid "Ping enabled" msgstr "アセット ディスカバリを有効にする" -#: assets/models/platform.py:35 assets/serializers/platform.py:64 +#: assets/models/platform.py:35 assets/serializers/platform.py:33 msgid "Ping method" msgstr "資産検出方法" @@ -1527,12 +1564,12 @@ msgid "Ping params" msgstr "資産検出パラメータ" #: assets/models/platform.py:38 assets/models/platform.py:62 -#: assets/serializers/platform.py:65 +#: assets/serializers/platform.py:34 msgid "Gather facts enabled" msgstr "資産情報の収集を有効にする" #: assets/models/platform.py:40 assets/models/platform.py:64 -#: assets/serializers/platform.py:66 +#: assets/serializers/platform.py:35 msgid "Gather facts method" msgstr "情報収集の方法" @@ -1540,11 +1577,11 @@ msgstr "情報収集の方法" msgid "Gather facts params" msgstr "情報収集パラメータ" -#: assets/models/platform.py:44 assets/serializers/platform.py:69 +#: assets/models/platform.py:44 assets/serializers/platform.py:38 msgid "Change secret enabled" msgstr "パスワードの変更が有効" -#: assets/models/platform.py:46 assets/serializers/platform.py:70 +#: assets/models/platform.py:46 assets/serializers/platform.py:39 msgid "Change secret method" msgstr "パスワード変更モード" @@ -1552,11 +1589,11 @@ msgstr "パスワード変更モード" msgid "Change secret params" msgstr "パスワード変更パラメータ" -#: assets/models/platform.py:50 assets/serializers/platform.py:71 +#: assets/models/platform.py:50 assets/serializers/platform.py:40 msgid "Push account enabled" msgstr "アカウントのプッシュを有効にする" -#: assets/models/platform.py:52 assets/serializers/platform.py:72 +#: assets/models/platform.py:52 assets/serializers/platform.py:41 msgid "Push account method" msgstr "アカウントプッシュ方式" @@ -1564,11 +1601,11 @@ msgstr "アカウントプッシュ方式" msgid "Push account params" msgstr "アカウントプッシュパラメータ" -#: assets/models/platform.py:56 assets/serializers/platform.py:67 +#: assets/models/platform.py:56 assets/serializers/platform.py:36 msgid "Verify account enabled" msgstr "アカウントの確認をオンにする" -#: assets/models/platform.py:58 assets/serializers/platform.py:68 +#: assets/models/platform.py:58 assets/serializers/platform.py:37 msgid "Verify account method" msgstr "アカウント認証方法" @@ -1584,23 +1621,23 @@ msgstr "メタ" msgid "Internal" msgstr "ビルトイン" -#: assets/models/platform.py:89 assets/serializers/platform.py:115 +#: assets/models/platform.py:89 assets/serializers/platform.py:125 msgid "Charset" msgstr "シャーセット" -#: assets/models/platform.py:91 assets/serializers/platform.py:143 +#: assets/models/platform.py:91 assets/serializers/platform.py:153 msgid "Domain enabled" msgstr "ドメインを有効にする" -#: assets/models/platform.py:93 assets/serializers/platform.py:142 +#: assets/models/platform.py:93 assets/serializers/platform.py:152 msgid "Su enabled" msgstr "アカウントの切り替えを有効にする" -#: assets/models/platform.py:94 assets/serializers/platform.py:121 +#: assets/models/platform.py:94 assets/serializers/platform.py:131 msgid "Su method" msgstr "アカウントの切り替え方法" -#: assets/models/platform.py:95 assets/serializers/platform.py:124 +#: assets/models/platform.py:95 assets/serializers/platform.py:134 msgid "Custom fields" msgstr "カスタムフィールド" @@ -1617,7 +1654,7 @@ msgstr "" "プラットフォームタイプがスキップされた資産に合致しない、資産内の一括更新プ" "ラットフォーム" -#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:118 +#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:128 #: authentication/serializers/connect_token_secret.py:29 #: authentication/serializers/connect_token_secret.py:72 #: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:99 @@ -1733,47 +1770,60 @@ msgstr "値" msgid "Can't contains: /" msgstr "含まれない:/" -#: assets/serializers/platform.py:26 -msgid "SFTP enabled" -msgstr "SFTP が有効" - -#: assets/serializers/platform.py:27 -msgid "SFTP home" -msgstr "SFTP ルート パス" - #: assets/serializers/platform.py:42 -msgid "Auth with username" -msgstr "ユーザー名で認証する" - -#: assets/serializers/platform.py:73 msgid "Gather accounts enabled" msgstr "アカウント収集を有効にする" -#: assets/serializers/platform.py:74 +#: assets/serializers/platform.py:43 msgid "Gather accounts method" msgstr "アカウントの収集方法" -#: assets/serializers/platform.py:103 +#: assets/serializers/platform.py:60 +msgid "" +"This protocol is primary, and it must be set when adding assets. " +"Additionally, there can only be one primary protocol." +msgstr "" +"このプロトコルはプライマリであり、資産を追加するときに設定する必要がありま" +"す。また、プライマリプロトコルは1つしかありません" + +#: assets/serializers/platform.py:65 +msgid "This protocol is required, and it must be set when adding assets." +msgstr "このプロトコルは必須であり、資産を追加するときに設定する必要があります" + +#: assets/serializers/platform.py:68 +msgid "" +"This protocol is default, when adding assets, it will be displayed by " +"default." +msgstr "" +"このプロトコルはデフォルトです。資産を追加するときに、デフォルトで表示されま" +"す" + +#: assets/serializers/platform.py:71 +msgid "This protocol is public, asset will show this protocol to user" +msgstr "" +"このプロトコルは公開されており、資産はこのプロトコルをユーザーに表示します" + +#: assets/serializers/platform.py:113 msgid "Help text" msgstr "ヘルプ" -#: assets/serializers/platform.py:104 +#: assets/serializers/platform.py:114 msgid "Choices" msgstr "せんたく" -#: assets/serializers/platform.py:119 +#: assets/serializers/platform.py:129 msgid "Automation" msgstr "オートメーション" -#: assets/serializers/platform.py:144 +#: assets/serializers/platform.py:154 msgid "Default Domain" msgstr "デフォルト ドメイン" -#: assets/serializers/platform.py:153 +#: assets/serializers/platform.py:163 msgid "type is required" msgstr "タイプ このフィールドは必須です." -#: assets/serializers/platform.py:176 +#: assets/serializers/platform.py:186 msgid "Protocols is required" msgstr "同意が必要です" @@ -1917,7 +1967,7 @@ msgstr "パスワードを変更する" #: audits/const.py:35 settings/serializers/terminal.py:6 #: terminal/models/applet/host.py:25 terminal/models/component/terminal.py:163 -#: terminal/serializers/session.py:49 terminal/serializers/session.py:58 +#: terminal/serializers/session.py:46 terminal/serializers/session.py:55 msgid "Terminal" msgstr "ターミナル" @@ -3001,6 +3051,9 @@ msgstr "{} 認証へのリダイレクト" #: authentication/views/login.py:207 msgid "Please enable cookies and try again." msgstr "クッキーを有効にして、もう一度お試しください。" +#: authentication/views/login.py:207 +msgid "Login timeout, please try again." +msgstr "ログインタイムアウト、もう一度お試しください" #: authentication/views/login.py:248 msgid "User email already exists ({})" @@ -3711,7 +3764,7 @@ msgstr "保存後に実行" msgid "Job type" msgstr "タスクの種類" -#: ops/serializers/job.py:57 terminal/serializers/session.py:50 +#: ops/serializers/job.py:57 terminal/serializers/session.py:47 msgid "Is finished" msgstr "終了しました" @@ -4157,23 +4210,23 @@ msgstr "テストの成功" msgid "Test mail sent to {}, please check" msgstr "{}に送信されたテストメールを確認してください" -#: settings/api/ldap.py:173 +#: settings/api/ldap.py:176 msgid "Synchronization start, please wait." msgstr "同期開始、お待ちください。" -#: settings/api/ldap.py:177 +#: settings/api/ldap.py:180 msgid "Synchronization is running, please wait." msgstr "同期が実行中です。しばらくお待ちください。" -#: settings/api/ldap.py:182 +#: settings/api/ldap.py:185 msgid "Synchronization error: {}" msgstr "同期エラー: {}" -#: settings/api/ldap.py:220 +#: settings/api/ldap.py:223 msgid "Get ldap users is None" msgstr "Ldapユーザーを取得するにはNone" -#: settings/api/ldap.py:230 +#: settings/api/ldap.py:233 msgid "Imported {} users successfully (Organization: {})" msgstr "{} 人のユーザーを正常にインポートしました (組織: {})" @@ -5087,10 +5140,6 @@ msgstr "ログインcaptchaの有効化" msgid "Enable captcha to prevent robot authentication" msgstr "Captchaを有効にしてロボット認証を防止する" -#: settings/serializers/security.py:151 -msgid "Security" -msgstr "セキュリティ" - #: settings/serializers/security.py:154 msgid "Enable terminal register" msgstr "ターミナルレジスタの有効化" @@ -6113,35 +6162,35 @@ msgstr "" msgid "Asset IP" msgstr "資産 IP" -#: terminal/serializers/session.py:25 terminal/serializers/session.py:47 +#: terminal/serializers/session.py:22 terminal/serializers/session.py:44 msgid "Can replay" msgstr "再生できます" -#: terminal/serializers/session.py:26 terminal/serializers/session.py:48 +#: terminal/serializers/session.py:23 terminal/serializers/session.py:45 msgid "Can join" msgstr "参加できます" -#: terminal/serializers/session.py:27 terminal/serializers/session.py:51 +#: terminal/serializers/session.py:24 terminal/serializers/session.py:48 msgid "Can terminate" msgstr "終了できます" -#: terminal/serializers/session.py:43 +#: terminal/serializers/session.py:40 msgid "User ID" msgstr "ユーザーID" -#: terminal/serializers/session.py:44 +#: terminal/serializers/session.py:41 msgid "Asset ID" msgstr "資産ID" -#: terminal/serializers/session.py:45 +#: terminal/serializers/session.py:42 msgid "Login from display" msgstr "表示からのログイン" -#: terminal/serializers/session.py:52 +#: terminal/serializers/session.py:49 msgid "Terminal display" msgstr "ターミナルディスプレイ" -#: terminal/serializers/session.py:57 +#: terminal/serializers/session.py:54 msgid "Command amount" msgstr "コマンド量" @@ -7735,3 +7784,6 @@ msgstr "究極のエディション" #: xpack/plugins/license/models.py:86 msgid "Community edition" msgstr "コミュニティ版" + +#~ msgid "Please enable cookies and try again." +#~ msgstr "クッキーを有効にして、もう一度お試しください。" diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index a2e363cc0..d2b7bc7f6 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-27 16:02+0800\n" +"POT-Creation-Date: 2023-06-15 15:35+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -314,7 +314,7 @@ msgstr "原因" #: accounts/models/automations/backup_account.py:99 #: accounts/serializers/automations/change_secret.py:111 #: accounts/serializers/automations/change_secret.py:134 -#: ops/serializers/job.py:56 terminal/serializers/session.py:46 +#: ops/serializers/job.py:56 terminal/serializers/session.py:43 msgid "Is success" msgstr "是否成功" @@ -484,8 +484,8 @@ msgstr "账号验证" #: assets/models/cmd_filter.py:21 assets/models/domain.py:18 #: assets/models/group.py:17 assets/models/label.py:18 #: assets/models/platform.py:13 assets/models/platform.py:81 -#: assets/serializers/asset/common.py:145 assets/serializers/platform.py:99 -#: assets/serializers/platform.py:199 +#: assets/serializers/asset/common.py:145 assets/serializers/platform.py:109 +#: assets/serializers/platform.py:209 #: authentication/serializers/connect_token_secret.py:110 ops/mixin.py:21 #: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57 #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 @@ -562,7 +562,7 @@ msgstr "账号存在策略" #: accounts/serializers/account/account.py:180 applications/models.py:11 #: assets/models/label.py:21 assets/models/platform.py:82 #: assets/serializers/asset/common.py:121 assets/serializers/cagegory.py:8 -#: assets/serializers/platform.py:117 assets/serializers/platform.py:200 +#: assets/serializers/platform.py:127 assets/serializers/platform.py:210 #: perms/serializers/user_permission.py:26 settings/models.py:35 #: tickets/models/ticket/apply_application.py:13 msgid "Category" @@ -573,13 +573,13 @@ msgstr "类别" #: acls/serializers/command_acl.py:18 applications/models.py:14 #: assets/models/_user.py:50 assets/models/automations/base.py:20 #: assets/models/cmd_filter.py:74 assets/models/platform.py:83 -#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:101 -#: assets/serializers/platform.py:116 audits/serializers.py:48 +#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:111 +#: assets/serializers/platform.py:126 audits/serializers.py:48 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 #: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:38 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 -#: terminal/serializers/session.py:23 terminal/serializers/storage.py:224 +#: terminal/serializers/session.py:20 terminal/serializers/storage.py:224 #: terminal/serializers/storage.py:236 tickets/models/comment.py:26 #: tickets/models/flow.py:56 tickets/models/ticket/apply_application.py:16 #: tickets/models/ticket/general.py:275 tickets/serializers/flow.py:53 @@ -689,9 +689,13 @@ msgstr "密钥密码" msgid "Spec info" msgstr "特殊信息" -#: accounts/serializers/account/base.py:81 -msgid "Tip: If no username is required for authentication, fill in `null`" -msgstr "提示: 如果认证时不需要用户名,可填写为 null" +#: accounts/serializers/account/base.py:82 +msgid "" +"Tip: If no username is required for authentication, fill in `null`, If AD " +"account, like `username@domain`" +msgstr "" +"提示: 如果认证时不需要用户名,可填写为 null, 如果是 AD 账号,格式为 " +"username@domain" #: accounts/serializers/automations/base.py:23 #: assets/models/asset/common.py:155 assets/models/automations/base.py:18 @@ -964,7 +968,7 @@ msgstr "应用程序" msgid "Can match application" msgstr "匹配应用" -#: assets/api/asset/asset.py:149 +#: assets/api/asset/asset.py:153 msgid "Cannot create asset directly, you should create a host or other" msgstr "不能直接创建资产, 你应该创建主机或其他资产" @@ -1042,6 +1046,19 @@ msgstr "测试网关" msgid "Gather facts" msgstr "收集资产信息" +#: assets/const/base.py:33 audits/const.py:47 +#: terminal/serializers/applet_host.py:32 +msgid "Disabled" +msgstr "禁用" + +#: assets/const/base.py:34 settings/serializers/basic.py:27 +msgid "Basic" +msgstr "基本" + +#: assets/const/base.py:35 assets/models/asset/web.py:13 +msgid "Script" +msgstr "脚本" + #: assets/const/category.py:10 assets/models/asset/host.py:8 #: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:67 #: terminal/models/component/endpoint.py:13 terminal/serializers/applet.py:17 @@ -1104,28 +1121,63 @@ msgstr "防火墙" msgid "Other" msgstr "其它" +#: assets/const/protocol.py:39 +msgid "SFTP enabled" +msgstr "SFTP 已启用" + +#: assets/const/protocol.py:44 +msgid "SFTP home" +msgstr "SFTP 根路径" + +#: assets/const/protocol.py:55 +msgid "Console" +msgstr "控制台" + +#: assets/const/protocol.py:56 +msgid "Connect to console session" +msgstr "连接到控制台会话" + +#: assets/const/protocol.py:60 +msgid "Any" +msgstr "任意" + +#: assets/const/protocol.py:62 settings/serializers/security.py:151 +msgid "Security" +msgstr "安全" + +#: assets/const/protocol.py:63 +msgid "Security layer to use for the connection" +msgstr "连接 RDP 使用的安全层" + +#: assets/const/protocol.py:87 assets/models/asset/database.py:10 +#: settings/serializers/email.py:37 +msgid "Use SSL" +msgstr "使用 SSL" + +#: assets/const/protocol.py:140 +msgid "Auth username" +msgstr "使用用户名认证" + +#: assets/const/protocol.py:167 assets/models/asset/web.py:10 +msgid "Username selector" +msgstr "用户名选择器" + +#: assets/const/protocol.py:172 assets/models/asset/web.py:11 +msgid "Password selector" +msgstr "密码选择器" + +#: assets/const/protocol.py:177 assets/models/asset/web.py:12 +msgid "Submit selector" +msgstr "确认按钮选择器" + #: assets/const/types.py:222 msgid "All types" msgstr "所有类型" -#: assets/const/web.py:8 +#: assets/const/web.py:7 msgid "Website" msgstr "网站" -#: assets/const/web.py:59 audits/const.py:47 -#: terminal/serializers/applet_host.py:32 -msgid "Disabled" -msgstr "禁用" - -#: assets/const/web.py:60 settings/serializers/basic.py:27 -msgid "Basic" -msgstr "基本" - -#: assets/const/web.py:61 assets/models/asset/web.py:13 -#: assets/serializers/platform.py:40 -msgid "Script" -msgstr "脚本" - #: assets/exceptions.py:12 msgid "This function is not supported temporarily" msgstr "暂时不支持此功能" @@ -1192,8 +1244,8 @@ msgstr "用户名与用户相同" #: assets/models/_user.py:52 authentication/models/connection_token.py:41 #: authentication/serializers/connect_token_secret.py:111 -#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:21 -#: terminal/serializers/session.py:42 terminal/serializers/storage.py:68 +#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:18 +#: terminal/serializers/session.py:39 terminal/serializers/storage.py:68 msgid "Protocol" msgstr "协议" @@ -1301,11 +1353,6 @@ msgstr "可以修改资产节点" msgid "Custom asset" msgstr "自定义资产" -#: assets/models/asset/database.py:10 assets/serializers/platform.py:45 -#: settings/serializers/email.py:37 -msgid "Use SSL" -msgstr "使用 SSL" - #: assets/models/asset/database.py:11 msgid "CA cert" msgstr "CA 证书" @@ -1323,22 +1370,9 @@ msgid "Allow invalid cert" msgstr "忽略证书校验" #: assets/models/asset/web.py:9 assets/serializers/asset/info/spec.py:16 -#: assets/serializers/platform.py:30 msgid "Autofill" msgstr "自动代填" -#: assets/models/asset/web.py:10 assets/serializers/platform.py:32 -msgid "Username selector" -msgstr "用户名选择器" - -#: assets/models/asset/web.py:11 assets/serializers/platform.py:35 -msgid "Password selector" -msgstr "密码选择器" - -#: assets/models/asset/web.py:12 assets/serializers/platform.py:38 -msgid "Submit selector" -msgstr "确认按钮选择器" - #: assets/models/automations/base.py:22 ops/models/job.py:187 #: settings/serializers/auth/sms.py:99 msgid "Parameters" @@ -1421,7 +1455,7 @@ msgstr "网关" msgid "Asset group" msgstr "资产组" -#: assets/models/group.py:31 assets/models/platform.py:17 +#: assets/models/group.py:34 assets/models/platform.py:17 #: assets/serializers/platform.py:102 #: xpack/plugins/cloud/providers/nutanix.py:30 msgid "Default" @@ -1445,7 +1479,7 @@ msgstr "值" #: assets/models/label.py:40 assets/serializers/asset/common.py:123 #: assets/serializers/cagegory.py:6 assets/serializers/cagegory.py:13 -#: assets/serializers/platform.py:100 +#: assets/serializers/platform.py:110 #: authentication/serializers/connect_token_secret.py:121 #: common/serializers/common.py:85 perms/serializers/user_permission.py:28 #: settings/serializers/sms.py:7 @@ -1493,7 +1527,8 @@ msgstr "必须的" msgid "Public" msgstr "开放的" -#: assets/models/platform.py:19 settings/serializers/settings.py:67 +#: assets/models/platform.py:19 assets/serializers/platform.py:48 +#: settings/serializers/settings.py:67 #: users/templates/users/reset_password.html:29 msgid "Setting" msgstr "设置" @@ -1507,11 +1542,11 @@ msgstr "启用" msgid "Ansible config" msgstr "Ansible 配置" -#: assets/models/platform.py:34 assets/serializers/platform.py:63 +#: assets/models/platform.py:34 assets/serializers/platform.py:32 msgid "Ping enabled" msgstr "启用资产探活" -#: assets/models/platform.py:35 assets/serializers/platform.py:64 +#: assets/models/platform.py:35 assets/serializers/platform.py:33 msgid "Ping method" msgstr "资产探活方式" @@ -1520,12 +1555,12 @@ msgid "Ping params" msgstr "资产探活参数" #: assets/models/platform.py:38 assets/models/platform.py:62 -#: assets/serializers/platform.py:65 +#: assets/serializers/platform.py:34 msgid "Gather facts enabled" msgstr "启用收集资产信息" #: assets/models/platform.py:40 assets/models/platform.py:64 -#: assets/serializers/platform.py:66 +#: assets/serializers/platform.py:35 msgid "Gather facts method" msgstr "收集信息方式" @@ -1533,11 +1568,11 @@ msgstr "收集信息方式" msgid "Gather facts params" msgstr "收集信息参数" -#: assets/models/platform.py:44 assets/serializers/platform.py:69 +#: assets/models/platform.py:44 assets/serializers/platform.py:38 msgid "Change secret enabled" msgstr "启用改密" -#: assets/models/platform.py:46 assets/serializers/platform.py:70 +#: assets/models/platform.py:46 assets/serializers/platform.py:39 msgid "Change secret method" msgstr "改密方式" @@ -1545,11 +1580,11 @@ msgstr "改密方式" msgid "Change secret params" msgstr "改密参数" -#: assets/models/platform.py:50 assets/serializers/platform.py:71 +#: assets/models/platform.py:50 assets/serializers/platform.py:40 msgid "Push account enabled" msgstr "启用账号推送" -#: assets/models/platform.py:52 assets/serializers/platform.py:72 +#: assets/models/platform.py:52 assets/serializers/platform.py:41 msgid "Push account method" msgstr "账号推送方式" @@ -1557,11 +1592,11 @@ msgstr "账号推送方式" msgid "Push account params" msgstr "账号推送参数" -#: assets/models/platform.py:56 assets/serializers/platform.py:67 +#: assets/models/platform.py:56 assets/serializers/platform.py:36 msgid "Verify account enabled" msgstr "开启账号验证" -#: assets/models/platform.py:58 assets/serializers/platform.py:68 +#: assets/models/platform.py:58 assets/serializers/platform.py:37 msgid "Verify account method" msgstr "账号验证方式" @@ -1577,23 +1612,23 @@ msgstr "元数据" msgid "Internal" msgstr "内置" -#: assets/models/platform.py:89 assets/serializers/platform.py:115 +#: assets/models/platform.py:89 assets/serializers/platform.py:125 msgid "Charset" msgstr "编码" -#: assets/models/platform.py:91 assets/serializers/platform.py:143 +#: assets/models/platform.py:91 assets/serializers/platform.py:153 msgid "Domain enabled" msgstr "启用网域" -#: assets/models/platform.py:93 assets/serializers/platform.py:142 +#: assets/models/platform.py:93 assets/serializers/platform.py:152 msgid "Su enabled" msgstr "启用账号切换" -#: assets/models/platform.py:94 assets/serializers/platform.py:121 +#: assets/models/platform.py:94 assets/serializers/platform.py:131 msgid "Su method" msgstr "账号切换方式" -#: assets/models/platform.py:95 assets/serializers/platform.py:124 +#: assets/models/platform.py:95 assets/serializers/platform.py:134 msgid "Custom fields" msgstr "自定义属性" @@ -1608,7 +1643,7 @@ msgid "" "type" msgstr "资产中批量更新平台,不符合平台类型跳过的资产" -#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:118 +#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:128 #: authentication/serializers/connect_token_secret.py:29 #: authentication/serializers/connect_token_secret.py:72 #: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:99 @@ -1724,47 +1759,55 @@ msgstr "值" msgid "Can't contains: /" msgstr "不能包含: /" -#: assets/serializers/platform.py:26 -msgid "SFTP enabled" -msgstr "SFTP 已启用" - -#: assets/serializers/platform.py:27 -msgid "SFTP home" -msgstr "SFTP 根路径" - #: assets/serializers/platform.py:42 -msgid "Auth with username" -msgstr "使用用户名认证" - -#: assets/serializers/platform.py:73 msgid "Gather accounts enabled" msgstr "启用账号收集" -#: assets/serializers/platform.py:74 +#: assets/serializers/platform.py:43 msgid "Gather accounts method" msgstr "收集账号方式" -#: assets/serializers/platform.py:103 +#: assets/serializers/platform.py:60 +msgid "" +"This protocol is primary, and it must be set when adding assets. " +"Additionally, there can only be one primary protocol." +msgstr "该协议是主要的,添加资产时必须设置。并且只能有一个主要协议" + +#: assets/serializers/platform.py:65 +msgid "This protocol is required, and it must be set when adding assets." +msgstr "该协议是必填的,添加资产时必须设置" + +#: assets/serializers/platform.py:68 +msgid "" +"This protocol is default, when adding assets, it will be displayed by " +"default." +msgstr "该协议是默认的,添加资产时,将默认显示" + +#: assets/serializers/platform.py:71 +msgid "This protocol is public, asset will show this protocol to user" +msgstr "该协议是公开的,资产将向用户显示该协议并可以连接使用" + +#: assets/serializers/platform.py:113 msgid "Help text" msgstr "帮助" -#: assets/serializers/platform.py:104 +#: assets/serializers/platform.py:114 msgid "Choices" msgstr "选择" -#: assets/serializers/platform.py:119 +#: assets/serializers/platform.py:129 msgid "Automation" msgstr "自动化" -#: assets/serializers/platform.py:144 +#: assets/serializers/platform.py:154 msgid "Default Domain" msgstr "默认网域" -#: assets/serializers/platform.py:153 +#: assets/serializers/platform.py:163 msgid "type is required" msgstr "类型 该字段是必填项。" -#: assets/serializers/platform.py:176 +#: assets/serializers/platform.py:186 msgid "Protocols is required" msgstr "协议是必填的" @@ -1906,7 +1949,7 @@ msgstr "改密" #: audits/const.py:35 settings/serializers/terminal.py:6 #: terminal/models/applet/host.py:25 terminal/models/component/terminal.py:163 -#: terminal/serializers/session.py:49 terminal/serializers/session.py:58 +#: terminal/serializers/session.py:46 terminal/serializers/session.py:55 msgid "Terminal" msgstr "终端" @@ -2964,14 +3007,14 @@ msgid "Redirecting to {} authentication" msgstr "正在跳转到 {} 认证" #: authentication/views/login.py:207 -msgid "Please enable cookies and try again." -msgstr "设置你的浏览器支持cookie" +msgid "Login timeout, please try again." +msgstr "登录超时,请重新登录" -#: authentication/views/login.py:248 +#: authentication/views/login.py:247 msgid "User email already exists ({})" msgstr "用户邮箱已存在 ({})" -#: authentication/views/login.py:326 +#: authentication/views/login.py:325 msgid "" "Wait for {} confirm, You also can copy link to her/him
\n" " Don't close this page" @@ -2979,15 +3022,15 @@ msgstr "" "等待 {} 确认, 你也可以复制链接发给他/她
\n" " 不要关闭本页面" -#: authentication/views/login.py:331 +#: authentication/views/login.py:330 msgid "No ticket found" msgstr "没有发现工单" -#: authentication/views/login.py:367 +#: authentication/views/login.py:366 msgid "Logout success" msgstr "退出登录成功" -#: authentication/views/login.py:368 +#: authentication/views/login.py:367 msgid "Logout success, return login page" msgstr "退出登录成功,返回到登录页面" @@ -3669,7 +3712,7 @@ msgstr "保存后执行" msgid "Job type" msgstr "任务类型" -#: ops/serializers/job.py:57 terminal/serializers/session.py:50 +#: ops/serializers/job.py:57 terminal/serializers/session.py:47 msgid "Is finished" msgstr "是否完成" @@ -4113,23 +4156,23 @@ msgstr "测试成功" msgid "Test mail sent to {}, please check" msgstr "邮件已经发送{}, 请检查" -#: settings/api/ldap.py:173 +#: settings/api/ldap.py:176 msgid "Synchronization start, please wait." msgstr "同步开始,请稍等" -#: settings/api/ldap.py:177 +#: settings/api/ldap.py:180 msgid "Synchronization is running, please wait." msgstr "同步正在运行,请稍等" -#: settings/api/ldap.py:182 +#: settings/api/ldap.py:185 msgid "Synchronization error: {}" msgstr "同步错误: {}" -#: settings/api/ldap.py:220 +#: settings/api/ldap.py:223 msgid "Get ldap users is None" msgstr "获取 LDAP 用户为 None" -#: settings/api/ldap.py:230 +#: settings/api/ldap.py:233 msgid "Imported {} users successfully (Organization: {})" msgstr "成功导入 {} 个用户 ( 组织: {} )" @@ -5022,10 +5065,6 @@ msgstr "启用登录验证码" msgid "Enable captcha to prevent robot authentication" msgstr "开启验证码,防止机器人登录" -#: settings/serializers/security.py:151 -msgid "Security" -msgstr "安全" - #: settings/serializers/security.py:154 msgid "Enable terminal register" msgstr "终端注册" @@ -6026,35 +6065,35 @@ msgstr "如果不同端点下的资产 IP 有冲突,使用资产标签实现" msgid "Asset IP" msgstr "资产 IP" -#: terminal/serializers/session.py:25 terminal/serializers/session.py:47 +#: terminal/serializers/session.py:22 terminal/serializers/session.py:44 msgid "Can replay" msgstr "是否可重放" -#: terminal/serializers/session.py:26 terminal/serializers/session.py:48 +#: terminal/serializers/session.py:23 terminal/serializers/session.py:45 msgid "Can join" msgstr "是否可加入" -#: terminal/serializers/session.py:27 terminal/serializers/session.py:51 +#: terminal/serializers/session.py:24 terminal/serializers/session.py:48 msgid "Can terminate" msgstr "是否可中断" -#: terminal/serializers/session.py:43 +#: terminal/serializers/session.py:40 msgid "User ID" msgstr "用户 ID" -#: terminal/serializers/session.py:44 +#: terminal/serializers/session.py:41 msgid "Asset ID" msgstr "资产 ID" -#: terminal/serializers/session.py:45 +#: terminal/serializers/session.py:42 msgid "Login from display" msgstr "登录来源名称" -#: terminal/serializers/session.py:52 +#: terminal/serializers/session.py:49 msgid "Terminal display" msgstr "终端显示" -#: terminal/serializers/session.py:57 +#: terminal/serializers/session.py:54 msgid "Command amount" msgstr "命令数量" @@ -7626,3 +7665,6 @@ msgstr "旗舰版" #: xpack/plugins/license/models.py:86 msgid "Community edition" msgstr "社区版" + +#~ msgid "Please enable cookies and try again." +#~ msgstr "设置你的浏览器支持cookie" diff --git a/apps/notifications/notifications.py b/apps/notifications/notifications.py index 6c631ec16..19a86ac94 100644 --- a/apps/notifications/notifications.py +++ b/apps/notifications/notifications.py @@ -194,7 +194,7 @@ class Message(metaclass=MessageType): return self.markdown_msg def get_feishu_msg(self) -> dict: - return self.text_msg + return self.markdown_msg def get_email_msg(self) -> dict: return self.html_msg_with_sign diff --git a/apps/ops/ansible/callback.py b/apps/ops/ansible/callback.py index 2045b6f29..1ba87f575 100644 --- a/apps/ops/ansible/callback.py +++ b/apps/ops/ansible/callback.py @@ -109,21 +109,21 @@ class DefaultCallback: pass def playbook_on_stats(self, event_data, **kwargs): - failed = [] error_func = lambda err, task_detail: err + f"{task_detail[0]}: {task_detail[1]['stderr']};" for tp in ['dark', 'failures']: for host, tasks in self.result[tp].items(): - failed.append(host) error = reduce(error_func, tasks.items(), '').strip(';') self.summary[tp][host] = error + failures = list(self.result['failures'].keys()) + dark_or_failures = list(self.result['dark'].keys()) + failures for host, tasks in self.result.get('ignored', {}).items(): ignore_errors = reduce(error_func, tasks.items(), '').strip(';') - if host in failed: + if host in failures: self.summary['failures'][host] += {ignore_errors} - self.summary['ok'] = list(set(self.result['ok'].keys()) - set(failed)) - self.summary['skipped'] = list(set(self.result['skipped'].keys()) - set(failed)) + self.summary['ok'] = list(set(self.result['ok'].keys()) - set(dark_or_failures)) + self.summary['skipped'] = list(set(self.result['skipped'].keys()) - set(dark_or_failures)) def playbook_on_include(self, event_data, **kwargs): pass diff --git a/apps/settings/api/ldap.py b/apps/settings/api/ldap.py index 256d21d31..8c98f821f 100644 --- a/apps/settings/api/ldap.py +++ b/apps/settings/api/ldap.py @@ -10,7 +10,7 @@ from rest_framework.generics import CreateAPIView from rest_framework.views import Response, APIView from common.api import AsyncApiMixin -from common.utils import get_logger, is_uuid +from common.utils import get_logger from orgs.models import Organization from orgs.utils import current_org from users.models import User @@ -166,6 +166,9 @@ class LDAPUserListApi(generics.ListAPIView): sync_util = LDAPSyncUtil() # 还没有同步任务 if sync_util.task_no_start: + ok, msg = LDAPTestUtil().test_config() + if not ok: + return Response(data={'msg': msg}, status=400) # 任务外部设置 task running 状态 sync_util.set_task_status(sync_util.TASK_STATUS_IS_RUNNING) t = threading.Thread(target=sync_ldap_user) diff --git a/apps/terminal/connect_methods.py b/apps/terminal/connect_methods.py index b5ba6360d..a4901b93c 100644 --- a/apps/terminal/connect_methods.py +++ b/apps/terminal/connect_methods.py @@ -39,7 +39,7 @@ class WebMethod(TextChoices): if not settings.XPACK_ENABLED: return methods - web_gui_dbs = [Protocol.mysql, Protocol.mariadb, Protocol.oracle, Protocol.postgresql] + web_gui_dbs = [Protocol.mysql, Protocol.mariadb, Protocol.oracle, Protocol.postgresql, Protocol.sqlserver] for db in web_gui_dbs: methods[db].append(cls.web_gui) return methods @@ -188,7 +188,7 @@ class ConnectMethodUtil: 'listen': [Protocol.http], 'support': [ Protocol.mysql, Protocol.postgresql, - Protocol.oracle + Protocol.oracle, Protocol.sqlserver, ], 'match': 'm2m' }, diff --git a/apps/terminal/serializers/session.py b/apps/terminal/serializers/session.py index 49a5af69a..dc736a522 100644 --- a/apps/terminal/serializers/session.py +++ b/apps/terminal/serializers/session.py @@ -1,7 +1,6 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers -from assets.const import Protocol from common.serializers.fields import LabeledChoiceField from orgs.mixins.serializers import BulkOrgResourceModelSerializer from .terminal import TerminalSmallSerializer @@ -14,11 +13,9 @@ __all__ = [ ] - - class SessionSerializer(BulkOrgResourceModelSerializer): org_id = serializers.CharField(allow_blank=True) - protocol = serializers.ChoiceField(choices=Protocol.choices, label=_("Protocol")) + protocol = serializers.CharField(max_length=128, label=_("Protocol")) type = LabeledChoiceField( choices=SessionType.choices, label=_("Type"), default=SessionType.normal )