Merge pull request #11452 from jumpserver/pr@dev@feat_audit_view_download_replay

feat: 查看/下载录像记录在操作及活动日志中
This commit is contained in:
老广 2023-08-30 13:48:53 +08:00 committed by GitHub
commit 894249a3d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 267 additions and 199 deletions

View File

@ -7,10 +7,10 @@ from rest_framework.status import HTTP_200_OK
from accounts import serializers from accounts import serializers
from accounts.filters import AccountFilterSet from accounts.filters import AccountFilterSet
from accounts.models import Account from accounts.models import Account
from accounts.mixins import AccountRecordViewLogMixin
from assets.models import Asset, Node from assets.models import Asset, Node
from common.api.mixin import ExtraFilterFieldsMixin from common.api.mixin import ExtraFilterFieldsMixin
from common.permissions import UserConfirmation, ConfirmType, IsValidUser from common.permissions import UserConfirmation, ConfirmType, IsValidUser
from common.views.mixins import RecordViewLogMixin
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from rbac.permissions import RBACPermission from rbac.permissions import RBACPermission
@ -86,7 +86,7 @@ class AccountViewSet(OrgBulkModelViewSet):
return Response(status=HTTP_200_OK) return Response(status=HTTP_200_OK)
class AccountSecretsViewSet(RecordViewLogMixin, AccountViewSet): class AccountSecretsViewSet(AccountRecordViewLogMixin, AccountViewSet):
""" """
因为可能要导出所有账号所以单独建立了一个 viewset 因为可能要导出所有账号所以单独建立了一个 viewset
""" """
@ -115,7 +115,7 @@ class AssetAccountBulkCreateApi(CreateAPIView):
return Response(data=serializer.data, status=HTTP_200_OK) return Response(data=serializer.data, status=HTTP_200_OK)
class AccountHistoriesSecretAPI(ExtraFilterFieldsMixin, RecordViewLogMixin, ListAPIView): class AccountHistoriesSecretAPI(ExtraFilterFieldsMixin, AccountRecordViewLogMixin, ListAPIView):
model = Account.history.model model = Account.history.model
serializer_class = serializers.AccountHistorySerializer serializer_class = serializers.AccountHistorySerializer
http_method_names = ['get', 'options'] http_method_names = ['get', 'options']

View File

@ -4,10 +4,10 @@ from rest_framework.response import Response
from accounts import serializers from accounts import serializers
from accounts.models import AccountTemplate from accounts.models import AccountTemplate
from accounts.mixins import AccountRecordViewLogMixin
from assets.const import Protocol from assets.const import Protocol
from common.drf.filters import BaseFilterSet from common.drf.filters import BaseFilterSet
from common.permissions import UserConfirmation, ConfirmType from common.permissions import UserConfirmation, ConfirmType
from common.views.mixins import RecordViewLogMixin
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from rbac.permissions import RBACPermission from rbac.permissions import RBACPermission
@ -55,7 +55,7 @@ class AccountTemplateViewSet(OrgBulkModelViewSet):
return Response(data=serializer.data) return Response(data=serializer.data)
class AccountTemplateSecretsViewSet(RecordViewLogMixin, AccountTemplateViewSet): class AccountTemplateSecretsViewSet(AccountRecordViewLogMixin, AccountTemplateViewSet):
serializer_classes = { serializer_classes = {
'default': serializers.AccountTemplateSecretSerializer, 'default': serializers.AccountTemplateSecretSerializer,
} }

75
apps/accounts/mixins.py Normal file
View File

@ -0,0 +1,75 @@
from rest_framework.response import Response
from rest_framework import status
from django.utils import translation
from django.utils.translation import gettext_noop
from audits.const import ActionChoices
from common.views.mixins import RecordViewLogMixin
from common.utils import i18n_fmt
class AccountRecordViewLogMixin(RecordViewLogMixin):
get_object: callable
get_queryset: callable
@staticmethod
def _filter_params(params):
new_params = {}
need_pop_params = ('format', 'order')
for key, value in params.items():
if key in need_pop_params:
continue
if isinstance(value, list):
value = list(filter(None, value))
if value:
new_params[key] = value
return new_params
def get_resource_display(self, request):
query_params = dict(request.query_params)
params = self._filter_params(query_params)
spm_filter = params.pop("spm", None)
if not params and not spm_filter:
display_message = gettext_noop("Export all")
elif spm_filter:
display_message = gettext_noop("Export only selected items")
else:
query = ",".join(
["%s=%s" % (key, value) for key, value in params.items()]
)
display_message = i18n_fmt(gettext_noop("Export filtered: %s"), query)
return display_message
@property
def detail_msg(self):
return i18n_fmt(
gettext_noop('User %s view/export secret'), self.request.user
)
def list(self, request, *args, **kwargs):
list_func = getattr(super(), 'list')
if not callable(list_func):
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
response = list_func(request, *args, **kwargs)
with translation.override('en'):
resource_display = self.get_resource_display(request)
ids = [q.id for q in self.get_queryset()]
self.record_logs(
ids, ActionChoices.view, self.detail_msg, resource_display=resource_display
)
return response
def retrieve(self, request, *args, **kwargs):
retrieve_func = getattr(super(), 'retrieve')
if not callable(retrieve_func):
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
response = retrieve_func(request, *args, **kwargs)
with translation.override('en'):
resource = self.get_object()
self.record_logs(
[resource.id], ActionChoices.view, self.detail_msg, resource=resource
)
return response

View File

@ -25,6 +25,7 @@ class ActionChoices(TextChoices):
delete = "delete", _("Delete") delete = "delete", _("Delete")
create = "create", _("Create") create = "create", _("Create")
# Activities action # Activities action
download = "download", _("Download")
connect = "connect", _("Connect") connect = "connect", _("Connect")
login = "login", _("Login") login = "login", _("Login")
change_auth = "change_password", _("Change password") change_auth = "change_password", _("Change password")

View File

@ -88,6 +88,7 @@ class AsyncApiMixin(InterceptMixin):
if not self.is_need_async(): if not self.is_need_async():
return handler(*args, **kwargs) return handler(*args, **kwargs)
resp = self.do_async(handler, *args, **kwargs) resp = self.do_async(handler, *args, **kwargs)
self.async_callback(*args, **kwargs)
return resp return resp
def is_need_refresh(self): def is_need_refresh(self):
@ -98,6 +99,9 @@ class AsyncApiMixin(InterceptMixin):
def is_need_async(self): def is_need_async(self):
return False return False
def async_callback(self, *args, **kwargs):
pass
def do_async(self, handler, *args, **kwargs): def do_async(self, handler, *args, **kwargs):
data = self.get_cache_data() data = self.get_cache_data()
if not data: if not data:

View File

