diff --git a/apps/accounts/automations/backup_account/handlers.py b/apps/accounts/automations/backup_account/handlers.py index e708e8d2d..f4fffca8d 100644 --- a/apps/accounts/automations/backup_account/handlers.py +++ b/apps/accounts/automations/backup_account/handlers.py @@ -6,11 +6,14 @@ from django.conf import settings from openpyxl import Workbook from rest_framework import serializers -from accounts.notifications import AccountBackupExecutionTaskMsg +from accounts.const.automation import AccountBackupType +from accounts.notifications import AccountBackupExecutionTaskMsg, AccountBackupByObjStorageExecutionTaskMsg from accounts.serializers import AccountSecretSerializer +from accounts.models.automations.backup_account import AccountBackupAutomation from assets.const import AllTypes -from common.utils.file import encrypt_and_compress_zip_file +from common.utils.file import encrypt_and_compress_zip_file, zip_files from common.utils.timezone import local_now_display +from terminal.models.component.storage import ReplayStorage from users.models import User PATH = os.path.join(os.path.dirname(settings.BASE_DIR), 'tmp') @@ -169,6 +172,29 @@ class AccountBackupHandler: for file in files: os.remove(file) + def send_backup_obj_storage(self, files, recipients, password): + if not files: + return + recipients = ReplayStorage.objects.filter(id__in=list(recipients)) + print( + '\n' + '\033[32m>>> 发送备份文件到sftp服务器\033[0m' + '' + ) + plan_name = self.plan_name + for rec in recipients: + attachment = os.path.join(PATH, f'{plan_name}-{local_now_display()}-{time.time()}.zip') + if password: + password = password.encode('utf8') + encrypt_and_compress_zip_file(attachment, password, files) + else: + zip_files(attachment, files) + attachment_list = attachment + AccountBackupByObjStorageExecutionTaskMsg(plan_name, rec).publish(attachment_list) + print('备份文件将发送至{}({})'.format(rec.name, rec.id)) + for file in files: + os.remove(file) + def step_perform_task_update(self, is_success, reason): self.execution.reason = reason[:1024] self.execution.is_success = is_success @@ -186,24 +212,11 @@ class AccountBackupHandler: is_success = False error = '-' try: - recipients_part_one = self.execution.snapshot.get('recipients_part_one', []) - recipients_part_two = self.execution.snapshot.get('recipients_part_two', []) - if not recipients_part_one and not recipients_part_two: - print( - '\n' - '\033[32m>>> 该备份任务未分配收件人\033[0m' - '' - ) - if recipients_part_one and recipients_part_two: - files = self.create_excel(section='front') - self.send_backup_mail(files, recipients_part_one) - - files = self.create_excel(section='back') - self.send_backup_mail(files, recipients_part_two) - else: - recipients = recipients_part_one or recipients_part_two - files = self.create_excel() - self.send_backup_mail(files, recipients) + backup_type = self.execution.snapshot.get('backup_type', AccountBackupType.email.value) + if backup_type == AccountBackupType.email.value: + self.backup_by_email() + elif backup_type == AccountBackupType.object_storage.value: + self.backup_by_obj_storage() except Exception as e: self.is_frozen = True print('任务执行被异常中断') @@ -217,6 +230,48 @@ class AccountBackupHandler: self.step_perform_task_update(is_success, reason) self.step_finished(is_success) + def backup_by_obj_storage(self): + object_id = self.execution.snapshot.get('id') + zip_encrypt_password = AccountBackupAutomation.objects.get(id=object_id).zip_encrypt_password + obj_recipients_part_one = self.execution.snapshot.get('obj_recipients_part_one', []) + obj_recipients_part_two = self.execution.snapshot.get('obj_recipients_part_two', []) + if not obj_recipients_part_one and not obj_recipients_part_two: + print( + '\n' + '\033[32m>>> 该备份任务未分配sftp服务器\033[0m' + '' + ) + if obj_recipients_part_one and obj_recipients_part_two: + files = self.create_excel(section='front') + self.send_backup_obj_storage(files, obj_recipients_part_one, zip_encrypt_password) + + files = self.create_excel(section='back') + self.send_backup_obj_storage(files, obj_recipients_part_two, zip_encrypt_password) + else: + recipients = obj_recipients_part_one or obj_recipients_part_two + files = self.create_excel() + self.send_backup_obj_storage(files, recipients, zip_encrypt_password) + + def backup_by_email(self): + recipients_part_one = self.execution.snapshot.get('recipients_part_one', []) + recipients_part_two = self.execution.snapshot.get('recipients_part_two', []) + if not recipients_part_one and not recipients_part_two: + print( + '\n' + '\033[32m>>> 该备份任务未分配收件人\033[0m' + '' + ) + if recipients_part_one and recipients_part_two: + files = self.create_excel(section='front') + self.send_backup_mail(files, recipients_part_one) + + files = self.create_excel(section='back') + self.send_backup_mail(files, recipients_part_two) + else: + recipients = recipients_part_one or recipients_part_two + files = self.create_excel() + self.send_backup_mail(files, recipients) + def run(self): print('任务开始: {}'.format(local_now_display())) time_start = time.time() diff --git a/apps/accounts/const/automation.py b/apps/accounts/const/automation.py index b27080a6f..0a67de5c8 100644 --- a/apps/accounts/const/automation.py +++ b/apps/accounts/const/automation.py @@ -16,7 +16,7 @@ DEFAULT_PASSWORD_RULES = { __all__ = [ 'AutomationTypes', 'SecretStrategy', 'SSHKeyStrategy', 'Connectivity', 'DEFAULT_PASSWORD_LENGTH', 'DEFAULT_PASSWORD_RULES', 'TriggerChoice', - 'PushAccountActionChoice', + 'PushAccountActionChoice', 'AccountBackupType' ] @@ -95,3 +95,10 @@ class TriggerChoice(models.TextChoices, TreeChoices): class PushAccountActionChoice(models.TextChoices): create_and_push = 'create_and_push', _('Create and push') only_create = 'only_create', _('Only create') + + +class AccountBackupType(models.TextChoices): + """Backup type""" + email = 'email', _('Email') + # 目前只支持sftp方式 + object_storage = 'object_storage', _('SFTP') diff --git a/apps/accounts/migrations/0018_accountbackupautomation_backup_type_and_more.py b/apps/accounts/migrations/0018_accountbackupautomation_backup_type_and_more.py new file mode 100644 index 000000000..e7e04fb24 --- /dev/null +++ b/apps/accounts/migrations/0018_accountbackupautomation_backup_type_and_more.py @@ -0,0 +1,45 @@ +# Generated by Django 4.1.10 on 2023-11-03 07:10 + +import common.db.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('terminal', '0067_alter_replaystorage_type'), + ('accounts', '0017_alter_automationexecution_options'), + ] + + operations = [ + migrations.AddField( + model_name='accountbackupautomation', + name='backup_type', + field=models.CharField(choices=[('email', 'Email'), ('object_storage', 'Object Storage')], default='email', max_length=128), + ), + migrations.AddField( + model_name='accountbackupautomation', + name='is_password_divided_by_email', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='accountbackupautomation', + name='is_password_divided_by_obj_storage', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='accountbackupautomation', + name='obj_recipients_part_one', + field=models.ManyToManyField(blank=True, related_name='obj_recipient_part_one_plans', to='terminal.replaystorage', verbose_name='Object Storage Recipient part one'), + ), + migrations.AddField( + model_name='accountbackupautomation', + name='obj_recipients_part_two', + field=models.ManyToManyField(blank=True, related_name='obj_recipient_part_two_plans', to='terminal.replaystorage', verbose_name='Object Storage Recipient part two'), + ), + migrations.AddField( + model_name='accountbackupautomation', + name='zip_encrypt_password', + field=common.db.fields.EncryptCharField(blank=True, max_length=4096, null=True, verbose_name='Zip Encrypt Password'), + ), + ] diff --git a/apps/accounts/models/automations/backup_account.py b/apps/accounts/models/automations/backup_account.py index c99c9e220..db325c702 100644 --- a/apps/accounts/models/automations/backup_account.py +++ b/apps/accounts/models/automations/backup_account.py @@ -8,10 +8,11 @@ from django.db import models from django.db.models import F from django.utils.translation import gettext_lazy as _ +from accounts.const.automation import AccountBackupType from common.const.choices import Trigger +from common.db import fields from common.db.encoder import ModelJSONFieldEncoder -from common.utils import get_logger -from common.utils import lazyproperty +from common.utils import get_logger, lazyproperty from ops.mixin import PeriodTaskModelMixin from orgs.mixins.models import OrgModelMixin, JMSOrgBaseModel @@ -22,6 +23,10 @@ logger = get_logger(__file__) class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel): types = models.JSONField(default=list) + backup_type = models.CharField(max_length=128, choices=AccountBackupType.choices, + default=AccountBackupType.email.value, verbose_name=_('Backup Type')) + is_password_divided_by_email = models.BooleanField(default=True, verbose_name=_('Is Password Divided')) + is_password_divided_by_obj_storage = models.BooleanField(default=True, verbose_name=_('Is Password Divided')) recipients_part_one = models.ManyToManyField( 'users.User', related_name='recipient_part_one_plans', blank=True, verbose_name=_("Recipient part one") @@ -30,6 +35,16 @@ class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel): 'users.User', related_name='recipient_part_two_plans', blank=True, verbose_name=_("Recipient part two") ) + obj_recipients_part_one = models.ManyToManyField( + 'terminal.ReplayStorage', related_name='obj_recipient_part_one_plans', blank=True, + verbose_name=_("Object Storage Recipient part one") + ) + obj_recipients_part_two = models.ManyToManyField( + 'terminal.ReplayStorage', related_name='obj_recipient_part_two_plans', blank=True, + verbose_name=_("Object Storage Recipient part two") + ) + zip_encrypt_password = fields.EncryptCharField(max_length=4096, blank=True, null=True, + verbose_name=_('Zip Encrypt Password')) def __str__(self): return f'{self.name}({self.org_id})' @@ -49,6 +64,7 @@ class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel): def to_attr_json(self): return { + 'id': self.id, 'name': self.name, 'is_periodic': self.is_periodic, 'interval': self.interval, @@ -56,6 +72,10 @@ class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel): 'org_id': self.org_id, 'created_by': self.created_by, 'types': self.types, + 'backup_type': self.backup_type, + 'is_password_divided_by_email': self.is_password_divided_by_email, + 'is_password_divided_by_obj_storage': self.is_password_divided_by_obj_storage, + 'zip_encrypt_password': self.zip_encrypt_password, 'recipients_part_one': { str(user.id): (str(user), bool(user.secret_key)) for user in self.recipients_part_one.all() @@ -63,7 +83,15 @@ class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel): 'recipients_part_two': { str(user.id): (str(user), bool(user.secret_key)) for user in self.recipients_part_two.all() - } + }, + 'obj_recipients_part_one': { + str(obj_storage.id): (str(obj_storage.name), str(obj_storage.type)) + for obj_storage in self.obj_recipients_part_one.all() + }, + 'obj_recipients_part_two': { + str(obj_storage.id): (str(obj_storage.name), str(obj_storage.type)) + for obj_storage in self.obj_recipients_part_two.all() + }, } @property diff --git a/apps/accounts/notifications.py b/apps/accounts/notifications.py index eb716a27a..b650410d1 100644 --- a/apps/accounts/notifications.py +++ b/apps/accounts/notifications.py @@ -1,9 +1,10 @@ from django.template.loader import render_to_string from django.utils.translation import gettext_lazy as _ -from common.tasks import send_mail_attachment_async +from common.tasks import send_mail_attachment_async, upload_backup_to_obj_storage from notifications.notifications import UserMessage from users.models import User +from terminal.models.component.storage import ReplayStorage class AccountBackupExecutionTaskMsg(object): @@ -31,6 +32,25 @@ class AccountBackupExecutionTaskMsg(object): ) +class AccountBackupByObjStorageExecutionTaskMsg(object): + subject = _('Notification of account backup route task results') + + def __init__(self, name: str, obj_storage: ReplayStorage): + self.name = name + self.obj_storage = obj_storage + + @property + def message(self): + name = self.name + return _('{} - The account backup passage task has been completed.' + ' See the attachment for details').format(name) + + def publish(self, attachment_list=None): + upload_backup_to_obj_storage( + self.obj_storage, attachment_list + ) + + class ChangeSecretExecutionTaskMsg(object): subject = _('Notification of implementation result of encryption change plan') diff --git a/apps/accounts/serializers/account/backup.py b/apps/accounts/serializers/account/backup.py index f11861fa3..a67d834c6 100644 --- a/apps/accounts/serializers/account/backup.py +++ b/apps/accounts/serializers/account/backup.py @@ -5,7 +5,7 @@ from rest_framework import serializers from accounts.models import AccountBackupAutomation, AccountBackupExecution from common.const.choices import Trigger -from common.serializers.fields import LabeledChoiceField +from common.serializers.fields import LabeledChoiceField, EncryptedField from common.utils import get_logger from ops.mixin import PeriodTaskSerializerMixin from orgs.mixins.serializers import BulkOrgResourceModelSerializer @@ -16,6 +16,11 @@ __all__ = ['AccountBackupSerializer', 'AccountBackupPlanExecutionSerializer'] class AccountBackupSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSerializer): + zip_encrypt_password = EncryptedField( + label=_('Zip Encrypt Password'), required=False, max_length=40960, allow_blank=True, + allow_null=True, write_only=True, + ) + class Meta: model = AccountBackupAutomation read_only_fields = [ @@ -24,7 +29,9 @@ class AccountBackupSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSer ] fields = read_only_fields + [ 'id', 'name', 'is_periodic', 'interval', 'crontab', - 'comment', 'types', 'recipients_part_one', 'recipients_part_two' + 'comment', 'types', 'recipients_part_one', 'recipients_part_two', 'backup_type', + 'is_password_divided_by_email', 'is_password_divided_by_obj_storage', 'obj_recipients_part_one', + 'obj_recipients_part_two', 'zip_encrypt_password' ] extra_kwargs = { 'name': {'required': True}, diff --git a/apps/common/tasks.py b/apps/common/tasks.py index 468fa2a51..d5c0cb609 100644 --- a/apps/common/tasks.py +++ b/apps/common/tasks.py @@ -4,6 +4,7 @@ from celery import shared_task from django.conf import settings from django.core.mail import send_mail, EmailMultiAlternatives from django.utils.translation import gettext_lazy as _ +import jms_storage from .utils import get_logger @@ -63,3 +64,18 @@ def send_mail_attachment_async(subject, message, recipient_list, attachment_list return email.send() except Exception as e: logger.error("Sending mail attachment error: {}".format(e)) + + +@shared_task(verbose_name=_('Upload session replay to external storage')) +def upload_backup_to_obj_storage(recipient, upload_file): + logger.info(f'Start upload file : {upload_file}') + remote_path = os.path.join('account_backup', os.path.basename(upload_file)) + storage = jms_storage.get_object_storage(recipient.config) + ok, err = storage.upload(src=upload_file, target=remote_path) + if not ok: + logger.error(f'upload {upload_file} failed, error: {err}') + return + try: + os.remove(upload_file) + except Exception as e: + print(f'remove upload file : {upload_file} error: {e}') diff --git a/apps/common/utils/file.py b/apps/common/utils/file.py index efc652870..ac3f5868b 100644 --- a/apps/common/utils/file.py +++ b/apps/common/utils/file.py @@ -3,6 +3,7 @@ import csv import pyzipper import requests +import zipfile from hashlib import md5 @@ -10,7 +11,7 @@ from django.conf import settings def create_csv_file(filename, headers, rows, ): - with open(filename, 'w', encoding='utf-8-sig')as f: + with open(filename, 'w', encoding='utf-8-sig') as f: w = csv.writer(f) w.writerow(headers) w.writerows(rows) @@ -26,6 +27,20 @@ def encrypt_and_compress_zip_file(filename, secret_password, encrypted_filenames zf.writestr(os.path.basename(encrypted_filename), f.read()) +def zip_files(output_file, file_list): + """ + 将多个文件打包成zip文件 + Args: + output_file (str): 打包后的zip文件路径 + file_list (list): 需要打包的文件列表 + Returns: + None + """ + with zipfile.ZipFile(output_file, 'w') as zipf: + for file in file_list: + zipf.write(file, arcname=os.path.basename(file)) + + def download_file(src, path): with requests.get(src, stream=True) as r: r.raise_for_status() diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 7467d47c6..fa4a3dc61 100644 --- a/apps/locale/ja/LC_MESSAGES/django.mo +++ b/apps/locale/ja/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cde05981ba0517af982f7ef197aed433c52510098589e4a6ce5101e48c26556e -size 163803 +oid sha256:5a5207051b4a959f750ebd48c770a552c460f864547aea8d6bb62d8920e24e32 +size 164428 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 0e05c61e2..cd412a9b8 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-03 16:52+0800\n" +"POT-Creation-Date: 2023-11-03 18:29+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -24,11 +24,12 @@ msgstr "パラメータ 'action' は [{}] でなければなりません。" #: accounts/const/account.py:6 #: accounts/serializers/automations/change_secret.py:32 -#: assets/models/_user.py:24 audits/signal_handlers/login_log.py:34 +#: assets/models/_user.py:23 audits/signal_handlers/login_log.py:34 #: authentication/confirm/password.py:9 authentication/confirm/password.py:24 #: authentication/confirm/password.py:26 authentication/forms.py:32 #: authentication/templates/authentication/login.html:330 #: settings/serializers/auth/ldap.py:25 settings/serializers/auth/ldap.py:47 +#: terminal/serializers/storage.py:123 terminal/serializers/storage.py:142 #: users/forms/profile.py:22 users/serializers/user.py:104 #: users/templates/users/_msg_user_created.html:13 #: users/templates/users/user_password_verify.html:18 @@ -38,6 +39,7 @@ msgstr "パスワード" #: accounts/const/account.py:7 #: accounts/serializers/automations/change_secret.py:33 +#: terminal/serializers/storage.py:124 msgid "SSH key" msgstr "SSH キー" @@ -45,7 +47,7 @@ msgstr "SSH キー" msgid "Access key" msgstr "アクセスキー" -#: accounts/const/account.py:9 assets/models/_user.py:48 +#: accounts/const/account.py:9 assets/models/_user.py:47 #: authentication/backends/passkey/models.py:16 #: authentication/models/sso_token.py:14 settings/serializers/feature.py:50 msgid "Token" @@ -97,7 +99,7 @@ msgstr "更新" #: accounts/const/account.py:33 #: accounts/serializers/automations/change_secret.py:150 audits/const.py:62 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 -#: ops/const.py:74 terminal/const.py:77 xpack/plugins/cloud/const.py:43 +#: ops/const.py:74 terminal/const.py:78 xpack/plugins/cloud/const.py:43 msgid "Failed" msgstr "失敗しました" @@ -189,6 +191,21 @@ msgstr "作成してプッシュ" msgid "Only create" msgstr "作成のみ" +#: accounts/const/automation.py:102 +#: authentication/serializers/password_mfa.py:16 +#: authentication/serializers/password_mfa.py:24 +#: notifications/backends/__init__.py:10 settings/serializers/msg.py:22 +#: settings/serializers/msg.py:57 users/forms/profile.py:102 +#: users/forms/profile.py:109 users/models/user.py:794 +#: users/templates/users/forgot_password.html:117 +#: users/views/profile/reset.py:92 +msgid "Email" +msgstr "メール" + +#: accounts/const/automation.py:104 terminal/const.py:86 +msgid "SFTP" +msgstr "SFTP" + #: accounts/const/vault.py:8 assets/const/category.py:12 #: assets/models/asset/database.py:9 assets/models/asset/database.py:24 msgid "Database" @@ -295,20 +312,42 @@ msgstr "アカウントを確認できます" msgid "Can push account" msgstr "アカウントをプッシュできます" -#: accounts/models/automations/backup_account.py:27 +#: accounts/models/automations/backup_account.py:28 +msgid "Backup Type" +msgstr "バックアップの種類" + +#: accounts/models/automations/backup_account.py:29 +#: accounts/models/automations/backup_account.py:30 +msgid "Is Password Divided" +msgstr "キーが 2 つの部分に分割されているかどうか" + +#: accounts/models/automations/backup_account.py:33 msgid "Recipient part one" msgstr "受信者 1" -#: accounts/models/automations/backup_account.py:31 +#: accounts/models/automations/backup_account.py:37 msgid "Recipient part two" msgstr "受信者 2" -#: accounts/models/automations/backup_account.py:40 -#: accounts/models/automations/backup_account.py:110 +#: accounts/models/automations/backup_account.py:41 +msgid "Object Storage Recipient part one" +msgstr "受信サーバー 1" + +#: accounts/models/automations/backup_account.py:45 +msgid "Object Storage Recipient part two" +msgstr "受信サーバー 2" + +#: accounts/models/automations/backup_account.py:48 +#: accounts/serializers/account/backup.py:20 +msgid "Zip Encrypt Password" +msgstr "新しいファイルの暗号化パスワード" + +#: accounts/models/automations/backup_account.py:56 +#: accounts/models/automations/backup_account.py:139 msgid "Account backup plan" msgstr "アカウントバックアップ計画" -#: accounts/models/automations/backup_account.py:91 +#: accounts/models/automations/backup_account.py:120 #: assets/models/automations/base.py:115 audits/models.py:64 #: ops/models/base.py:55 ops/models/celery.py:63 ops/models/job.py:228 #: ops/templates/ops/celery_task_log.html:75 @@ -319,37 +358,37 @@ msgstr "アカウントバックアップ計画" msgid "Date start" msgstr "開始日" -#: accounts/models/automations/backup_account.py:94 +#: accounts/models/automations/backup_account.py:123 #: authentication/templates/authentication/_msg_oauth_bind.html:11 #: notifications/notifications.py:186 msgid "Time" msgstr "時間" -#: accounts/models/automations/backup_account.py:98 +#: accounts/models/automations/backup_account.py:127 msgid "Account backup snapshot" msgstr "アカウントのバックアップスナップショット" -#: accounts/models/automations/backup_account.py:102 -#: accounts/serializers/account/backup.py:42 +#: accounts/models/automations/backup_account.py:131 +#: accounts/serializers/account/backup.py:49 #: accounts/serializers/automations/base.py:55 #: assets/models/automations/base.py:122 #: assets/serializers/automations/base.py:40 msgid "Trigger mode" msgstr "トリガーモード" -#: accounts/models/automations/backup_account.py:105 audits/models.py:202 +#: accounts/models/automations/backup_account.py:134 audits/models.py:202 #: terminal/models/session/sharing.py:125 xpack/plugins/cloud/models.py:205 msgid "Reason" msgstr "理由" -#: accounts/models/automations/backup_account.py:107 +#: accounts/models/automations/backup_account.py:136 #: accounts/serializers/automations/change_secret.py:105 #: accounts/serializers/automations/change_secret.py:128 #: ops/serializers/job.py:56 terminal/serializers/session.py:49 msgid "Is success" msgstr "成功は" -#: accounts/models/automations/backup_account.py:115 +#: accounts/models/automations/backup_account.py:144 msgid "Account backup execution" msgstr "アカウントバックアップの実行" @@ -394,7 +433,7 @@ msgid "SSH key change strategy" msgstr "SSHキープッシュ方式" #: accounts/models/automations/change_secret.py:15 -#: accounts/serializers/account/backup.py:34 +#: accounts/serializers/account/backup.py:41 #: accounts/serializers/automations/change_secret.py:56 msgid "Recipient" msgstr "受信者" @@ -458,13 +497,14 @@ msgstr "最終ログイン日" #: accounts/models/automations/push_account.py:15 accounts/models/base.py:65 #: accounts/serializers/account/virtual.py:21 acls/serializers/base.py:19 #: acls/serializers/base.py:50 acls/templates/acls/asset_login_reminder.html:5 -#: acls/templates/acls/user_login_reminder.html:5 assets/models/_user.py:23 +#: acls/templates/acls/user_login_reminder.html:5 assets/models/_user.py:22 #: audits/models.py:187 authentication/forms.py:25 authentication/forms.py:27 #: authentication/models/temp_token.py:9 #: authentication/templates/authentication/_msg_different_city.html:9 #: authentication/templates/authentication/_msg_oauth_bind.html:9 -#: users/forms/profile.py:32 users/forms/profile.py:115 -#: users/models/user.py:790 users/templates/users/_msg_user_created.html:12 +#: terminal/serializers/storage.py:136 users/forms/profile.py:32 +#: users/forms/profile.py:115 users/models/user.py:790 +#: users/templates/users/_msg_user_created.html:12 #: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Username" msgstr "ユーザー名" @@ -512,6 +552,7 @@ msgstr "アカウントの確認" #: accounts/serializers/automations/change_secret.py:45 #: authentication/serializers/connect_token_secret.py:41 #: authentication/serializers/connect_token_secret.py:50 +#: terminal/serializers/storage.py:140 msgid "Secret type" msgstr "鍵の種類" @@ -536,7 +577,7 @@ msgstr "パスワードルール" #: accounts/models/base.py:64 accounts/serializers/account/virtual.py:20 #: acls/models/base.py:35 acls/models/base.py:96 acls/models/command_acl.py:21 #: acls/serializers/base.py:35 applications/models.py:9 -#: assets/models/_user.py:22 assets/models/asset/common.py:91 +#: assets/models/_user.py:21 assets/models/asset/common.py:91 #: assets/models/asset/common.py:149 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:15 @@ -572,7 +613,7 @@ msgstr "特権アカウント" msgid "Is active" msgstr "アクティブです。" -#: accounts/models/template.py:17 assets/models/_user.py:53 +#: accounts/models/template.py:17 assets/models/_user.py:54 msgid "Auto push" msgstr "オートプッシュ" @@ -625,11 +666,11 @@ msgstr "" "ユーザー名とパスワードを使用せずにアセットに接続します。Webベースとカスタムタ" "イプのアセットのみをサポートします" -#: accounts/notifications.py:8 +#: accounts/notifications.py:9 accounts/notifications.py:34 msgid "Notification of account backup route task results" msgstr "アカウントバックアップルートタスクの結果の通知" -#: accounts/notifications.py:18 +#: accounts/notifications.py:19 accounts/notifications.py:43 msgid "" "{} - The account backup passage task has been completed. See the attachment " "for details" @@ -637,7 +678,7 @@ msgstr "" "{} -アカウントバックアップの通過タスクが完了しました。詳細は添付ファイルをご" "覧ください" -#: accounts/notifications.py:21 +#: accounts/notifications.py:22 msgid "" "{} - The account backup passage task has been completed: the encryption " "password has not been set - please go to personal information -> file " @@ -647,17 +688,17 @@ msgstr "" "されていません-個人情報にアクセスしてください-> ファイル暗号化パスワードを設" "定してください暗号化パスワード" -#: accounts/notifications.py:33 +#: accounts/notifications.py:53 msgid "Notification of implementation result of encryption change plan" msgstr "暗号化変更プランの実装結果の通知" -#: accounts/notifications.py:43 +#: accounts/notifications.py:63 msgid "" "{} - The encryption change task has been completed. See the attachment for " "details" msgstr "{} -暗号化変更タスクが完了しました。詳細は添付ファイルをご覧ください" -#: accounts/notifications.py:46 +#: accounts/notifications.py:66 msgid "" "{} - The encryption change task has been completed: the encryption password " "has not been set - please go to personal information -> file encryption " @@ -686,7 +727,7 @@ msgstr "カテゴリ" #: accounts/serializers/account/account.py:191 #: accounts/serializers/automations/base.py:54 acls/models/command_acl.py:24 #: acls/serializers/command_acl.py:19 applications/models.py:14 -#: assets/models/_user.py:50 assets/models/automations/base.py:20 +#: assets/models/_user.py:49 assets/models/automations/base.py:20 #: assets/models/cmd_filter.py:74 assets/models/platform.py:90 #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:113 #: assets/serializers/platform.py:132 audits/serializers.py:50 @@ -695,8 +736,8 @@ msgstr "カテゴリ" #: perms/serializers/user_permission.py:26 terminal/models/applet/applet.py:39 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 -#: terminal/serializers/session.py:21 terminal/serializers/storage.py:228 -#: terminal/serializers/storage.py:240 tickets/models/comment.py:26 +#: terminal/serializers/session.py:21 terminal/serializers/storage.py:264 +#: terminal/serializers/storage.py:276 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 #: tickets/serializers/ticket/ticket.py:19 @@ -778,28 +819,28 @@ msgstr "ユーザー" msgid "Date" msgstr "日付" -#: accounts/serializers/account/backup.py:31 +#: accounts/serializers/account/backup.py:38 #: accounts/serializers/automations/base.py:36 #: assets/serializers/automations/base.py:34 ops/mixin.py:23 ops/mixin.py:104 #: settings/serializers/auth/ldap.py:66 msgid "Periodic perform" msgstr "定期的なパフォーマンス" -#: accounts/serializers/account/backup.py:32 +#: accounts/serializers/account/backup.py:39 #: accounts/serializers/automations/base.py:37 msgid "Executed amount" msgstr "実行回数" -#: accounts/serializers/account/backup.py:35 +#: accounts/serializers/account/backup.py:42 #: accounts/serializers/automations/change_secret.py:57 msgid "Currently only mail sending is supported" msgstr "現在、メール送信のみがサポートされています" -#: accounts/serializers/account/backup.py:37 +#: accounts/serializers/account/backup.py:44 msgid "Asset type" msgstr "資産タイプ" -#: accounts/serializers/account/base.py:24 +#: accounts/serializers/account/base.py:24 terminal/serializers/storage.py:149 msgid "Key password" msgstr "キーパスワード" @@ -850,7 +891,7 @@ msgid "" "default parameters will be used" msgstr "关联平台,可以配置推送参数,如果不关联,则使用默认参数" -#: accounts/serializers/account/virtual.py:19 assets/models/_user.py:27 +#: accounts/serializers/account/virtual.py:19 assets/models/_user.py:26 #: 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 #: ops/models/job.py:145 ops/models/playbook.py:31 rbac/models/role.py:37 @@ -912,7 +953,7 @@ msgstr "自動タスク実行履歴" #: accounts/serializers/automations/change_secret.py:149 audits/const.py:61 #: audits/models.py:63 audits/signal_handlers/activity_log.py:33 #: common/const/choices.py:18 ops/const.py:72 ops/serializers/celery.py:40 -#: terminal/const.py:76 terminal/models/session/sharing.py:121 +#: terminal/const.py:77 terminal/models/session/sharing.py:121 #: tickets/views/approve.py:117 msgid "Success" msgstr "成功" @@ -937,8 +978,6 @@ msgid "Account execute automation" msgstr "アカウント実行の自動化" #: accounts/tasks/automation.py:51 accounts/tasks/automation.py:62 -#, fuzzy -#| msgid "Asset execute automation" msgid "Execute automation record" msgstr "アセット実行の自動化" @@ -1015,7 +1054,7 @@ msgstr "警告" msgid "Notifications" msgstr "通知" -#: acls/models/base.py:37 assets/models/_user.py:51 +#: acls/models/base.py:37 assets/models/_user.py:50 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:97 #: xpack/plugins/cloud/models.py:275 msgid "Priority" @@ -1051,7 +1090,7 @@ msgid "Accounts" msgstr "アカウント" #: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60 -#: ops/serializers/job.py:55 terminal/const.py:84 +#: ops/serializers/job.py:55 terminal/const.py:85 #: terminal/models/session/session.py:42 terminal/serializers/command.py:18 #: terminal/templates/terminal/_msg_command_alert.html:12 #: terminal/templates/terminal/_msg_command_execute_alert.html:10 @@ -1305,7 +1344,7 @@ msgid "Authentication failed" msgstr "認証に失敗しました" #: assets/automations/ping_gateway/manager.py:60 -#: assets/automations/ping_gateway/manager.py:86 terminal/const.py:100 +#: assets/automations/ping_gateway/manager.py:86 terminal/const.py:101 msgid "Connect failed" msgstr "接続に失敗しました" @@ -1541,97 +1580,97 @@ msgstr "Webサイト" msgid "This function is not supported temporarily" msgstr "この機能は一時的にサポートされていません" -#: assets/models/_user.py:25 +#: assets/models/_user.py:24 msgid "SSH private key" msgstr "SSH秘密鍵" -#: assets/models/_user.py:26 +#: assets/models/_user.py:25 msgid "SSH public key" msgstr "SSHパブリックキー" -#: assets/models/_user.py:28 assets/models/automations/base.py:114 +#: assets/models/_user.py:27 assets/models/automations/base.py:114 #: assets/models/cmd_filter.py:41 assets/models/group.py:19 #: audits/models.py:266 common/db/models.py:34 ops/models/base.py:54 #: ops/models/job.py:227 users/models/user.py:1024 msgid "Date created" msgstr "作成された日付" -#: assets/models/_user.py:29 assets/models/cmd_filter.py:42 +#: assets/models/_user.py:28 assets/models/cmd_filter.py:42 #: common/db/models.py:35 users/models/user.py:846 msgid "Date updated" msgstr "更新日" -#: assets/models/_user.py:30 assets/models/cmd_filter.py:44 +#: assets/models/_user.py:29 assets/models/cmd_filter.py:44 #: assets/models/cmd_filter.py:91 assets/models/group.py:18 #: common/db/models.py:32 users/models/user.py:835 #: users/serializers/group.py:29 msgid "Created by" msgstr "によって作成された" -#: assets/models/_user.py:40 +#: assets/models/_user.py:39 msgid "Automatic managed" msgstr "自動管理" -#: assets/models/_user.py:41 +#: assets/models/_user.py:40 msgid "Manually input" msgstr "手動入力" -#: assets/models/_user.py:45 +#: assets/models/_user.py:44 msgid "Common user" msgstr "共通ユーザー" -#: assets/models/_user.py:46 assets/models/_user.py:95 +#: assets/models/_user.py:45 assets/models/_user.py:98 msgid "Admin user" msgstr "管理ユーザー" -#: assets/models/_user.py:49 +#: assets/models/_user.py:48 msgid "Username same with user" msgstr "ユーザーと同じユーザー名" -#: assets/models/_user.py:52 authentication/models/connection_token.py:41 +#: assets/models/_user.py:53 authentication/models/connection_token.py:41 #: authentication/serializers/connect_token_secret.py:111 #: terminal/models/applet/applet.py:42 terminal/serializers/session.py:19 -#: terminal/serializers/session.py:45 terminal/serializers/storage.py:70 +#: terminal/serializers/session.py:45 terminal/serializers/storage.py:71 msgid "Protocol" msgstr "プロトコル" -#: assets/models/_user.py:54 +#: assets/models/_user.py:55 msgid "Sudo" msgstr "すど" -#: assets/models/_user.py:55 ops/const.py:49 ops/const.py:59 +#: assets/models/_user.py:56 ops/const.py:49 ops/const.py:59 msgid "Shell" msgstr "シェル" -#: assets/models/_user.py:56 +#: assets/models/_user.py:58 msgid "Login mode" msgstr "ログインモード" -#: assets/models/_user.py:57 +#: assets/models/_user.py:59 terminal/serializers/storage.py:152 msgid "SFTP Root" msgstr "SFTPルート" -#: assets/models/_user.py:58 +#: assets/models/_user.py:60 msgid "Home" msgstr "ホーム" -#: assets/models/_user.py:59 +#: assets/models/_user.py:61 msgid "System groups" msgstr "システムグループ" -#: assets/models/_user.py:62 +#: assets/models/_user.py:64 msgid "User switch" msgstr "ユーザースイッチ" -#: assets/models/_user.py:63 +#: assets/models/_user.py:66 msgid "Switch from" msgstr "から切り替え" -#: assets/models/_user.py:69 +#: assets/models/_user.py:72 msgid "System user" msgstr "システムユーザー" -#: assets/models/_user.py:71 +#: assets/models/_user.py:74 msgid "Can match system user" msgstr "システムユーザーに一致できます" @@ -1641,6 +1680,7 @@ msgstr "クラウド サービス" #: assets/models/asset/common.py:92 assets/models/platform.py:16 #: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:72 +#: terminal/serializers/storage.py:133 #: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "ポート" @@ -2969,7 +3009,7 @@ msgid "IP group" msgstr "IP グループ" #: authentication/models/connection_token.py:38 -#: terminal/serializers/storage.py:113 +#: terminal/serializers/storage.py:114 msgid "Account name" msgstr "アカウント名" @@ -3105,24 +3145,12 @@ msgstr "アクション" msgid "Is expired" msgstr "期限切れです" -#: authentication/serializers/password_mfa.py:16 -#: authentication/serializers/password_mfa.py:24 -#: notifications/backends/__init__.py:10 settings/serializers/msg.py:22 -#: settings/serializers/msg.py:57 users/forms/profile.py:102 -#: users/forms/profile.py:109 users/models/user.py:794 -#: users/templates/users/forgot_password.html:117 -#: users/views/profile/reset.py:92 -msgid "Email" -msgstr "メール" - #: authentication/serializers/password_mfa.py:29 #: users/templates/users/forgot_password.html:108 msgid "The {} cannot be empty" msgstr "{} 空にしてはならない" #: authentication/serializers/token.py:22 -#, fuzzy -#| msgid "Access key" msgid "Access IP" msgstr "IPホワイトリスト" @@ -3526,7 +3554,7 @@ msgstr "タイミングトリガー" msgid "Ready" msgstr "の準備を" -#: common/const/choices.py:16 terminal/const.py:75 tickets/const.py:29 +#: common/const/choices.py:16 terminal/const.py:76 tickets/const.py:29 #: tickets/const.py:39 msgid "Pending" msgstr "未定" @@ -3783,14 +3811,18 @@ msgstr "間違ったデータ タイプです。リストにする必要があ msgid "Invalid choice: {}" msgstr "無効なオプション: {}" -#: common/tasks.py:20 common/utils/verify_code.py:16 +#: common/tasks.py:21 common/utils/verify_code.py:16 msgid "Send email" msgstr "メールを送る" -#: common/tasks.py:47 +#: common/tasks.py:48 msgid "Send email attachment" msgstr "メールの添付ファイルを送信" +#: common/tasks.py:69 terminal/tasks.py:62 +msgid "Upload session replay to external storage" +msgstr "セッションの記録を外部ストレージにアップロードする" + #: common/utils/ip/geoip/utils.py:26 msgid "Invalid ip" msgstr "無効な IP" @@ -4520,8 +4552,6 @@ msgid "Can view file manager" msgstr "ファイルマネージャを表示できます" #: rbac/models/menu.py:20 -#, fuzzy -#| msgid "Can view my assets" msgid "Can view System Tools" msgstr "私の資産を見ることができます" @@ -6257,64 +6287,60 @@ msgstr "確認して同意する" msgid "Review & Cancel" msgstr "確認してキャンセル" -#: terminal/const.py:44 +#: terminal/const.py:45 msgid "Critical" msgstr "クリティカル" -#: terminal/const.py:45 +#: terminal/const.py:46 msgid "High" msgstr "高い" -#: terminal/const.py:46 terminal/const.py:82 +#: terminal/const.py:47 terminal/const.py:83 #: users/templates/users/reset_password.html:50 msgid "Normal" msgstr "正常" -#: terminal/const.py:47 +#: terminal/const.py:48 msgid "Offline" msgstr "オフライン" -#: terminal/const.py:78 +#: terminal/const.py:79 msgid "Mismatch" msgstr "一致しない" -#: terminal/const.py:83 +#: terminal/const.py:84 msgid "Tunnel" msgstr "ちかチャネル" -#: terminal/const.py:85 -msgid "SFTP" -msgstr "SFTP" - -#: terminal/const.py:89 +#: terminal/const.py:90 msgid "Read only" msgstr "読み取り専用" -#: terminal/const.py:90 +#: terminal/const.py:91 msgid "Writable" msgstr "書き込み可能" -#: terminal/const.py:94 +#: terminal/const.py:95 msgid "Kill session" msgstr "セッションを終了する" -#: terminal/const.py:95 +#: terminal/const.py:96 msgid "Lock session" msgstr "セッションをロックする" -#: terminal/const.py:96 +#: terminal/const.py:97 msgid "Unlock session" msgstr "セッションのロックを解除する" -#: terminal/const.py:101 +#: terminal/const.py:102 msgid "Replay create failed" msgstr "ビデオの作成に失敗しました" -#: terminal/const.py:102 +#: terminal/const.py:103 msgid "Replay upload failed" msgstr "動画のアップロードに失敗しました" -#: terminal/const.py:103 +#: terminal/const.py:104 msgid "Replay convert failed" msgstr "ビデオのトランスコーディングに失敗しました" @@ -6350,7 +6376,7 @@ msgstr "同時実行可能" msgid "Tags" msgstr "ラベル" -#: terminal/models/applet/applet.py:48 terminal/serializers/storage.py:161 +#: terminal/models/applet/applet.py:48 terminal/serializers/storage.py:197 msgid "Hosts" msgstr "ホスト" @@ -6443,9 +6469,9 @@ msgstr "Redis ポート" #: terminal/models/component/endpoint.py:29 #: terminal/models/component/endpoint.py:102 -#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:40 -#: terminal/serializers/storage.py:52 terminal/serializers/storage.py:82 -#: terminal/serializers/storage.py:92 terminal/serializers/storage.py:100 +#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:41 +#: terminal/serializers/storage.py:53 terminal/serializers/storage.py:83 +#: terminal/serializers/storage.py:93 terminal/serializers/storage.py:101 msgid "Endpoint" msgstr "エンドポイント" @@ -6697,7 +6723,7 @@ msgstr "" "URL を入力します。
例: https://172.16.10.110 または https://dev." "jumpserver.com" -#: terminal/serializers/applet_host.py:46 terminal/serializers/storage.py:172 +#: terminal/serializers/applet_host.py:46 terminal/serializers/storage.py:208 msgid "Ignore Certificate Verification" msgstr "証明書の検証を無視する" @@ -6860,69 +6886,78 @@ msgstr "表示からのログイン" msgid "Terminal display" msgstr "ターミナルディスプレイ" -#: terminal/serializers/storage.py:22 +#: terminal/serializers/storage.py:23 msgid "Endpoint invalid: remove path `{}`" msgstr "エンドポイントが無効: パス '{}' を削除" -#: terminal/serializers/storage.py:28 +#: terminal/serializers/storage.py:29 msgid "Bucket" msgstr "バケット" -#: terminal/serializers/storage.py:32 +#: terminal/serializers/storage.py:33 #: xpack/plugins/cloud/serializers/account_attrs.py:17 msgid "Access key id" msgstr "アクセスキー" -#: terminal/serializers/storage.py:36 +#: terminal/serializers/storage.py:37 #: xpack/plugins/cloud/serializers/account_attrs.py:20 msgid "Access key secret" msgstr "アクセスキーシークレット" -#: terminal/serializers/storage.py:67 xpack/plugins/cloud/models.py:250 +#: terminal/serializers/storage.py:68 xpack/plugins/cloud/models.py:250 msgid "Region" msgstr "リージョン" -#: terminal/serializers/storage.py:111 +#: terminal/serializers/storage.py:112 msgid "Container name" msgstr "コンテナー名" -#: terminal/serializers/storage.py:114 +#: terminal/serializers/storage.py:115 msgid "Account key" msgstr "アカウントキー" -#: terminal/serializers/storage.py:117 +#: terminal/serializers/storage.py:118 msgid "Endpoint suffix" msgstr "エンドポイントサフィックス" -#: terminal/serializers/storage.py:137 +#: terminal/serializers/storage.py:129 +msgid "HOST" +msgstr "" + +#: terminal/serializers/storage.py:146 users/models/user.py:822 +#: xpack/plugins/cloud/serializers/account_attrs.py:206 +msgid "Private key" +msgstr "ssh秘密鍵" + +#: terminal/serializers/storage.py:173 msgid "The address cannot contain the special character `#`" msgstr "アドレスには特殊文字「#」を含めることはできません" -#: terminal/serializers/storage.py:139 +#: terminal/serializers/storage.py:175 msgid "The address format is incorrect" msgstr "アドレス形式が正しくありません" -#: terminal/serializers/storage.py:146 +#: terminal/serializers/storage.py:182 msgid "Host invalid" msgstr "ホスト無効" -#: terminal/serializers/storage.py:149 +#: terminal/serializers/storage.py:185 msgid "Port invalid" msgstr "ポートが無効" -#: terminal/serializers/storage.py:164 +#: terminal/serializers/storage.py:200 msgid "Index by date" msgstr "日付による索引付け" -#: terminal/serializers/storage.py:165 +#: terminal/serializers/storage.py:201 msgid "Whether to create an index by date" msgstr "現在の日付に基づいてインデックスを動的に作成するかどうか" -#: terminal/serializers/storage.py:168 +#: terminal/serializers/storage.py:204 msgid "Index" msgstr "インデックス" -#: terminal/serializers/storage.py:170 +#: terminal/serializers/storage.py:206 msgid "Doc type" msgstr "Docタイプ" @@ -6942,10 +6977,6 @@ msgstr "端末の状態を定期的にクリーンアップする" msgid "Clean orphan session" msgstr "オフライン セッションをクリアする" -#: terminal/tasks.py:62 -msgid "Upload session replay to external storage" -msgstr "セッションの記録を外部ストレージにアップロードする" - #: terminal/tasks.py:91 msgid "Run applet host deployment" msgstr "アプリケーション マシンの展開を実行する" @@ -7500,11 +7531,6 @@ msgstr "電話" msgid "OTP secret key" msgstr "OTP 秘密" -#: users/models/user.py:822 -#: xpack/plugins/cloud/serializers/account_attrs.py:206 -msgid "Private key" -msgstr "ssh秘密鍵" - #: users/models/user.py:830 users/serializers/profile.py:128 #: users/serializers/user.py:166 msgid "Is first login" @@ -8664,3 +8690,6 @@ msgstr "エンタープライズプロフェッショナル版" #: xpack/plugins/license/models.py:86 msgid "Ultimate edition" msgstr "エンタープライズ・フラッグシップ・エディション" + +#~ msgid "Object Storage" +#~ msgstr "オブジェクトストレージ" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 91ea218c2..837642306 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:73e074ad0c1d8bfec0c2df6e2c9e29a230a3acc0e8ee1c0820910e8ce769fd52 -size 134072 +oid sha256:b9a380c7adbd9fad7af4257cb72742c0e68b50846591cc5b0124a0df539ec285 +size 134380 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 10d1bfa29..175d7b1d1 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-11-03 16:52+0800\n" +"POT-Creation-Date: 2023-11-03 18:29+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -23,11 +23,12 @@ msgstr "参数 'action' 必须是 [{}]" #: accounts/const/account.py:6 #: accounts/serializers/automations/change_secret.py:32 -#: assets/models/_user.py:24 audits/signal_handlers/login_log.py:34 +#: assets/models/_user.py:23 audits/signal_handlers/login_log.py:34 #: authentication/confirm/password.py:9 authentication/confirm/password.py:24 #: authentication/confirm/password.py:26 authentication/forms.py:32 #: authentication/templates/authentication/login.html:330 #: settings/serializers/auth/ldap.py:25 settings/serializers/auth/ldap.py:47 +#: terminal/serializers/storage.py:123 terminal/serializers/storage.py:142 #: users/forms/profile.py:22 users/serializers/user.py:104 #: users/templates/users/_msg_user_created.html:13 #: users/templates/users/user_password_verify.html:18 @@ -37,6 +38,7 @@ msgstr "密码" #: accounts/const/account.py:7 #: accounts/serializers/automations/change_secret.py:33 +#: terminal/serializers/storage.py:124 msgid "SSH key" msgstr "SSH 密钥" @@ -44,7 +46,7 @@ msgstr "SSH 密钥" msgid "Access key" msgstr "Access key" -#: accounts/const/account.py:9 assets/models/_user.py:48 +#: accounts/const/account.py:9 assets/models/_user.py:47 #: authentication/backends/passkey/models.py:16 #: authentication/models/sso_token.py:14 settings/serializers/feature.py:50 msgid "Token" @@ -96,7 +98,7 @@ msgstr "更新" #: accounts/const/account.py:33 #: accounts/serializers/automations/change_secret.py:150 audits/const.py:62 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 -#: ops/const.py:74 terminal/const.py:77 xpack/plugins/cloud/const.py:43 +#: ops/const.py:74 terminal/const.py:78 xpack/plugins/cloud/const.py:43 msgid "Failed" msgstr "失败" @@ -188,6 +190,21 @@ msgstr "创建并推送" msgid "Only create" msgstr "仅创建" +#: accounts/const/automation.py:102 +#: authentication/serializers/password_mfa.py:16 +#: authentication/serializers/password_mfa.py:24 +#: notifications/backends/__init__.py:10 settings/serializers/msg.py:22 +#: settings/serializers/msg.py:57 users/forms/profile.py:102 +#: users/forms/profile.py:109 users/models/user.py:794 +#: users/templates/users/forgot_password.html:117 +#: users/views/profile/reset.py:92 +msgid "Email" +msgstr "邮箱" + +#: accounts/const/automation.py:104 terminal/const.py:86 +msgid "SFTP" +msgstr "SFTP" + #: accounts/const/vault.py:8 assets/const/category.py:12 #: assets/models/asset/database.py:9 assets/models/asset/database.py:24 msgid "Database" @@ -294,20 +311,42 @@ msgstr "可以验证账号" msgid "Can push account" msgstr "可以推送账号" -#: accounts/models/automations/backup_account.py:27 +#: accounts/models/automations/backup_account.py:28 +msgid "Backup Type" +msgstr "备份类型" + +#: accounts/models/automations/backup_account.py:29 +#: accounts/models/automations/backup_account.py:30 +msgid "Is Password Divided" +msgstr "密钥是否拆分成前后两部分" + +#: accounts/models/automations/backup_account.py:33 msgid "Recipient part one" msgstr "收件人部分一" -#: accounts/models/automations/backup_account.py:31 +#: accounts/models/automations/backup_account.py:37 msgid "Recipient part two" msgstr "收件人部分二" -#: accounts/models/automations/backup_account.py:40 -#: accounts/models/automations/backup_account.py:110 +#: accounts/models/automations/backup_account.py:41 +msgid "Object Storage Recipient part one" +msgstr "接收服务器一" + +#: accounts/models/automations/backup_account.py:45 +msgid "Object Storage Recipient part two" +msgstr "接收服务器二" + +#: accounts/models/automations/backup_account.py:48 +#: accounts/serializers/account/backup.py:20 +msgid "Zip Encrypt Password" +msgstr "文件加密密码" + +#: accounts/models/automations/backup_account.py:56 +#: accounts/models/automations/backup_account.py:139 msgid "Account backup plan" msgstr "账号备份计划" -#: accounts/models/automations/backup_account.py:91 +#: accounts/models/automations/backup_account.py:120 #: assets/models/automations/base.py:115 audits/models.py:64 #: ops/models/base.py:55 ops/models/celery.py:63 ops/models/job.py:228 #: ops/templates/ops/celery_task_log.html:75 @@ -318,37 +357,37 @@ msgstr "账号备份计划" msgid "Date start" msgstr "开始日期" -#: accounts/models/automations/backup_account.py:94 +#: accounts/models/automations/backup_account.py:123 #: authentication/templates/authentication/_msg_oauth_bind.html:11 #: notifications/notifications.py:186 msgid "Time" msgstr "时间" -#: accounts/models/automations/backup_account.py:98 +#: accounts/models/automations/backup_account.py:127 msgid "Account backup snapshot" msgstr "账号备份快照" -#: accounts/models/automations/backup_account.py:102 -#: accounts/serializers/account/backup.py:42 +#: accounts/models/automations/backup_account.py:131 +#: accounts/serializers/account/backup.py:49 #: accounts/serializers/automations/base.py:55 #: assets/models/automations/base.py:122 #: assets/serializers/automations/base.py:40 msgid "Trigger mode" msgstr "触发模式" -#: accounts/models/automations/backup_account.py:105 audits/models.py:202 +#: accounts/models/automations/backup_account.py:134 audits/models.py:202 #: terminal/models/session/sharing.py:125 xpack/plugins/cloud/models.py:205 msgid "Reason" msgstr "原因" -#: accounts/models/automations/backup_account.py:107 +#: accounts/models/automations/backup_account.py:136 #: accounts/serializers/automations/change_secret.py:105 #: accounts/serializers/automations/change_secret.py:128 #: ops/serializers/job.py:56 terminal/serializers/session.py:49 msgid "Is success" msgstr "是否成功" -#: accounts/models/automations/backup_account.py:115 +#: accounts/models/automations/backup_account.py:144 msgid "Account backup execution" msgstr "账号备份执行" @@ -393,7 +432,7 @@ msgid "SSH key change strategy" msgstr "SSH 密钥推送方式" #: accounts/models/automations/change_secret.py:15 -#: accounts/serializers/account/backup.py:34 +#: accounts/serializers/account/backup.py:41 #: accounts/serializers/automations/change_secret.py:56 msgid "Recipient" msgstr "收件人" @@ -457,13 +496,14 @@ msgstr "最后登录日期" #: accounts/models/automations/push_account.py:15 accounts/models/base.py:65 #: accounts/serializers/account/virtual.py:21 acls/serializers/base.py:19 #: acls/serializers/base.py:50 acls/templates/acls/asset_login_reminder.html:5 -#: acls/templates/acls/user_login_reminder.html:5 assets/models/_user.py:23 +#: acls/templates/acls/user_login_reminder.html:5 assets/models/_user.py:22 #: audits/models.py:187 authentication/forms.py:25 authentication/forms.py:27 #: authentication/models/temp_token.py:9 #: authentication/templates/authentication/_msg_different_city.html:9 #: authentication/templates/authentication/_msg_oauth_bind.html:9 -#: users/forms/profile.py:32 users/forms/profile.py:115 -#: users/models/user.py:790 users/templates/users/_msg_user_created.html:12 +#: terminal/serializers/storage.py:136 users/forms/profile.py:32 +#: users/forms/profile.py:115 users/models/user.py:790 +#: users/templates/users/_msg_user_created.html:12 #: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Username" msgstr "用户名" @@ -511,6 +551,7 @@ msgstr "账号验证" #: accounts/serializers/automations/change_secret.py:45 #: authentication/serializers/connect_token_secret.py:41 #: authentication/serializers/connect_token_secret.py:50 +#: terminal/serializers/storage.py:140 msgid "Secret type" msgstr "密文类型" @@ -535,7 +576,7 @@ msgstr "密码规则" #: accounts/models/base.py:64 accounts/serializers/account/virtual.py:20 #: acls/models/base.py:35 acls/models/base.py:96 acls/models/command_acl.py:21 #: acls/serializers/base.py:35 applications/models.py:9 -#: assets/models/_user.py:22 assets/models/asset/common.py:91 +#: assets/models/_user.py:21 assets/models/asset/common.py:91 #: assets/models/asset/common.py:149 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:15 @@ -571,7 +612,7 @@ msgstr "特权账号" msgid "Is active" msgstr "激活" -#: accounts/models/template.py:17 assets/models/_user.py:53 +#: accounts/models/template.py:17 assets/models/_user.py:54 msgid "Auto push" msgstr "自动推送" @@ -626,17 +667,17 @@ msgid "" msgstr "" "连接资产时不使用用户名和密码的账号,仅支持 web类型 和 自定义类型 的资产" -#: accounts/notifications.py:8 +#: accounts/notifications.py:9 accounts/notifications.py:34 msgid "Notification of account backup route task results" msgstr "账号备份任务结果通知" -#: accounts/notifications.py:18 +#: accounts/notifications.py:19 accounts/notifications.py:43 msgid "" "{} - The account backup passage task has been completed. See the attachment " "for details" msgstr "{} - 账号备份任务已完成, 详情见附件" -#: accounts/notifications.py:21 +#: accounts/notifications.py:22 msgid "" "{} - The account backup passage task has been completed: the encryption " "password has not been set - please go to personal information -> file " @@ -645,17 +686,17 @@ msgstr "" "{} - 账号备份任务已完成: 未设置加密密码 - 请前往个人信息 -> 文件加密密码中设" "置加密密码" -#: accounts/notifications.py:33 +#: accounts/notifications.py:53 msgid "Notification of implementation result of encryption change plan" msgstr "改密计划任务结果通知" -#: accounts/notifications.py:43 +#: accounts/notifications.py:63 msgid "" "{} - The encryption change task has been completed. See the attachment for " "details" msgstr "{} - 改密任务已完成, 详情见附件" -#: accounts/notifications.py:46 +#: accounts/notifications.py:66 msgid "" "{} - The encryption change task has been completed: the encryption password " "has not been set - please go to personal information -> file encryption " @@ -684,7 +725,7 @@ msgstr "类别" #: accounts/serializers/account/account.py:191 #: accounts/serializers/automations/base.py:54 acls/models/command_acl.py:24 #: acls/serializers/command_acl.py:19 applications/models.py:14 -#: assets/models/_user.py:50 assets/models/automations/base.py:20 +#: assets/models/_user.py:49 assets/models/automations/base.py:20 #: assets/models/cmd_filter.py:74 assets/models/platform.py:90 #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:113 #: assets/serializers/platform.py:132 audits/serializers.py:50 @@ -693,8 +734,8 @@ msgstr "类别" #: perms/serializers/user_permission.py:26 terminal/models/applet/applet.py:39 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 -#: terminal/serializers/session.py:21 terminal/serializers/storage.py:228 -#: terminal/serializers/storage.py:240 tickets/models/comment.py:26 +#: terminal/serializers/session.py:21 terminal/serializers/storage.py:264 +#: terminal/serializers/storage.py:276 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 #: tickets/serializers/ticket/ticket.py:19 @@ -776,28 +817,28 @@ msgstr "用户" msgid "Date" msgstr "日期" -#: accounts/serializers/account/backup.py:31 +#: accounts/serializers/account/backup.py:38 #: accounts/serializers/automations/base.py:36 #: assets/serializers/automations/base.py:34 ops/mixin.py:23 ops/mixin.py:104 #: settings/serializers/auth/ldap.py:66 msgid "Periodic perform" msgstr "定时执行" -#: accounts/serializers/account/backup.py:32 +#: accounts/serializers/account/backup.py:39 #: accounts/serializers/automations/base.py:37 msgid "Executed amount" msgstr "执行次数" -#: accounts/serializers/account/backup.py:35 +#: accounts/serializers/account/backup.py:42 #: accounts/serializers/automations/change_secret.py:57 msgid "Currently only mail sending is supported" msgstr "当前只支持邮件发送" -#: accounts/serializers/account/backup.py:37 +#: accounts/serializers/account/backup.py:44 msgid "Asset type" msgstr "资产类型" -#: accounts/serializers/account/base.py:24 +#: accounts/serializers/account/base.py:24 terminal/serializers/storage.py:149 msgid "Key password" msgstr "密钥密码" @@ -848,7 +889,7 @@ msgid "" "default parameters will be used" msgstr "关联平台,可配置推送参数,如果不关联,将使用默认参数" -#: accounts/serializers/account/virtual.py:19 assets/models/_user.py:27 +#: accounts/serializers/account/virtual.py:19 assets/models/_user.py:26 #: 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 #: ops/models/job.py:145 ops/models/playbook.py:31 rbac/models/role.py:37 @@ -909,7 +950,7 @@ msgstr "自动化任务执行历史" #: accounts/serializers/automations/change_secret.py:149 audits/const.py:61 #: audits/models.py:63 audits/signal_handlers/activity_log.py:33 #: common/const/choices.py:18 ops/const.py:72 ops/serializers/celery.py:40 -#: terminal/const.py:76 terminal/models/session/sharing.py:121 +#: terminal/const.py:77 terminal/models/session/sharing.py:121 #: tickets/views/approve.py:117 msgid "Success" msgstr "成功" @@ -1012,7 +1053,7 @@ msgstr "告警" msgid "Notifications" msgstr "通知" -#: acls/models/base.py:37 assets/models/_user.py:51 +#: acls/models/base.py:37 assets/models/_user.py:50 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:97 #: xpack/plugins/cloud/models.py:275 msgid "Priority" @@ -1048,7 +1089,7 @@ msgid "Accounts" msgstr "账号管理" #: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60 -#: ops/serializers/job.py:55 terminal/const.py:84 +#: ops/serializers/job.py:55 terminal/const.py:85 #: terminal/models/session/session.py:42 terminal/serializers/command.py:18 #: terminal/templates/terminal/_msg_command_alert.html:12 #: terminal/templates/terminal/_msg_command_execute_alert.html:10 @@ -1298,7 +1339,7 @@ msgid "Authentication failed" msgstr "认证失败" #: assets/automations/ping_gateway/manager.py:60 -#: assets/automations/ping_gateway/manager.py:86 terminal/const.py:100 +#: assets/automations/ping_gateway/manager.py:86 terminal/const.py:101 msgid "Connect failed" msgstr "连接失败" @@ -1532,99 +1573,99 @@ msgstr "网站" msgid "This function is not supported temporarily" msgstr "暂时不支持此功能" -#: assets/models/_user.py:25 +#: assets/models/_user.py:24 msgid "SSH private key" msgstr "SSH密钥" -#: assets/models/_user.py:26 +#: assets/models/_user.py:25 msgid "SSH public key" msgstr "SSH公钥" # msgid "Comment" # msgstr "备注" -#: assets/models/_user.py:28 assets/models/automations/base.py:114 +#: assets/models/_user.py:27 assets/models/automations/base.py:114 #: assets/models/cmd_filter.py:41 assets/models/group.py:19 #: audits/models.py:266 common/db/models.py:34 ops/models/base.py:54 #: ops/models/job.py:227 users/models/user.py:1024 msgid "Date created" msgstr "创建日期" -#: assets/models/_user.py:29 assets/models/cmd_filter.py:42 +#: assets/models/_user.py:28 assets/models/cmd_filter.py:42 #: common/db/models.py:35 users/models/user.py:846 msgid "Date updated" msgstr "更新日期" -#: assets/models/_user.py:30 assets/models/cmd_filter.py:44 +#: assets/models/_user.py:29 assets/models/cmd_filter.py:44 #: assets/models/cmd_filter.py:91 assets/models/group.py:18 #: common/db/models.py:32 users/models/user.py:835 #: users/serializers/group.py:29 msgid "Created by" msgstr "创建者" -#: assets/models/_user.py:40 +#: assets/models/_user.py:39 msgid "Automatic managed" msgstr "托管密码" -#: assets/models/_user.py:41 +#: assets/models/_user.py:40 msgid "Manually input" msgstr "手动输入" -#: assets/models/_user.py:45 +#: assets/models/_user.py:44 msgid "Common user" msgstr "普通用户" -#: assets/models/_user.py:46 assets/models/_user.py:95 +#: assets/models/_user.py:45 assets/models/_user.py:98 msgid "Admin user" msgstr "特权用户" -#: assets/models/_user.py:49 +#: assets/models/_user.py:48 msgid "Username same with user" msgstr "用户名与用户相同" -#: assets/models/_user.py:52 authentication/models/connection_token.py:41 +#: assets/models/_user.py:53 authentication/models/connection_token.py:41 #: authentication/serializers/connect_token_secret.py:111 #: terminal/models/applet/applet.py:42 terminal/serializers/session.py:19 -#: terminal/serializers/session.py:45 terminal/serializers/storage.py:70 +#: terminal/serializers/session.py:45 terminal/serializers/storage.py:71 msgid "Protocol" msgstr "协议" -#: assets/models/_user.py:54 +#: assets/models/_user.py:55 msgid "Sudo" msgstr "Sudo" -#: assets/models/_user.py:55 ops/const.py:49 ops/const.py:59 +#: assets/models/_user.py:56 ops/const.py:49 ops/const.py:59 msgid "Shell" msgstr "Shell" -#: assets/models/_user.py:56 +#: assets/models/_user.py:58 msgid "Login mode" msgstr "认证方式" -#: assets/models/_user.py:57 +#: assets/models/_user.py:59 terminal/serializers/storage.py:152 msgid "SFTP Root" msgstr "SFTP根路径" -#: assets/models/_user.py:58 +#: assets/models/_user.py:60 msgid "Home" msgstr "家目录" -#: assets/models/_user.py:59 +#: assets/models/_user.py:61 msgid "System groups" msgstr "用户组" -#: assets/models/_user.py:62 +#: assets/models/_user.py:64 msgid "User switch" msgstr "用户切换" -#: assets/models/_user.py:63 +#: assets/models/_user.py:66 msgid "Switch from" msgstr "切换自" -#: assets/models/_user.py:69 +#: assets/models/_user.py:72 msgid "System user" msgstr "系统用户" -#: assets/models/_user.py:71 +#: assets/models/_user.py:74 msgid "Can match system user" msgstr "可以匹配系统用户" @@ -1634,6 +1675,7 @@ msgstr "云服务" #: assets/models/asset/common.py:92 assets/models/platform.py:16 #: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:72 +#: terminal/serializers/storage.py:133 #: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "端口" @@ -2938,7 +2980,7 @@ msgid "IP group" msgstr "IPグループ" #: authentication/models/connection_token.py:38 -#: terminal/serializers/storage.py:113 +#: terminal/serializers/storage.py:114 msgid "Account name" msgstr "账号名称" @@ -3074,16 +3116,6 @@ msgstr "动作" msgid "Is expired" msgstr "已过期" -#: authentication/serializers/password_mfa.py:16 -#: authentication/serializers/password_mfa.py:24 -#: notifications/backends/__init__.py:10 settings/serializers/msg.py:22 -#: settings/serializers/msg.py:57 users/forms/profile.py:102 -#: users/forms/profile.py:109 users/models/user.py:794 -#: users/templates/users/forgot_password.html:117 -#: users/views/profile/reset.py:92 -msgid "Email" -msgstr "邮箱" - #: authentication/serializers/password_mfa.py:29 #: users/templates/users/forgot_password.html:108 msgid "The {} cannot be empty" @@ -3481,7 +3513,7 @@ msgstr "定时触发" msgid "Ready" msgstr "准备" -#: common/const/choices.py:16 terminal/const.py:75 tickets/const.py:29 +#: common/const/choices.py:16 terminal/const.py:76 tickets/const.py:29 #: tickets/const.py:39 msgid "Pending" msgstr "待定的" @@ -3736,14 +3768,18 @@ msgstr "错误的数据类型,应该是列表" msgid "Invalid choice: {}" msgstr "无效选项: {}" -#: common/tasks.py:20 common/utils/verify_code.py:16 +#: common/tasks.py:21 common/utils/verify_code.py:16 msgid "Send email" msgstr "发件邮件" -#: common/tasks.py:47 +#: common/tasks.py:48 msgid "Send email attachment" msgstr "发送邮件附件" +#: common/tasks.py:69 terminal/tasks.py:62 +msgid "Upload session replay to external storage" +msgstr "上传会话录像到外部存储" + #: common/utils/ip/geoip/utils.py:26 msgid "Invalid ip" msgstr "无效 IP" @@ -6165,64 +6201,60 @@ msgstr "审批 & 接受" msgid "Review & Cancel" msgstr "审批 & 取消" -#: terminal/const.py:44 +#: terminal/const.py:45 msgid "Critical" msgstr "严重" -#: terminal/const.py:45 +#: terminal/const.py:46 msgid "High" msgstr "较高" -#: terminal/const.py:46 terminal/const.py:82 +#: terminal/const.py:47 terminal/const.py:83 #: users/templates/users/reset_password.html:50 msgid "Normal" msgstr "正常" -#: terminal/const.py:47 +#: terminal/const.py:48 msgid "Offline" msgstr "离线" -#: terminal/const.py:78 +#: terminal/const.py:79 msgid "Mismatch" msgstr "未匹配" -#: terminal/const.py:83 +#: terminal/const.py:84 msgid "Tunnel" msgstr "隧道" -#: terminal/const.py:85 -msgid "SFTP" -msgstr "SFTP" - -#: terminal/const.py:89 +#: terminal/const.py:90 msgid "Read only" msgstr "只读" -#: terminal/const.py:90 +#: terminal/const.py:91 msgid "Writable" msgstr "读写" -#: terminal/const.py:94 +#: terminal/const.py:95 msgid "Kill session" msgstr "终断会话" -#: terminal/const.py:95 +#: terminal/const.py:96 msgid "Lock session" msgstr "锁定会话" -#: terminal/const.py:96 +#: terminal/const.py:97 msgid "Unlock session" msgstr "解锁会话" -#: terminal/const.py:101 +#: terminal/const.py:102 msgid "Replay create failed" msgstr "录像创建失败" -#: terminal/const.py:102 +#: terminal/const.py:103 msgid "Replay upload failed" msgstr "录像上传失败" -#: terminal/const.py:103 +#: terminal/const.py:104 msgid "Replay convert failed" msgstr "录像转码失败" @@ -6258,7 +6290,7 @@ msgstr "可以并发" msgid "Tags" msgstr "标签" -#: terminal/models/applet/applet.py:48 terminal/serializers/storage.py:161 +#: terminal/models/applet/applet.py:48 terminal/serializers/storage.py:197 msgid "Hosts" msgstr "主机" @@ -6349,9 +6381,9 @@ msgstr "Redis 端口" #: terminal/models/component/endpoint.py:29 #: terminal/models/component/endpoint.py:102 -#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:40 -#: terminal/serializers/storage.py:52 terminal/serializers/storage.py:82 -#: terminal/serializers/storage.py:92 terminal/serializers/storage.py:100 +#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:41 +#: terminal/serializers/storage.py:53 terminal/serializers/storage.py:83 +#: terminal/serializers/storage.py:93 terminal/serializers/storage.py:101 msgid "Endpoint" msgstr "端点" @@ -6601,7 +6633,7 @@ msgstr "" "建议填写内网地址,否则填写当前站点 URL
例如:https://172.16.10.110 or " "https://dev.jumpserver.com" -#: terminal/serializers/applet_host.py:46 terminal/serializers/storage.py:172 +#: terminal/serializers/applet_host.py:46 terminal/serializers/storage.py:208 msgid "Ignore Certificate Verification" msgstr "忽略证书认证" @@ -6759,69 +6791,78 @@ msgstr "登录来源名称" msgid "Terminal display" msgstr "终端显示" -#: terminal/serializers/storage.py:22 +#: terminal/serializers/storage.py:23 msgid "Endpoint invalid: remove path `{}`" msgstr "端点无效: 移除路径 `{}`" -#: terminal/serializers/storage.py:28 +#: terminal/serializers/storage.py:29 msgid "Bucket" msgstr "桶名称" -#: terminal/serializers/storage.py:32 +#: terminal/serializers/storage.py:33 #: xpack/plugins/cloud/serializers/account_attrs.py:17 msgid "Access key id" msgstr "Access key ID(AK)" -#: terminal/serializers/storage.py:36 +#: terminal/serializers/storage.py:37 #: xpack/plugins/cloud/serializers/account_attrs.py:20 msgid "Access key secret" msgstr "Access key secret(SK)" -#: terminal/serializers/storage.py:67 xpack/plugins/cloud/models.py:250 +#: terminal/serializers/storage.py:68 xpack/plugins/cloud/models.py:250 msgid "Region" msgstr "地域" -#: terminal/serializers/storage.py:111 +#: terminal/serializers/storage.py:112 msgid "Container name" msgstr "容器名称" -#: terminal/serializers/storage.py:114 +#: terminal/serializers/storage.py:115 msgid "Account key" msgstr "账号密钥" -#: terminal/serializers/storage.py:117 +#: terminal/serializers/storage.py:118 msgid "Endpoint suffix" msgstr "端点后缀" -#: terminal/serializers/storage.py:137 +#: terminal/serializers/storage.py:129 +msgid "HOST" +msgstr "" + +#: terminal/serializers/storage.py:146 users/models/user.py:822 +#: xpack/plugins/cloud/serializers/account_attrs.py:206 +msgid "Private key" +msgstr "ssh私钥" + +#: terminal/serializers/storage.py:173 msgid "The address cannot contain the special character `#`" msgstr "地址中不能包含特殊字符 `#`" -#: terminal/serializers/storage.py:139 +#: terminal/serializers/storage.py:175 msgid "The address format is incorrect" msgstr "地址格式不正确" -#: terminal/serializers/storage.py:146 +#: terminal/serializers/storage.py:182 msgid "Host invalid" msgstr "主机无效" -#: terminal/serializers/storage.py:149 +#: terminal/serializers/storage.py:185 msgid "Port invalid" msgstr "端口无效" -#: terminal/serializers/storage.py:164 +#: terminal/serializers/storage.py:200 msgid "Index by date" msgstr "按日期建索引" -#: terminal/serializers/storage.py:165 +#: terminal/serializers/storage.py:201 msgid "Whether to create an index by date" msgstr "是否根据日期动态建立索引" -#: terminal/serializers/storage.py:168 +#: terminal/serializers/storage.py:204 msgid "Index" msgstr "索引" -#: terminal/serializers/storage.py:170 +#: terminal/serializers/storage.py:206 msgid "Doc type" msgstr "文档类型" @@ -6841,10 +6882,6 @@ msgstr "周期清理终端状态" msgid "Clean orphan session" msgstr "清除离线会话" -#: terminal/tasks.py:62 -msgid "Upload session replay to external storage" -msgstr "上传会话录像到外部存储" - #: terminal/tasks.py:91 msgid "Run applet host deployment" msgstr "运行应用机部署" @@ -7393,11 +7430,6 @@ msgstr "手机" msgid "OTP secret key" msgstr "OTP 密钥" -#: users/models/user.py:822 -#: xpack/plugins/cloud/serializers/account_attrs.py:206 -msgid "Private key" -msgstr "ssh私钥" - #: users/models/user.py:830 users/serializers/profile.py:128 #: users/serializers/user.py:166 msgid "Is first login" @@ -8541,3 +8573,6 @@ msgstr "企业专业版" #: xpack/plugins/license/models.py:86 msgid "Ultimate edition" msgstr "企业旗舰版" + +#~ msgid "Object Storage" +#~ msgstr "对象存储" diff --git a/apps/terminal/const.py b/apps/terminal/const.py index 9f0b8a947..a545a0a3a 100644 --- a/apps/terminal/const.py +++ b/apps/terminal/const.py @@ -29,6 +29,7 @@ class ReplayStorageType(TextChoices): azure = 'azure', 'Azure' obs = 'obs', 'OBS' cos = 'cos', 'COS' + sftp = 'sftp', 'SFTP' class CommandStorageType(TextChoices): diff --git a/apps/terminal/migrations/0067_alter_replaystorage_type.py b/apps/terminal/migrations/0067_alter_replaystorage_type.py new file mode 100644 index 000000000..a35343407 --- /dev/null +++ b/apps/terminal/migrations/0067_alter_replaystorage_type.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.10 on 2023-11-02 10:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('terminal', '0066_applethost_using_same_account'), + ] + + operations = [ + migrations.AlterField( + model_name='replaystorage', + name='type', + field=models.CharField(choices=[('null', 'Null'), ('server', 'Server'), ('s3', 'S3'), ('ceph', 'Ceph'), ('swift', 'Swift'), ('oss', 'OSS'), ('azure', 'Azure'), ('obs', 'OBS'), ('cos', 'COS'), ('sftp', 'SFTP')], default='server', max_length=16, verbose_name='Type'), + ), + ] diff --git a/apps/terminal/serializers/storage.py b/apps/terminal/serializers/storage.py index 969b44e3c..caf887f21 100644 --- a/apps/terminal/serializers/storage.py +++ b/apps/terminal/serializers/storage.py @@ -3,6 +3,7 @@ from urllib.parse import urlparse from django.db.models import TextChoices +from django.core.validators import MaxValueValidator, MinValueValidator, validate_ipv46_address from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from rest_framework.validators import UniqueValidator @@ -118,6 +119,40 @@ class ReplayStorageTypeAzureSerializer(serializers.Serializer): ) +class SftpSecretType(TextChoices): + PASSWORD = 'password', _('Password') + SSH_KEY = 'ssh_key', _('SSH key') + + +class ReplayStorageTypeSFTPSerializer(serializers.Serializer): + SFTP_HOST = serializers.CharField( + required=True, max_length=1024, label=_('HOST'), validators=[validate_ipv46_address] + ) + SFTP_PORT = serializers.IntegerField( + required=False, default=22, validators=[MaxValueValidator(65535), MinValueValidator(0)], + label=_('Port') + ) + SFTP_USERNAME = serializers.CharField( + required=True, max_length=1024, label=_('Username') + ) + STP_SECRET_TYPE = serializers.ChoiceField(choices=SftpSecretType.choices, + default=SftpSecretType.PASSWORD, + label=_('Secret type')) + SFTP_PASSWORD = EncryptedField( + allow_blank=True, allow_null=True, required=False, max_length=1024, label=_('Password') + ) + STP_PRIVATE_KEY = serializers.CharField( + allow_blank=True, allow_null=True, required=False, max_length=4096, + write_only=True, label=_('Private key') + ) + STP_PASSPHRASE = EncryptedField( + allow_blank=True, allow_null=True, required=False, max_length=1024, label=_('Key password') + ) + SFTP_ROOT_PATH = serializers.CharField( + required=True, max_length=1024, label=_('SFTP Root') + ) + + # mapping replay_storage_type_serializer_classes_mapping = { const.ReplayStorageType.s3.value: ReplayStorageTypeS3Serializer, @@ -126,7 +161,8 @@ replay_storage_type_serializer_classes_mapping = { const.ReplayStorageType.oss.value: ReplayStorageTypeOSSSerializer, const.ReplayStorageType.azure.value: ReplayStorageTypeAzureSerializer, const.ReplayStorageType.obs.value: ReplayStorageTypeOBSSerializer, - const.ReplayStorageType.cos.value: ReplayStorageTypeCOSSerializer + const.ReplayStorageType.cos.value: ReplayStorageTypeCOSSerializer, + const.ReplayStorageType.sftp.value: ReplayStorageTypeSFTPSerializer }