@ -2,16 +2,15 @@
# #
from django.contrib.auth.mixins import UserPassesTestMixin from django.contrib.auth.mixins import UserPassesTestMixin
from django.http.response import JsonResponse from django.http.response import JsonResponse
from django.db.models import Model
from django.utils import translation from django.utils import translation
from django.utils.translation import gettext_noop
from rest_framework import permissions from rest_framework import permissions
from rest_framework.request import Request from rest_framework.request import Request
from audits.const import ActionChoices, ActivityChoices from audits.const import ActivityChoices
from audits.handler import create_or_update_operate_log from audits.handler import create_or_update_operate_log
from audits.models import ActivityLog from audits.models import ActivityLog
from common.exceptions import UserConfirmRequired from common.exceptions import UserConfirmRequired
from common.utils import i18n_fmt
from orgs.utils import current_org from orgs.utils import current_org
__all__ = [ __all__ = [
@ -49,66 +48,20 @@ class PermissionsMixin(UserPassesTestMixin):
class RecordViewLogMixin: class RecordViewLogMixin:
ACTION = ActionChoices.view model: Model
@staticmethod def record_logs(self, ids, action, detail, model=None, **kwargs):
def _filter_params(params): with translation.override('en'):
new_params = {} model = model or self.model
need_pop_params = ('format', 'order') resource_type = model._meta.verbose_name
for key, value in params.items():
if key in need_pop_params:
continue
if isinstance(value, list):
value = list(filter(None, value))
if value:
new_params[key] = value
return new_params
def get_resource_display(self, request):
query_params = dict(request.query_params)
params = self._filter_params(query_params)
spm_filter = params.pop("spm", None)
if not params and not spm_filter:
display_message = gettext_noop("Export all")
elif spm_filter:
display_message = gettext_noop("Export only selected items")
else:
query = ",".join(
["%s=%s" % (key, value) for key, value in params.items()]
)
display_message = i18n_fmt(gettext_noop("Export filtered: %s"), query)
return display_message
def record_logs(self, ids, **kwargs):
resource_type = self.model._meta.verbose_name
create_or_update_operate_log( create_or_update_operate_log(
self.ACTION, resource_type, force=True, **kwargs action, resource_type, force=True, **kwargs
)
detail = i18n_fmt(
gettext_noop('User %s view/export secret'), self.request.user
) )
activities = [ activities = [
ActivityLog( ActivityLog(
resource_id=getattr(resource_id, 'pk', resource_id), resource_id=resource_id, type=ActivityChoices.operate_log,
type=ActivityChoices.operate_log, detail=detail, org_id=current_org.id, detail=detail, org_id=current_org.id,
) )
for resource_id in ids for resource_id in ids
] ]
ActivityLog.objects.bulk_create(activities) ActivityLog.objects.bulk_create(activities)
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
with translation.override('en'):
resource_display = self.get_resource_display(request)
ids = [q.id for q in self.get_queryset()]
self.record_logs(ids, resource_display=resource_display)
return response
def retrieve(self, request, *args, **kwargs):
response = super().retrieve(request, *args, **kwargs)
with translation.override('en'):
resource = self.get_object()
self.record_logs([resource.id], resource=resource)
return response

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-08-28 10:55+0800\n" "POT-Creation-Date: 2023-08-29 15:14+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -93,7 +93,7 @@ msgid "Update"
msgstr "更新" msgstr "更新"
#: accounts/const/account.py:33 #: accounts/const/account.py:33
#: accounts/serializers/automations/change_secret.py:156 audits/const.py:54 #: accounts/serializers/automations/change_secret.py:156 audits/const.py:55
#: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19
#: ops/const.py:61 terminal/const.py:77 xpack/plugins/cloud/const.py:43 #: ops/const.py:61 terminal/const.py:77 xpack/plugins/cloud/const.py:43
msgid "Failed" msgid "Failed"
@ -227,7 +227,7 @@ msgstr "から切り替え"
#: accounts/models/account.py:54 assets/const/protocol.py:162 #: accounts/models/account.py:54 assets/const/protocol.py:162
#: settings/serializers/auth/cas.py:20 settings/serializers/auth/feishu.py:20 #: settings/serializers/auth/cas.py:20 settings/serializers/auth/feishu.py:20
#: terminal/models/applet/applet.py:34 #: terminal/models/applet/applet.py:35
msgid "Version" msgid "Version"
msgstr "バージョン" msgstr "バージョン"
@ -331,56 +331,56 @@ msgstr "成功は"
msgid "Account backup execution" msgid "Account backup execution"
msgstr "アカウントバックアップの実行" msgstr "アカウントバックアップの実行"
#: accounts/models/automations/base.py:20 #: accounts/models/automations/base.py:19
msgid "Account automation task" msgid "Account automation task"
msgstr "アカウント自動化タスク" msgstr "アカウント自動化タスク"
#: accounts/models/automations/base.py:34 #: accounts/models/automations/base.py:33
msgid "Automation execution" msgid "Automation execution"
msgstr "自動実行" msgstr "自動実行"
#: accounts/models/automations/base.py:35 #: accounts/models/automations/base.py:34
msgid "Automation executions" msgid "Automation executions"
msgstr "自動実行" msgstr "自動実行"
#: accounts/models/automations/base.py:37 #: accounts/models/automations/base.py:36
msgid "Can view change secret execution" msgid "Can view change secret execution"
msgstr "改密実行の表示" msgstr "改密実行の表示"
#: accounts/models/automations/base.py:38 #: accounts/models/automations/base.py:37
msgid "Can add change secret execution" msgid "Can add change secret execution"
msgstr "改密実行の作成" msgstr "改密実行の作成"
#: accounts/models/automations/base.py:40 #: accounts/models/automations/base.py:39
msgid "Can view gather accounts execution" msgid "Can view gather accounts execution"
msgstr "コレクションアカウントの実行を表示" msgstr "コレクションアカウントの実行を表示"
#: accounts/models/automations/base.py:41 #: accounts/models/automations/base.py:40
msgid "Can add gather accounts execution" msgid "Can add gather accounts execution"
msgstr "回収口座作成の実行" msgstr "回収口座作成の実行"
#: accounts/models/automations/base.py:43 #: accounts/models/automations/base.py:42
msgid "Can view push account execution" msgid "Can view push account execution"
msgstr "プッシュ アカウントの実行を表示する" msgstr "プッシュ アカウントの実行を表示する"
#: accounts/models/automations/base.py:44 #: accounts/models/automations/base.py:43
msgid "Can add push account execution" msgid "Can add push account execution"
msgstr "プッシュ アカウントの作成の実行" msgstr "プッシュ アカウントの作成の実行"
#: accounts/models/automations/base.py:56 accounts/models/template.py:21 #: accounts/models/automations/base.py:55 accounts/models/template.py:21
#: accounts/serializers/automations/change_secret.py:40 #: accounts/serializers/automations/change_secret.py:40
msgid "Secret strategy" msgid "Secret strategy"
msgstr "鍵ポリシー" msgstr "鍵ポリシー"
#: accounts/models/automations/base.py:58 #: accounts/models/automations/base.py:57
msgid "Password rules" msgid "Password rules"
msgstr "パスワードルール" msgstr "パスワードルール"
#: accounts/models/automations/base.py:61 #: accounts/models/automations/base.py:60
msgid "SSH key change strategy" msgid "SSH key change strategy"
msgstr "SSHキープッシュ方式" msgstr "SSHキープッシュ方式"
#: accounts/models/automations/base.py:71 accounts/models/base.py:36 #: accounts/models/automations/base.py:70 accounts/models/base.py:36
#: accounts/serializers/account/account.py:429 #: accounts/serializers/account/account.py:429
#: accounts/serializers/account/base.py:16 #: accounts/serializers/account/base.py:16
#: accounts/serializers/automations/change_secret.py:46 #: accounts/serializers/automations/change_secret.py:46
@ -389,7 +389,7 @@ msgstr "SSHキープッシュ方式"
msgid "Secret type" msgid "Secret type"
msgstr "鍵の種類" msgstr "鍵の種類"
#: accounts/models/automations/base.py:73 accounts/models/mixins/vault.py:48 #: accounts/models/automations/base.py:72 accounts/models/mixins/vault.py:48
#: accounts/serializers/account/base.py:19 #: accounts/serializers/account/base.py:19
#: authentication/models/temp_token.py:10 #: authentication/models/temp_token.py:10
#: authentication/templates/authentication/_access_key_modal.html:31 #: authentication/templates/authentication/_access_key_modal.html:31
@ -510,7 +510,7 @@ msgstr "アカウントの確認"
#: ops/models/job.py:126 ops/models/playbook.py:28 ops/serializers/job.py:20 #: ops/models/job.py:126 ops/models/playbook.py:28 ops/serializers/job.py:20
#: orgs/models.py:82 perms/models/asset_permission.py:56 rbac/models/role.py:29 #: orgs/models.py:82 perms/models/asset_permission.py:56 rbac/models/role.py:29
#: settings/models.py:32 settings/serializers/msg.py:82 #: settings/models.py:32 settings/serializers/msg.py:82
#: terminal/models/applet/applet.py:32 terminal/models/component/endpoint.py:12 #: terminal/models/applet/applet.py:33 terminal/models/component/endpoint.py:12
#: terminal/models/component/endpoint.py:94 #: terminal/models/component/endpoint.py:94
#: terminal/models/component/storage.py:26 terminal/models/component/task.py:13 #: terminal/models/component/storage.py:26 terminal/models/component/task.py:13
#: terminal/models/component/terminal.py:84 users/forms/profile.py:33 #: terminal/models/component/terminal.py:84 users/forms/profile.py:33
@ -528,7 +528,7 @@ msgstr "特権アカウント"
#: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39
#: assets/models/label.py:22 #: assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:114 #: authentication/serializers/connect_token_secret.py:114
#: terminal/models/applet/applet.py:39 #: terminal/models/applet/applet.py:40
#: terminal/models/component/endpoint.py:105 users/serializers/user.py:170 #: terminal/models/component/endpoint.py:105 users/serializers/user.py:170
msgid "Is active" msgid "Is active"
msgstr "アクティブです。" msgstr "アクティブです。"
@ -652,7 +652,7 @@ msgstr "カテゴリ"
#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:112 #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:112
#: assets/serializers/platform.py:127 audits/serializers.py:49 #: assets/serializers/platform.py:127 audits/serializers.py:49
#: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:137 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:137
#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:38 #: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:39
#: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:57
#: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29
#: terminal/serializers/session.py:21 terminal/serializers/storage.py:226 #: terminal/serializers/session.py:21 terminal/serializers/storage.py:226
@ -792,8 +792,8 @@ msgstr "关联平台,可以配置推送参数,如果不关联,则使用默
#: assets/models/cmd_filter.py:40 assets/models/cmd_filter.py:88 #: assets/models/cmd_filter.py:40 assets/models/cmd_filter.py:88
#: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26 #: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26
#: ops/models/job.py:145 ops/models/playbook.py:31 rbac/models/role.py:37 #: ops/models/job.py:145 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:37 terminal/models/applet/applet.py:44 #: settings/models.py:37 terminal/models/applet/applet.py:45
#: terminal/models/applet/applet.py:284 terminal/models/applet/host.py:142 #: terminal/models/applet/applet.py:302 terminal/models/applet/host.py:142
#: terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:24
#: terminal/models/component/endpoint.py:104 #: terminal/models/component/endpoint.py:104
#: terminal/models/session/session.py:46 tickets/models/comment.py:32 #: terminal/models/session/session.py:46 tickets/models/comment.py:32
@ -844,7 +844,7 @@ msgstr "* パスワードの長さの範囲6-30ビット"
msgid "Automation task execution" msgid "Automation task execution"
msgstr "自動タスク実行履歴" msgstr "自動タスク実行履歴"
#: accounts/serializers/automations/change_secret.py:155 audits/const.py:53 #: accounts/serializers/automations/change_secret.py:155 audits/const.py:54
#: audits/models.py:59 audits/signal_handlers/activity_log.py:33 #: audits/models.py:59 audits/signal_handlers/activity_log.py:33
#: common/const/choices.py:18 ops/const.py:59 ops/serializers/celery.py:40 #: common/const/choices.py:18 ops/const.py:59 ops/serializers/celery.py:40
#: terminal/const.py:76 terminal/models/session/sharing.py:121 #: terminal/const.py:76 terminal/models/session/sharing.py:121
@ -852,7 +852,8 @@ msgstr "自動タスク実行履歴"
msgid "Success" msgid "Success"
msgstr "成功" msgstr "成功"
#: accounts/signal_handlers.py:47 #: accounts/signal_handlers.py:46
#, python-format
msgid "Push related accounts to assets: %s, by system" msgid "Push related accounts to assets: %s, by system"
msgstr "関連するアカウントをアセットにプッシュ: %s, by system" msgstr "関連するアカウントをアセットにプッシュ: %s, by system"
@ -1166,7 +1167,7 @@ msgstr "認証に失敗しました"
msgid "Connect failed" msgid "Connect failed"
msgstr "接続に失敗しました" msgstr "接続に失敗しました"
#: assets/const/automation.py:6 audits/const.py:6 audits/const.py:36 #: assets/const/automation.py:6 audits/const.py:6 audits/const.py:37
#: audits/signal_handlers/activity_log.py:62 common/utils/ip/geoip/utils.py:31 #: audits/signal_handlers/activity_log.py:62 common/utils/ip/geoip/utils.py:31
#: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:104 #: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:104
msgid "Unknown" msgid "Unknown"
@ -1188,7 +1189,7 @@ msgstr "テストゲートウェイ"
msgid "Gather facts" msgid "Gather facts"
msgstr "資産情報の収集" msgstr "資産情報の収集"
#: assets/const/base.py:33 audits/const.py:47 #: assets/const/base.py:33 audits/const.py:48
#: terminal/serializers/applet_host.py:32 #: terminal/serializers/applet_host.py:32
msgid "Disabled" msgid "Disabled"
msgstr "無効" msgstr "無効"
@ -1219,8 +1220,8 @@ msgid "Cloud service"
msgstr "クラウド サービス" msgstr "クラウド サービス"
#: assets/const/category.py:14 assets/models/asset/gpt.py:11 #: assets/const/category.py:14 assets/models/asset/gpt.py:11
#: assets/models/asset/web.py:16 audits/const.py:34 #: assets/models/asset/web.py:16 audits/const.py:35
#: terminal/models/applet/applet.py:26 #: terminal/models/applet/applet.py:27
msgid "Web" msgid "Web"
msgstr "Web" msgstr "Web"
@ -1240,7 +1241,7 @@ msgstr "私有雲"
msgid "Kubernetes" msgid "Kubernetes"
msgstr "Kubernetes" msgstr "Kubernetes"
#: assets/const/device.py:7 terminal/models/applet/applet.py:25 #: assets/const/device.py:7 terminal/models/applet/applet.py:26
#: tickets/const.py:8 #: tickets/const.py:8
msgid "General" msgid "General"
msgstr "一般" msgstr "一般"
@ -1433,7 +1434,7 @@ msgstr "ユーザーと同じユーザー名"
#: assets/models/_user.py:52 authentication/models/connection_token.py:41 #: assets/models/_user.py:52 authentication/models/connection_token.py:41
#: authentication/serializers/connect_token_secret.py:111 #: authentication/serializers/connect_token_secret.py:111
#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:19 #: terminal/models/applet/applet.py:42 terminal/serializers/session.py:19
#: terminal/serializers/session.py:42 terminal/serializers/storage.py:70 #: terminal/serializers/session.py:42 terminal/serializers/storage.py:70
msgid "Protocol" msgid "Protocol"
msgstr "プロトコル" msgstr "プロトコル"
@ -1572,7 +1573,7 @@ msgstr "アセットの自動化タスク"
#: assets/models/automations/base.py:113 audits/models.py:199 #: assets/models/automations/base.py:113 audits/models.py:199
#: audits/serializers.py:50 ops/models/base.py:49 ops/models/job.py:220 #: audits/serializers.py:50 ops/models/base.py:49 ops/models/job.py:220
#: terminal/models/applet/applet.py:283 terminal/models/applet/host.py:139 #: terminal/models/applet/applet.py:301 terminal/models/applet/host.py:139
#: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18
#: terminal/serializers/applet_host.py:115 tickets/models/ticket/general.py:283 #: terminal/serializers/applet_host.py:115 tickets/models/ticket/general.py:283
#: tickets/serializers/super_ticket.py:13 #: tickets/serializers/super_ticket.py:13
@ -1717,7 +1718,7 @@ msgstr "開ける"
msgid "Setting" msgid "Setting"
msgstr "設定" msgstr "設定"
#: assets/models/platform.py:38 audits/const.py:48 settings/models.py:36 #: assets/models/platform.py:38 audits/const.py:49 settings/models.py:36
#: terminal/serializers/applet_host.py:33 #: terminal/serializers/applet_host.py:33
msgid "Enabled" msgid "Enabled"
msgstr "有効化" msgstr "有効化"
@ -2129,7 +2130,8 @@ msgstr "名前の変更"
msgid "Symlink" msgid "Symlink"
msgstr "Symlink" msgstr "Symlink"
#: audits/const.py:18 perms/const.py:14 #: audits/const.py:18 audits/const.py:28 perms/const.py:14
#: terminal/api/session/session.py:141
msgid "Download" msgid "Download"
msgstr "ダウンロード" msgstr "ダウンロード"
@ -2137,7 +2139,7 @@ msgstr "ダウンロード"
msgid "Rename dir" msgid "Rename dir"
msgstr "マップディレクトリ" msgstr "マップディレクトリ"
#: audits/const.py:23 rbac/tree.py:232 #: audits/const.py:23 rbac/tree.py:232 terminal/api/session/session.py:234
#: terminal/templates/terminal/_msg_command_warning.html:18 #: terminal/templates/terminal/_msg_command_warning.html:18
#: terminal/templates/terminal/_msg_session_sharing.html:10 #: terminal/templates/terminal/_msg_session_sharing.html:10
msgid "View" msgid "View"
@ -2149,44 +2151,44 @@ msgstr "表示"
msgid "Create" msgid "Create"
msgstr "作成" msgstr "作成"
#: audits/const.py:28 perms/const.py:12 #: audits/const.py:29 perms/const.py:12
msgid "Connect" msgid "Connect"
msgstr "接続" msgstr "接続"
#: audits/const.py:29 authentication/templates/authentication/login.html:252 #: audits/const.py:30 authentication/templates/authentication/login.html:252
#: authentication/templates/authentication/login.html:325 #: authentication/templates/authentication/login.html:325
#: templates/_header_bar.html:89 #: templates/_header_bar.html:89
msgid "Login" msgid "Login"
msgstr "ログイン" msgstr "ログイン"
#: audits/const.py:30 ops/const.py:9 #: audits/const.py:31 ops/const.py:9
msgid "Change password" msgid "Change password"
msgstr "パスワードを変更する" msgstr "パスワードを変更する"
#: audits/const.py:35 settings/serializers/terminal.py:6 #: audits/const.py:36 settings/serializers/terminal.py:6
#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:164 #: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:164
#: terminal/serializers/session.py:49 terminal/serializers/session.py:63 #: terminal/serializers/session.py:49 terminal/serializers/session.py:63
msgid "Terminal" msgid "Terminal"
msgstr "ターミナル" msgstr "ターミナル"
#: audits/const.py:40 audits/models.py:127 #: audits/const.py:41 audits/models.py:127
msgid "Operate log" msgid "Operate log"
msgstr "ログの操作" msgstr "ログの操作"
#: audits/const.py:41 #: audits/const.py:42
msgid "Session log" msgid "Session log"
msgstr "セッションログ" msgstr "セッションログ"
#: audits/const.py:42 #: audits/const.py:43
msgid "Login log" msgid "Login log"
msgstr "ログインログ" msgstr "ログインログ"
#: audits/const.py:43 terminal/models/applet/host.py:143 #: audits/const.py:44 terminal/models/applet/host.py:143
#: terminal/models/component/task.py:22 #: terminal/models/component/task.py:22
msgid "Task" msgid "Task"
msgstr "タスク" msgstr "タスク"
#: audits/const.py:49 #: audits/const.py:50
msgid "-" msgid "-"
msgstr "-" msgstr "-"
@ -2412,7 +2414,7 @@ msgstr "ACL アクションはレビューです"
msgid "Current user not support mfa type: {}" msgid "Current user not support mfa type: {}"
msgstr "現在のユーザーはmfaタイプをサポートしていません: {}" msgstr "現在のユーザーはmfaタイプをサポートしていません: {}"
#: authentication/api/password.py:32 terminal/api/session/session.py:259 #: authentication/api/password.py:32 terminal/api/session/session.py:282
#: users/views/profile/reset.py:44 #: users/views/profile/reset.py:44
msgid "User does not exist: {}" msgid "User does not exist: {}"
msgstr "ユーザーが存在しない: {}" msgstr "ユーザーが存在しない: {}"
@ -4099,7 +4101,7 @@ msgstr "デフォルト組織"
msgid "SYSTEM" msgid "SYSTEM"
msgstr "システム組織" msgstr "システム組織"
#: orgs/models.py:83 rbac/models/role.py:36 terminal/models/applet/applet.py:40 #: orgs/models.py:83 rbac/models/role.py:36 terminal/models/applet/applet.py:41
msgid "Builtin" msgid "Builtin"
msgstr "ビルトイン" msgstr "ビルトイン"
@ -4336,7 +4338,7 @@ msgstr "パーマ"
msgid "Users amount" msgid "Users amount"
msgstr "ユーザー数" msgstr "ユーザー数"
#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:33 #: rbac/serializers/role.py:28 terminal/models/applet/applet.py:34
msgid "Display name" msgid "Display name"
msgstr "表示名" msgstr "表示名"
@ -4396,8 +4398,8 @@ msgstr "タスクセンター"
msgid "My assets" msgid "My assets"
msgstr "私の資産" msgstr "私の資産"
#: rbac/tree.py:56 terminal/models/applet/applet.py:51 #: rbac/tree.py:56 terminal/models/applet/applet.py:52
#: terminal/models/applet/applet.py:280 terminal/models/applet/host.py:29 #: terminal/models/applet/applet.py:298 terminal/models/applet/host.py:29
#: terminal/serializers/applet.py:15 #: terminal/serializers/applet.py:15
msgid "Applet" msgid "Applet"
msgstr "リモートアプリケーション" msgstr "リモートアプリケーション"
@ -5902,15 +5904,20 @@ msgstr "テスト失敗: アカウントが無効"
msgid "Have online sessions" msgid "Have online sessions"
msgstr "オンラインセッションを持つ" msgstr "オンラインセッションを持つ"
#: terminal/api/session/session.py:251 #: terminal/api/session/session.py:46
#, python-format
msgid "User %s %s session %s replay"
msgstr "ユーザー%s %sこのセッション %s の録画です"
#: terminal/api/session/session.py:274
msgid "Session does not exist: {}" msgid "Session does not exist: {}"
msgstr "セッションが存在しません: {}" msgstr "セッションが存在しません: {}"
#: terminal/api/session/session.py:254 #: terminal/api/session/session.py:277
msgid "Session is finished or the protocol not supported" msgid "Session is finished or the protocol not supported"
msgstr "セッションが終了したか、プロトコルがサポートされていません" msgstr "セッションが終了したか、プロトコルがサポートされていません"
#: terminal/api/session/session.py:267 #: terminal/api/session/session.py:290
msgid "User does not have permission" msgid "User does not have permission"
msgstr "ユーザーに権限がありません" msgstr "ユーザーに権限がありません"
@ -6028,51 +6035,51 @@ msgstr "一括作成非サポート"
msgid "Storage is invalid" msgid "Storage is invalid"
msgstr "ストレージが無効です" msgstr "ストレージが無効です"
#: terminal/models/applet/applet.py:29 #: terminal/models/applet/applet.py:30
msgid "Community" msgid "Community"
msgstr "コミュニティ版" msgstr "コミュニティ版"
#: terminal/models/applet/applet.py:30 #: terminal/models/applet/applet.py:31
msgid "Enterprise" msgid "Enterprise"
msgstr "エンタープライズ版" msgstr "エンタープライズ版"
#: terminal/models/applet/applet.py:35 #: terminal/models/applet/applet.py:36
msgid "Author" msgid "Author"
msgstr "著者" msgstr "著者"
#: terminal/models/applet/applet.py:37 terminal/serializers/applet.py:31 #: terminal/models/applet/applet.py:38 terminal/serializers/applet.py:31
msgid "Edition" msgid "Edition"
msgstr "バージョン" msgstr "バージョン"
#: terminal/models/applet/applet.py:42 #: terminal/models/applet/applet.py:43
msgid "Can concurrent" msgid "Can concurrent"
msgstr "同時実行可能" msgstr "同時実行可能"
#: terminal/models/applet/applet.py:43 #: terminal/models/applet/applet.py:44
msgid "Tags" msgid "Tags"
msgstr "ラベル" msgstr "ラベル"
#: terminal/models/applet/applet.py:47 terminal/serializers/storage.py:159 #: terminal/models/applet/applet.py:48 terminal/serializers/storage.py:159
msgid "Hosts" msgid "Hosts"
msgstr "ホスト" msgstr "ホスト"
#: terminal/models/applet/applet.py:92 #: terminal/models/applet/applet.py:93
msgid "Applet pkg not valid, Missing file {}" msgid "Applet pkg not valid, Missing file {}"
msgstr "無効なアプレット パッケージ、ファイル {} がありません" msgstr "無効なアプレット パッケージ、ファイル {} がありません"
#: terminal/models/applet/applet.py:111 #: terminal/models/applet/applet.py:112
msgid "Load platform.yml failed: {}" msgid "Load platform.yml failed: {}"
msgstr "platform.ymlのロードに失敗しました:{}" msgstr "platform.ymlのロードに失敗しました:{}"
#: terminal/models/applet/applet.py:114 #: terminal/models/applet/applet.py:115
msgid "Only support custom platform" msgid "Only support custom platform"
msgstr "カスタムプラットフォームのみをサポート" msgstr "カスタムプラットフォームのみをサポート"
#: terminal/models/applet/applet.py:119 #: terminal/models/applet/applet.py:120
msgid "Missing type in platform.yml" msgid "Missing type in platform.yml"
msgstr "platform.ymlにタイプがありません" msgstr "platform.ymlにタイプがありません"
#: terminal/models/applet/applet.py:282 terminal/models/applet/host.py:35 #: terminal/models/applet/applet.py:300 terminal/models/applet/host.py:35
#: terminal/models/applet/host.py:137 #: terminal/models/applet/host.py:137
msgid "Hosting" msgid "Hosting"
msgstr "ホスト マシン" msgstr "ホスト マシン"

View File

@ -7,7 +7,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: 2023-08-28 10:55+0800\n" "POT-Creation-Date: 2023-08-29 14:45+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n" "Language-Team: JumpServer team<ibuler@qq.com>\n"
@ -92,7 +92,7 @@ msgid "Update"
msgstr "更新" msgstr "更新"
#: accounts/const/account.py:33 #: accounts/const/account.py:33
#: accounts/serializers/automations/change_secret.py:156 audits/const.py:54 #: accounts/serializers/automations/change_secret.py:156 audits/const.py:55
#: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19
#: ops/const.py:61 terminal/const.py:77 xpack/plugins/cloud/const.py:43 #: ops/const.py:61 terminal/const.py:77 xpack/plugins/cloud/const.py:43
msgid "Failed" msgid "Failed"
@ -226,7 +226,7 @@ msgstr "切换自"
#: accounts/models/account.py:54 assets/const/protocol.py:162 #: accounts/models/account.py:54 assets/const/protocol.py:162
#: settings/serializers/auth/cas.py:20 settings/serializers/auth/feishu.py:20 #: settings/serializers/auth/cas.py:20 settings/serializers/auth/feishu.py:20
#: terminal/models/applet/applet.py:34 #: terminal/models/applet/applet.py:35
msgid "Version" msgid "Version"
msgstr "版本" msgstr "版本"
@ -330,56 +330,56 @@ msgstr "是否成功"
msgid "Account backup execution" msgid "Account backup execution"
msgstr "账号备份执行" msgstr "账号备份执行"
#: accounts/models/automations/base.py:20 #: accounts/models/automations/base.py:19
msgid "Account automation task" msgid "Account automation task"
msgstr "账号自动化任务" msgstr "账号自动化任务"
#: accounts/models/automations/base.py:34 #: accounts/models/automations/base.py:33
msgid "Automation execution" msgid "Automation execution"
msgstr "自动化执行" msgstr "自动化执行"
#: accounts/models/automations/base.py:35 #: accounts/models/automations/base.py:34
msgid "Automation executions" msgid "Automation executions"
msgstr "自动化执行" msgstr "自动化执行"
#: accounts/models/automations/base.py:37 #: accounts/models/automations/base.py:36
msgid "Can view change secret execution" msgid "Can view change secret execution"
msgstr "查看改密执行" msgstr "查看改密执行"
#: accounts/models/automations/base.py:38 #: accounts/models/automations/base.py:37
msgid "Can add change secret execution" msgid "Can add change secret execution"
msgstr "创建改密执行" msgstr "创建改密执行"
#: accounts/models/automations/base.py:40 #: accounts/models/automations/base.py:39
msgid "Can view gather accounts execution" msgid "Can view gather accounts execution"
msgstr "查看收集账号执行" msgstr "查看收集账号执行"
#: accounts/models/automations/base.py:41 #: accounts/models/automations/base.py:40
msgid "Can add gather accounts execution" msgid "Can add gather accounts execution"
msgstr "创建收集账号执行" msgstr "创建收集账号执行"
#: accounts/models/automations/base.py:43 #: accounts/models/automations/base.py:42
msgid "Can view push account execution" msgid "Can view push account execution"
msgstr "查看推送账号执行" msgstr "查看推送账号执行"
#: accounts/models/automations/base.py:44 #: accounts/models/automations/base.py:43
msgid "Can add push account execution" msgid "Can add push account execution"
msgstr "创建推送账号执行" msgstr "创建推送账号执行"
#: accounts/models/automations/base.py:56 accounts/models/template.py:21 #: accounts/models/automations/base.py:55 accounts/models/template.py:21
#: accounts/serializers/automations/change_secret.py:40 #: accounts/serializers/automations/change_secret.py:40
msgid "Secret strategy" msgid "Secret strategy"
msgstr "密文策略" msgstr "密文策略"
#: accounts/models/automations/base.py:58 #: accounts/models/automations/base.py:57
msgid "Password rules" msgid "Password rules"
msgstr "密码规则" msgstr "密码规则"
#: accounts/models/automations/base.py:61 #: accounts/models/automations/base.py:60
msgid "SSH key change strategy" msgid "SSH key change strategy"
msgstr "SSH 密钥推送方式" msgstr "SSH 密钥推送方式"
#: accounts/models/automations/base.py:71 accounts/models/base.py:36 #: accounts/models/automations/base.py:70 accounts/models/base.py:36
#: accounts/serializers/account/account.py:429 #: accounts/serializers/account/account.py:429
#: accounts/serializers/account/base.py:16 #: accounts/serializers/account/base.py:16
#: accounts/serializers/automations/change_secret.py:46 #: accounts/serializers/automations/change_secret.py:46
@ -388,7 +388,7 @@ msgstr "SSH 密钥推送方式"
msgid "Secret type" msgid "Secret type"
msgstr "密文类型" msgstr "密文类型"
#: accounts/models/automations/base.py:73 accounts/models/mixins/vault.py:48 #: accounts/models/automations/base.py:72 accounts/models/mixins/vault.py:48
#: accounts/serializers/account/base.py:19 #: accounts/serializers/account/base.py:19
#: authentication/models/temp_token.py:10 #: authentication/models/temp_token.py:10
#: authentication/templates/authentication/_access_key_modal.html:31 #: authentication/templates/authentication/_access_key_modal.html:31
@ -509,7 +509,7 @@ msgstr "账号验证"
#: ops/models/job.py:126 ops/models/playbook.py:28 ops/serializers/job.py:20 #: ops/models/job.py:126 ops/models/playbook.py:28 ops/serializers/job.py:20
#: orgs/models.py:82 perms/models/asset_permission.py:56 rbac/models/role.py:29 #: orgs/models.py:82 perms/models/asset_permission.py:56 rbac/models/role.py:29
#: settings/models.py:32 settings/serializers/msg.py:82 #: settings/models.py:32 settings/serializers/msg.py:82
#: terminal/models/applet/applet.py:32 terminal/models/component/endpoint.py:12 #: terminal/models/applet/applet.py:33 terminal/models/component/endpoint.py:12
#: terminal/models/component/endpoint.py:94 #: terminal/models/component/endpoint.py:94
#: terminal/models/component/storage.py:26 terminal/models/component/task.py:13 #: terminal/models/component/storage.py:26 terminal/models/component/task.py:13
#: terminal/models/component/terminal.py:84 users/forms/profile.py:33 #: terminal/models/component/terminal.py:84 users/forms/profile.py:33
@ -527,7 +527,7 @@ msgstr "特权账号"
#: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39
#: assets/models/label.py:22 #: assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:114 #: authentication/serializers/connect_token_secret.py:114
#: terminal/models/applet/applet.py:39 #: terminal/models/applet/applet.py:40
#: terminal/models/component/endpoint.py:105 users/serializers/user.py:170 #: terminal/models/component/endpoint.py:105 users/serializers/user.py:170
msgid "Is active" msgid "Is active"
msgstr "激活" msgstr "激活"
@ -650,7 +650,7 @@ msgstr "类别"
#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:112 #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:112
#: assets/serializers/platform.py:127 audits/serializers.py:49 #: assets/serializers/platform.py:127 audits/serializers.py:49
#: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:137 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:137
#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:38 #: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:39
#: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:57
#: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29
#: terminal/serializers/session.py:21 terminal/serializers/storage.py:226 #: terminal/serializers/session.py:21 terminal/serializers/storage.py:226
@ -790,8 +790,8 @@ msgstr "关联平台,可配置推送参数,如果不关联,将使用默认
#: assets/models/cmd_filter.py:40 assets/models/cmd_filter.py:88 #: assets/models/cmd_filter.py:40 assets/models/cmd_filter.py:88
#: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26 #: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26
#: ops/models/job.py:145 ops/models/playbook.py:31 rbac/models/role.py:37 #: ops/models/job.py:145 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:37 terminal/models/applet/applet.py:44 #: settings/models.py:37 terminal/models/applet/applet.py:45
#: terminal/models/applet/applet.py:284 terminal/models/applet/host.py:142 #: terminal/models/applet/applet.py:302 terminal/models/applet/host.py:142
#: terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:24
#: terminal/models/component/endpoint.py:104 #: terminal/models/component/endpoint.py:104
#: terminal/models/session/session.py:46 tickets/models/comment.py:32 #: terminal/models/session/session.py:46 tickets/models/comment.py:32
@ -842,7 +842,7 @@ msgstr "* 密码长度范围 6-30 位"
msgid "Automation task execution" msgid "Automation task execution"
msgstr "自动化任务执行历史" msgstr "自动化任务执行历史"
#: accounts/serializers/automations/change_secret.py:155 audits/const.py:53 #: accounts/serializers/automations/change_secret.py:155 audits/const.py:54
#: audits/models.py:59 audits/signal_handlers/activity_log.py:33 #: audits/models.py:59 audits/signal_handlers/activity_log.py:33
#: common/const/choices.py:18 ops/const.py:59 ops/serializers/celery.py:40 #: common/const/choices.py:18 ops/const.py:59 ops/serializers/celery.py:40
#: terminal/const.py:76 terminal/models/session/sharing.py:121 #: terminal/const.py:76 terminal/models/session/sharing.py:121
@ -850,8 +850,8 @@ msgstr "自动化任务执行历史"
msgid "Success" msgid "Success"
msgstr "成功" msgstr "成功"
#: accounts/signal_handlers.py:47 #: accounts/signal_handlers.py:46
#, fpython-format #, python-format
msgid "Push related accounts to assets: %s, by system" msgid "Push related accounts to assets: %s, by system"
msgstr "推送账号到资产: %s, 由系统执行" msgstr "推送账号到资产: %s, 由系统执行"
@ -1162,7 +1162,7 @@ msgstr "认证失败"
msgid "Connect failed" msgid "Connect failed"
msgstr "连接失败" msgstr "连接失败"
#: assets/const/automation.py:6 audits/const.py:6 audits/const.py:36 #: assets/const/automation.py:6 audits/const.py:6 audits/const.py:37
#: audits/signal_handlers/activity_log.py:62 common/utils/ip/geoip/utils.py:31 #: audits/signal_handlers/activity_log.py:62 common/utils/ip/geoip/utils.py:31
#: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:104 #: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:104
msgid "Unknown" msgid "Unknown"
@ -1184,7 +1184,7 @@ msgstr "测试网关"
msgid "Gather facts" msgid "Gather facts"
msgstr "收集资产信息" msgstr "收集资产信息"
#: assets/const/base.py:33 audits/const.py:47 #: assets/const/base.py:33 audits/const.py:48
#: terminal/serializers/applet_host.py:32 #: terminal/serializers/applet_host.py:32
msgid "Disabled" msgid "Disabled"
msgstr "禁用" msgstr "禁用"
@ -1215,8 +1215,8 @@ msgid "Cloud service"
msgstr "云服务" msgstr "云服务"
#: assets/const/category.py:14 assets/models/asset/gpt.py:11 #: assets/const/category.py:14 assets/models/asset/gpt.py:11
#: assets/models/asset/web.py:16 audits/const.py:34 #: assets/models/asset/web.py:16 audits/const.py:35
#: terminal/models/applet/applet.py:26 #: terminal/models/applet/applet.py:27
msgid "Web" msgid "Web"
msgstr "Web" msgstr "Web"
@ -1236,7 +1236,7 @@ msgstr "私有云"
msgid "Kubernetes" msgid "Kubernetes"
msgstr "Kubernetes" msgstr "Kubernetes"
#: assets/const/device.py:7 terminal/models/applet/applet.py:25 #: assets/const/device.py:7 terminal/models/applet/applet.py:26
#: tickets/const.py:8 #: tickets/const.py:8
msgid "General" msgid "General"
msgstr "一般" msgstr "一般"
@ -1430,7 +1430,7 @@ msgstr "用户名与用户相同"
#: assets/models/_user.py:52 authentication/models/connection_token.py:41 #: assets/models/_user.py:52 authentication/models/connection_token.py:41
#: authentication/serializers/connect_token_secret.py:111 #: authentication/serializers/connect_token_secret.py:111
#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:19 #: terminal/models/applet/applet.py:42 terminal/serializers/session.py:19
#: terminal/serializers/session.py:42 terminal/serializers/storage.py:70 #: terminal/serializers/session.py:42 terminal/serializers/storage.py:70
msgid "Protocol" msgid "Protocol"
msgstr "协议" msgstr "协议"
@ -1569,7 +1569,7 @@ msgstr "资产自动化任务"
#: assets/models/automations/base.py:113 audits/models.py:199 #: assets/models/automations/base.py:113 audits/models.py:199
#: audits/serializers.py:50 ops/models/base.py:49 ops/models/job.py:220 #: audits/serializers.py:50 ops/models/base.py:49 ops/models/job.py:220
#: terminal/models/applet/applet.py:283 terminal/models/applet/host.py:139 #: terminal/models/applet/applet.py:301 terminal/models/applet/host.py:139
#: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18
#: terminal/serializers/applet_host.py:115 tickets/models/ticket/general.py:283 #: terminal/serializers/applet_host.py:115 tickets/models/ticket/general.py:283
#: tickets/serializers/super_ticket.py:13 #: tickets/serializers/super_ticket.py:13
@ -1714,7 +1714,7 @@ msgstr "开放的"
msgid "Setting" msgid "Setting"
msgstr "设置" msgstr "设置"
#: assets/models/platform.py:38 audits/const.py:48 settings/models.py:36 #: assets/models/platform.py:38 audits/const.py:49 settings/models.py:36
#: terminal/serializers/applet_host.py:33 #: terminal/serializers/applet_host.py:33
msgid "Enabled" msgid "Enabled"
msgstr "启用" msgstr "启用"
@ -2117,7 +2117,7 @@ msgstr "重命名"
msgid "Symlink" msgid "Symlink"
msgstr "建立软链接" msgstr "建立软链接"
#: audits/const.py:18 perms/const.py:14 #: audits/const.py:18 audits/const.py:28 perms/const.py:14
msgid "Download" msgid "Download"
msgstr "下载" msgstr "下载"
@ -2137,44 +2137,44 @@ msgstr "查看"
msgid "Create" msgid "Create"
msgstr "创建" msgstr "创建"
#: audits/const.py:28 perms/const.py:12 #: audits/const.py:29 perms/const.py:12
msgid "Connect" msgid "Connect"
msgstr "连接" msgstr "连接"
#: audits/const.py:29 authentication/templates/authentication/login.html:252 #: audits/const.py:30 authentication/templates/authentication/login.html:252
#: authentication/templates/authentication/login.html:325 #: authentication/templates/authentication/login.html:325
#: templates/_header_bar.html:89 #: templates/_header_bar.html:89
msgid "Login" msgid "Login"
msgstr "登录" msgstr "登录"
#: audits/const.py:30 ops/const.py:9 #: audits/const.py:31 ops/const.py:9
msgid "Change password" msgid "Change password"
msgstr "改密" msgstr "改密"
#: audits/const.py:35 settings/serializers/terminal.py:6 #: audits/const.py:36 settings/serializers/terminal.py:6
#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:164 #: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:164
#: terminal/serializers/session.py:49 terminal/serializers/session.py:63 #: terminal/serializers/session.py:49 terminal/serializers/session.py:63
msgid "Terminal" msgid "Terminal"
msgstr "终端" msgstr "终端"
#: audits/const.py:40 audits/models.py:127 #: audits/const.py:41 audits/models.py:127
msgid "Operate log" msgid "Operate log"
msgstr "操作日志" msgstr "操作日志"
#: audits/const.py:41 #: audits/const.py:42
msgid "Session log" msgid "Session log"
msgstr "会话日志" msgstr "会话日志"
#: audits/const.py:42 #: audits/const.py:43
msgid "Login log" msgid "Login log"
msgstr "登录日志" msgstr "登录日志"
#: audits/const.py:43 terminal/models/applet/host.py:143 #: audits/const.py:44 terminal/models/applet/host.py:143
#: terminal/models/component/task.py:22 #: terminal/models/component/task.py:22
msgid "Task" msgid "Task"
msgstr "任务" msgstr "任务"
#: audits/const.py:49 #: audits/const.py:50
msgid "-" msgid "-"
msgstr "-" msgstr "-"
@ -2398,7 +2398,7 @@ msgstr "ACL 动作是复核"
msgid "Current user not support mfa type: {}" msgid "Current user not support mfa type: {}"
msgstr "当前用户不支持 MFA 类型: {}" msgstr "当前用户不支持 MFA 类型: {}"
#: authentication/api/password.py:32 terminal/api/session/session.py:259 #: authentication/api/password.py:32 terminal/api/session/session.py:284
#: users/views/profile/reset.py:44 #: users/views/profile/reset.py:44
msgid "User does not exist: {}" msgid "User does not exist: {}"
msgstr "用户不存在: {}" msgstr "用户不存在: {}"
@ -4055,7 +4055,7 @@ msgstr "默认组织"
msgid "SYSTEM" msgid "SYSTEM"
msgstr "系统组织" msgstr "系统组织"
#: orgs/models.py:83 rbac/models/role.py:36 terminal/models/applet/applet.py:40 #: orgs/models.py:83 rbac/models/role.py:36 terminal/models/applet/applet.py:41
msgid "Builtin" msgid "Builtin"
msgstr "内置的" msgstr "内置的"
@ -4291,7 +4291,7 @@ msgstr "权限"
msgid "Users amount" msgid "Users amount"
msgstr "用户数量" msgstr "用户数量"
#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:33 #: rbac/serializers/role.py:28 terminal/models/applet/applet.py:34
msgid "Display name" msgid "Display name"
msgstr "显示名称" msgstr "显示名称"
@ -4351,8 +4351,8 @@ msgstr "任务中心"
msgid "My assets" msgid "My assets"
msgstr "我的资产" msgstr "我的资产"
#: rbac/tree.py:56 terminal/models/applet/applet.py:51 #: rbac/tree.py:56 terminal/models/applet/applet.py:52
#: terminal/models/applet/applet.py:280 terminal/models/applet/host.py:29 #: terminal/models/applet/applet.py:298 terminal/models/applet/host.py:29
#: terminal/serializers/applet.py:15 #: terminal/serializers/applet.py:15
msgid "Applet" msgid "Applet"
msgstr "远程应用" msgstr "远程应用"
@ -5818,15 +5818,20 @@ msgstr "测试失败: 账号无效"
msgid "Have online sessions" msgid "Have online sessions"
msgstr "有在线会话" msgstr "有在线会话"
#: terminal/api/session/session.py:251 #: terminal/api/session/session.py:47
#, python-format
msgid "User %s %s session %s replay"
msgstr "用户 %s %s 了会话 %s 的录像"
#: terminal/api/session/session.py:276
msgid "Session does not exist: {}" msgid "Session does not exist: {}"
msgstr "会话不存在: {}" msgstr "会话不存在: {}"
#: terminal/api/session/session.py:254 #: terminal/api/session/session.py:279
msgid "Session is finished or the protocol not supported" msgid "Session is finished or the protocol not supported"
msgstr "会话已经完成或协议不支持" msgstr "会话已经完成或协议不支持"
#: terminal/api/session/session.py:267 #: terminal/api/session/session.py:292
msgid "User does not have permission" msgid "User does not have permission"
msgstr "用户没有权限" msgstr "用户没有权限"
@ -5944,51 +5949,51 @@ msgstr "不支持批量创建"
msgid "Storage is invalid" msgid "Storage is invalid"
msgstr "存储无效" msgstr "存储无效"
#: terminal/models/applet/applet.py:29 #: terminal/models/applet/applet.py:30
msgid "Community" msgid "Community"
msgstr "社区版" msgstr "社区版"
#: terminal/models/applet/applet.py:30 #: terminal/models/applet/applet.py:31
msgid "Enterprise" msgid "Enterprise"
msgstr "企业版" msgstr "企业版"
#: terminal/models/applet/applet.py:35 #: terminal/models/applet/applet.py:36
msgid "Author" msgid "Author"
msgstr "作者" msgstr "作者"
#: terminal/models/applet/applet.py:37 terminal/serializers/applet.py:31 #: terminal/models/applet/applet.py:38 terminal/serializers/applet.py:31
msgid "Edition" msgid "Edition"
msgstr "版本" msgstr "版本"
#: terminal/models/applet/applet.py:42 #: terminal/models/applet/applet.py:43
msgid "Can concurrent" msgid "Can concurrent"
msgstr "可以并发" msgstr "可以并发"
#: terminal/models/applet/applet.py:43 #: terminal/models/applet/applet.py:44
msgid "Tags" msgid "Tags"
msgstr "标签" msgstr "标签"
#: terminal/models/applet/applet.py:47 terminal/serializers/storage.py:159 #: terminal/models/applet/applet.py:48 terminal/serializers/storage.py:159
msgid "Hosts" msgid "Hosts"
msgstr "主机" msgstr "主机"
#: terminal/models/applet/applet.py:92 #: terminal/models/applet/applet.py:93
msgid "Applet pkg not valid, Missing file {}" msgid "Applet pkg not valid, Missing file {}"
msgstr "Applet pkg 无效,缺少文件 {}" msgstr "Applet pkg 无效,缺少文件 {}"
#: terminal/models/applet/applet.py:111 #: terminal/models/applet/applet.py:112
msgid "Load platform.yml failed: {}" msgid "Load platform.yml failed: {}"
msgstr "加载 platform.yml 失败: {}" msgstr "加载 platform.yml 失败: {}"
#: terminal/models/applet/applet.py:114 #: terminal/models/applet/applet.py:115
msgid "Only support custom platform" msgid "Only support custom platform"
msgstr "只支持自定义平台" msgstr "只支持自定义平台"
#: terminal/models/applet/applet.py:119 #: terminal/models/applet/applet.py:120
msgid "Missing type in platform.yml" msgid "Missing type in platform.yml"
msgstr "在 platform.yml 中缺少类型" msgstr "在 platform.yml 中缺少类型"
#: terminal/models/applet/applet.py:282 terminal/models/applet/host.py:35 #: terminal/models/applet/applet.py:300 terminal/models/applet/host.py:35
#: terminal/models/applet/host.py:137 #: terminal/models/applet/host.py:137
msgid "Hosting" msgid "Hosting"
msgstr "宿主机" msgstr "宿主机"

View File

@ -8,7 +8,7 @@ from django.db.models import F
from django.http import FileResponse from django.http import FileResponse
from django.shortcuts import get_object_or_404, reverse from django.shortcuts import get_object_or_404, reverse
from django.utils.encoding import escape_uri_path from django.utils.encoding import escape_uri_path
from django.utils.translation import gettext as _ from django.utils.translation import gettext_noop, gettext as _
from django_filters import rest_framework as filters from django_filters import rest_framework as filters
from rest_framework import generics from rest_framework import generics
from rest_framework import viewsets, views from rest_framework import viewsets, views
@ -16,14 +16,16 @@ from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response from rest_framework.response import Response
from audits.const import ActionChoices
from common.api import AsyncApiMixin from common.api import AsyncApiMixin
from common.const.http import GET from common.const.http import GET
from common.drf.filters import BaseFilterSet from common.drf.filters import BaseFilterSet
from common.drf.filters import DatetimeRangeFilterBackend from common.drf.filters import DatetimeRangeFilterBackend
from common.drf.renders import PassthroughRenderer from common.drf.renders import PassthroughRenderer
from common.storage.replay import ReplayStorageHandler from common.storage.replay import ReplayStorageHandler
from common.utils import data_to_json, is_uuid from common.utils import data_to_json, is_uuid, i18n_fmt
from common.utils import get_logger, get_object_or_none from common.utils import get_logger, get_object_or_none
from common.views.mixins import RecordViewLogMixin
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from orgs.utils import tmp_to_root_org, tmp_to_org from orgs.utils import tmp_to_root_org, tmp_to_org
from rbac.permissions import RBACPermission from rbac.permissions import RBACPermission
@ -41,6 +43,8 @@ __all__ = [
logger = get_logger(__name__) logger = get_logger(__name__)
REPLAY_OP = gettext_noop('User %s %s session %s replay')
class MySessionAPIView(generics.ListAPIView): class MySessionAPIView(generics.ListAPIView):
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticated,)
@ -70,7 +74,7 @@ class SessionFilterSet(BaseFilterSet):
return queryset.filter(terminal__name=value) return queryset.filter(terminal__name=value)
class SessionViewSet(OrgBulkModelViewSet): class SessionViewSet(RecordViewLogMixin, OrgBulkModelViewSet):
model = Session model = Session
serializer_classes = { serializer_classes = {
'default': serializers.SessionSerializer, 'default': serializers.SessionSerializer,
@ -132,6 +136,14 @@ class SessionViewSet(OrgBulkModelViewSet):
filename = escape_uri_path('{}.tar'.format(storage.obj.id)) filename = escape_uri_path('{}.tar'.format(storage.obj.id))
disposition = "attachment; filename*=UTF-8''{}".format(filename) disposition = "attachment; filename*=UTF-8''{}".format(filename)
response["Content-Disposition"] = disposition response["Content-Disposition"] = disposition
detail = i18n_fmt(
REPLAY_OP, self.request.user, _('Download'), str(storage.obj)
)
self.record_logs(
[storage.obj.asset_id], ActionChoices.download, detail,
model=Session, resource_display=str(storage.obj)
)
return response return response
def get_queryset(self): def get_queryset(self):
@ -152,7 +164,7 @@ class SessionViewSet(OrgBulkModelViewSet):
return super().perform_create(serializer) return super().perform_create(serializer)
class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet): class SessionReplayViewSet(AsyncApiMixin, RecordViewLogMixin, viewsets.ViewSet):
serializer_class = serializers.ReplaySerializer serializer_class = serializers.ReplaySerializer
download_cache_key = "SESSION_REPLAY_DOWNLOAD_{}" download_cache_key = "SESSION_REPLAY_DOWNLOAD_{}"
session = None session = None
@ -215,6 +227,17 @@ class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet):
return False return False
return True return True
def async_callback(self, *args, **kwargs):
session_id = kwargs.get('pk')
session = get_object_or_404(Session, id=session_id)
detail = i18n_fmt(
REPLAY_OP, self.request.user, _('View'), str(session)
)
self.record_logs(
[session.asset_id], ActionChoices.download, detail,
model=Session, resource_display=str(session)
)
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
session_id = kwargs.get('pk') session_id = kwargs.get('pk')
session = get_object_or_404(Session, id=session_id) session = get_object_or_404(Session, id=session_id)