diff --git a/Dockerfile-ce b/Dockerfile-ce index 915494216..850c56218 100644 --- a/Dockerfile-ce +++ b/Dockerfile-ce @@ -19,11 +19,11 @@ ARG BUILD_DEPENDENCIES=" \ ARG DEPENDENCIES=" \ freetds-dev \ - libpq-dev \ libffi-dev \ libjpeg-dev \ libkrb5-dev \ libldap2-dev \ + libpq-dev \ libsasl2-dev \ libssl-dev \ libxml2-dev \ @@ -75,6 +75,7 @@ ENV LANG=zh_CN.UTF-8 \ ARG DEPENDENCIES=" \ libjpeg-dev \ + libpq-dev \ libx11-dev \ freerdp2-dev \ libxmlsec1-openssl" diff --git a/apps/accounts/api/account/task.py b/apps/accounts/api/account/task.py index c4f6ebd9f..07e6db35a 100644 --- a/apps/accounts/api/account/task.py +++ b/apps/accounts/api/account/task.py @@ -1,11 +1,12 @@ +from django.db.models import Q from rest_framework.generics import CreateAPIView from accounts import serializers +from accounts.models import Account from accounts.permissions import AccountTaskActionPermission from accounts.tasks import ( remove_accounts_task, verify_accounts_connectivity_task, push_accounts_to_assets_task ) -from assets.exceptions import NotSupportedTemporarilyError from authentication.permissions import UserConfirmation, ConfirmType __all__ = [ @@ -26,25 +27,35 @@ class AccountsTaskCreateAPI(CreateAPIView): ] return super().get_permissions() - def perform_create(self, serializer): - data = serializer.validated_data - accounts = data.get('accounts', []) - params = data.get('params') + @staticmethod + def get_account_ids(data, action): + account_type = 'gather_accounts' if action == 'remove' else 'accounts' + accounts = data.get(account_type, []) account_ids = [str(a.id) for a in accounts] - if data['action'] == 'push': - task = push_accounts_to_assets_task.delay(account_ids, params) - elif data['action'] == 'remove': - gather_accounts = data.get('gather_accounts', []) - gather_account_ids = [str(a.id) for a in gather_accounts] - task = remove_accounts_task.delay(gather_account_ids) + if action == 'remove': + return account_ids + + assets = data.get('assets', []) + asset_ids = [str(a.id) for a in assets] + ids = Account.objects.filter( + Q(id__in=account_ids) | Q(asset_id__in=asset_ids) + ).distinct().values_list('id', flat=True) + return [str(_id) for _id in ids] + + def perform_create(self, serializer): + data = serializer.validated_data + action = data['action'] + ids = self.get_account_ids(data, action) + + if action == 'push': + task = push_accounts_to_assets_task.delay(ids, data.get('params')) + elif action == 'remove': + task = remove_accounts_task.delay(ids) + elif action == 'verify': + task = verify_accounts_connectivity_task.delay(ids) else: - account = accounts[0] - asset = account.asset - if not asset.auto_config['ansible_enabled'] or \ - not asset.auto_config['ping_enabled']: - raise NotSupportedTemporarilyError() - task = verify_accounts_connectivity_task.delay(account_ids) + raise ValueError(f"Invalid action: {action}") data = getattr(serializer, '_data', {}) data["task"] = task.id diff --git a/apps/accounts/automations/backup_account/handlers.py b/apps/accounts/automations/backup_account/handlers.py index c47454685..6a00a2436 100644 --- a/apps/accounts/automations/backup_account/handlers.py +++ b/apps/accounts/automations/backup_account/handlers.py @@ -168,9 +168,8 @@ class AccountBackupHandler: if not user.secret_key: attachment_list = [] else: - password = user.secret_key.encode('utf8') attachment = os.path.join(PATH, f'{plan_name}-{local_now_filename()}-{time.time()}.zip') - encrypt_and_compress_zip_file(attachment, password, files) + encrypt_and_compress_zip_file(attachment, user.secret_key, files) attachment_list = [attachment, ] AccountBackupExecutionTaskMsg(plan_name, user).publish(attachment_list) print('邮件已发送至{}({})'.format(user, user.email)) @@ -191,7 +190,6 @@ class AccountBackupHandler: attachment = os.path.join(PATH, f'{plan_name}-{local_now_filename()}-{time.time()}.zip') if password: print('\033[32m>>> 使用加密密码对文件进行加密中\033[0m') - password = password.encode('utf8') encrypt_and_compress_zip_file(attachment, password, files) else: zip_files(attachment, files) diff --git a/apps/accounts/automations/change_secret/custom/ssh/manifest.yml b/apps/accounts/automations/change_secret/custom/ssh/manifest.yml index 7d3d0edde..1b0a38a00 100644 --- a/apps/accounts/automations/change_secret/custom/ssh/manifest.yml +++ b/apps/accounts/automations/change_secret/custom/ssh/manifest.yml @@ -7,6 +7,7 @@ type: - all method: change_secret protocol: ssh +priority: 50 params: - name: commands type: list diff --git a/apps/accounts/automations/change_secret/database/oracle/main.yml b/apps/accounts/automations/change_secret/database/oracle/main.yml index 03eb5d45f..5a94f3184 100644 --- a/apps/accounts/automations/change_secret/database/oracle/main.yml +++ b/apps/accounts/automations/change_secret/database/oracle/main.yml @@ -39,3 +39,4 @@ login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" login_database: "{{ jms_asset.spec_info.db_name }}" + mode: "{{ account.mode }}" diff --git a/apps/accounts/automations/change_secret/host/windows_rdp_verify/manifest.yml b/apps/accounts/automations/change_secret/host/windows_rdp_verify/manifest.yml index 52f0e02df..242261d59 100644 --- a/apps/accounts/automations/change_secret/host/windows_rdp_verify/manifest.yml +++ b/apps/accounts/automations/change_secret/host/windows_rdp_verify/manifest.yml @@ -5,6 +5,7 @@ method: change_secret category: host type: - windows +priority: 49 params: - name: groups type: str diff --git a/apps/accounts/automations/change_secret/manager.py b/apps/accounts/automations/change_secret/manager.py index 8381419ad..e4d1a0fd5 100644 --- a/apps/accounts/automations/change_secret/manager.py +++ b/apps/accounts/automations/change_secret/manager.py @@ -4,6 +4,7 @@ from copy import deepcopy from django.conf import settings from django.utils import timezone +from django.utils.translation import gettext_lazy as _ from xlsxwriter import Workbook from accounts.const import AutomationTypes, SecretType, SSHKeyStrategy, SecretStrategy @@ -118,6 +119,10 @@ class ChangeSecretManager(AccountBasePlaybookManager): else: new_secret = self.get_secret(secret_type) + if new_secret is None: + print(f'new_secret is None, account: {account}') + continue + if self.record_id is None: recorder = ChangeSecretRecord( asset=asset, account=account, execution=self.execution, @@ -183,17 +188,33 @@ class ChangeSecretManager(AccountBasePlaybookManager): return False return True + @staticmethod + def get_summary(recorders): + total, succeed, failed = 0, 0, 0 + for recorder in recorders: + if recorder.status == 'success': + succeed += 1 + else: + failed += 1 + total += 1 + + summary = _('Success: %s, Failed: %s, Total: %s') % (succeed, failed, total) + return summary + def run(self, *args, **kwargs): if self.secret_type and not self.check_secret(): return super().run(*args, **kwargs) + recorders = list(self.name_recorder_mapper.values()) + summary = self.get_summary(recorders) + print(summary, end='') + if self.record_id: return - recorders = self.name_recorder_mapper.values() - recorders = list(recorders) - self.send_recorder_mail(recorders) - def send_recorder_mail(self, recorders): + self.send_recorder_mail(recorders, summary) + + def send_recorder_mail(self, recorders, summary): recipients = self.execution.recipients if not recorders or not recipients: return @@ -209,11 +230,10 @@ class ChangeSecretManager(AccountBasePlaybookManager): for user in recipients: attachments = [] if user.secret_key: - password = user.secret_key.encode('utf8') attachment = os.path.join(path, f'{name}-{local_now_filename()}-{time.time()}.zip') - encrypt_and_compress_zip_file(attachment, password, [filename]) + encrypt_and_compress_zip_file(attachment, user.secret_key, [filename]) attachments = [attachment] - ChangeSecretExecutionTaskMsg(name, user).publish(attachments) + ChangeSecretExecutionTaskMsg(name, user, summary).publish(attachments) os.remove(filename) @staticmethod diff --git a/apps/accounts/automations/gather_accounts/host/windows/main.yml b/apps/accounts/automations/gather_accounts/host/windows/main.yml index d117e6a2e..6f36feb83 100644 --- a/apps/accounts/automations/gather_accounts/host/windows/main.yml +++ b/apps/accounts/automations/gather_accounts/host/windows/main.yml @@ -1,9 +1,10 @@ - hosts: demo gather_facts: no tasks: - - name: Gather posix account + - name: Gather windows account ansible.builtin.win_shell: net user register: result + ignore_errors: true - name: Define info by set_fact ansible.builtin.set_fact: diff --git a/apps/accounts/automations/push_account/database/oracle/main.yml b/apps/accounts/automations/push_account/database/oracle/main.yml index 03eb5d45f..5a94f3184 100644 --- a/apps/accounts/automations/push_account/database/oracle/main.yml +++ b/apps/accounts/automations/push_account/database/oracle/main.yml @@ -39,3 +39,4 @@ login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" login_database: "{{ jms_asset.spec_info.db_name }}" + mode: "{{ account.mode }}" diff --git a/apps/accounts/automations/push_account/host/windows_rdp_verify/manifest.yml b/apps/accounts/automations/push_account/host/windows_rdp_verify/manifest.yml index d08a29ebc..63b4a0f9c 100644 --- a/apps/accounts/automations/push_account/host/windows_rdp_verify/manifest.yml +++ b/apps/accounts/automations/push_account/host/windows_rdp_verify/manifest.yml @@ -5,6 +5,7 @@ method: push_account category: host type: - windows +priority: 49 params: - name: groups type: str diff --git a/apps/accounts/automations/verify_account/custom/rdp/manifest.yml b/apps/accounts/automations/verify_account/custom/rdp/manifest.yml index e4b034366..3cfaf1880 100644 --- a/apps/accounts/automations/verify_account/custom/rdp/manifest.yml +++ b/apps/accounts/automations/verify_account/custom/rdp/manifest.yml @@ -6,6 +6,7 @@ type: - windows method: verify_account protocol: rdp +priority: 1 i18n: Windows rdp account verify: diff --git a/apps/accounts/automations/verify_account/custom/ssh/manifest.yml b/apps/accounts/automations/verify_account/custom/ssh/manifest.yml index bebc02c7f..3edddc531 100644 --- a/apps/accounts/automations/verify_account/custom/ssh/manifest.yml +++ b/apps/accounts/automations/verify_account/custom/ssh/manifest.yml @@ -7,6 +7,7 @@ type: - all method: verify_account protocol: ssh +priority: 50 i18n: SSH account verify: diff --git a/apps/accounts/automations/verify_account/manager.py b/apps/accounts/automations/verify_account/manager.py index 794cf4ff6..94be53b89 100644 --- a/apps/accounts/automations/verify_account/manager.py +++ b/apps/accounts/automations/verify_account/manager.py @@ -51,6 +51,9 @@ class VerifyAccountManager(AccountBasePlaybookManager): h['name'] += '(' + account.username + ')' self.host_account_mapper[h['name']] = account secret = account.secret + if secret is None: + print(f'account {account.name} secret is None') + continue private_key_path = None if account.secret_type == SecretType.SSH_KEY: @@ -62,7 +65,7 @@ class VerifyAccountManager(AccountBasePlaybookManager): 'name': account.name, 'username': account.username, 'secret_type': account.secret_type, - 'secret': account.escape_jinja2_syntax(secret), + 'secret': account.escape_jinja2_syntax(secret), 'private_key_path': private_key_path, 'become': account.get_ansible_become_auth(), } diff --git a/apps/accounts/filters.py b/apps/accounts/filters.py index 5e4e0c257..b26e9d391 100644 --- a/apps/accounts/filters.py +++ b/apps/accounts/filters.py @@ -52,6 +52,7 @@ class AccountFilterSet(BaseFilterSet): class GatheredAccountFilterSet(BaseFilterSet): node_id = drf_filters.CharFilter(method='filter_nodes') asset_id = drf_filters.CharFilter(field_name='asset_id', lookup_expr='exact') + asset_name = drf_filters.CharFilter(field_name='asset__name', lookup_expr='icontains') @staticmethod def filter_nodes(queryset, name, value): diff --git a/apps/accounts/notifications.py b/apps/accounts/notifications.py index 404125fd3..0082f8b80 100644 --- a/apps/accounts/notifications.py +++ b/apps/accounts/notifications.py @@ -54,20 +54,23 @@ class AccountBackupByObjStorageExecutionTaskMsg(object): class ChangeSecretExecutionTaskMsg(object): subject = _('Notification of implementation result of encryption change plan') - def __init__(self, name: str, user: User): + def __init__(self, name: str, user: User, summary): self.name = name self.user = user + self.summary = summary @property def message(self): name = self.name if self.user.secret_key: - return _('{} - The encryption change task has been completed. ' - 'See the attachment for details').format(name) + default_message = _('{} - The encryption change task has been completed. ' + 'See the attachment for details').format(name) + else: - return _("{} - The encryption change task has been completed: the encryption " - "password has not been set - please go to personal information -> " - "file encryption password to set the encryption password").format(name) + default_message = _("{} - The encryption change task has been completed: the encryption " + "password has not been set - please go to personal information -> " + "set encryption password in preferences").format(name) + return self.summary + '\n' + default_message def publish(self, attachments=None): send_mail_attachment_async( diff --git a/apps/accounts/serializers/account/account.py b/apps/accounts/serializers/account/account.py index 197c64c7d..2230c8e92 100644 --- a/apps/accounts/serializers/account/account.py +++ b/apps/accounts/serializers/account/account.py @@ -58,7 +58,7 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer): for data in initial_data: if not data.get('asset') and not self.instance: raise serializers.ValidationError({'asset': UniqueTogetherValidator.missing_message}) - asset = data.get('asset') or self.instance.asset + asset = data.get('asset') or getattr(self.instance, 'asset', None) self.from_template_if_need(data) self.set_uniq_name_if_need(data, asset) @@ -455,12 +455,14 @@ class AccountHistorySerializer(serializers.ModelSerializer): class AccountTaskSerializer(serializers.Serializer): ACTION_CHOICES = ( - ('test', 'test'), ('verify', 'verify'), ('push', 'push'), ('remove', 'remove'), ) action = serializers.ChoiceField(choices=ACTION_CHOICES, write_only=True) + assets = serializers.PrimaryKeyRelatedField( + queryset=Asset.objects, required=False, allow_empty=True, many=True + ) accounts = serializers.PrimaryKeyRelatedField( queryset=Account.objects, required=False, allow_empty=True, many=True ) diff --git a/apps/accounts/signal_handlers.py b/apps/accounts/signal_handlers.py index 4c87df5cf..3ae1fba5c 100644 --- a/apps/accounts/signal_handlers.py +++ b/apps/accounts/signal_handlers.py @@ -63,7 +63,7 @@ def create_accounts_activities(account, action='create'): def on_account_create_by_template(sender, instance, created=False, **kwargs): if not created or instance.source != 'template': return - push_accounts_if_need(accounts=(instance,)) + push_accounts_if_need.delay(accounts=(instance,)) create_accounts_activities(instance, action='create') diff --git a/apps/acls/notifications.py b/apps/acls/notifications.py index dc4db25ac..b0e413590 100644 --- a/apps/acls/notifications.py +++ b/apps/acls/notifications.py @@ -41,21 +41,21 @@ class UserLoginReminderMsg(UserMessage): class AssetLoginReminderMsg(UserMessage): subject = _('Asset login reminder') - def __init__(self, user, asset: Asset, login_user: User, account_username): + def __init__(self, user, asset: Asset, login_user: User, account: Account, input_username): self.asset = asset self.login_user = login_user - self.account_username = account_username + self.account = account + self.input_username = input_username super().__init__(user) def get_html_msg(self) -> dict: - account = Account.objects.get(asset=self.asset, username=self.account_username) context = { 'recipient': self.user, 'username': self.login_user.username, 'name': self.login_user.name, 'asset': str(self.asset), - 'account': self.account_username, - 'account_name': account.name, + 'account': self.input_username, + 'account_name': self.account.name, } message = render_to_string('acls/asset_login_reminder.html', context) diff --git a/apps/assets/api/asset/asset.py b/apps/assets/api/asset/asset.py index b6e532b36..0f66d4b9a 100644 --- a/apps/assets/api/asset/asset.py +++ b/apps/assets/api/asset/asset.py @@ -92,6 +92,7 @@ class AssetViewSet(SuggestionMixin, OrgBulkModelViewSet): model = Asset filterset_class = AssetFilterSet search_fields = ("name", "address", "comment") + ordering = ('name',) ordering_fields = ('name', 'address', 'connectivity', 'platform', 'date_updated', 'date_created') serializer_classes = ( ("default", serializers.AssetSerializer), diff --git a/apps/assets/api/asset/permission.py b/apps/assets/api/asset/permission.py index 5981d1105..2461f9a5f 100644 --- a/apps/assets/api/asset/permission.py +++ b/apps/assets/api/asset/permission.py @@ -48,7 +48,7 @@ class AssetPermUserListApi(BaseAssetPermUserOrUserGroupListApi): def get_queryset(self): perms = self.get_asset_related_perms() - users = User.objects.filter( + users = User.get_queryset().filter( Q(assetpermissions__in=perms) | Q(groups__assetpermissions__in=perms) ).distinct() return users diff --git a/apps/assets/automations/__init__.py b/apps/assets/automations/__init__.py index 30fb03cda..f508f7ba2 100644 --- a/apps/assets/automations/__init__.py +++ b/apps/assets/automations/__init__.py @@ -1,2 +1,2 @@ from .endpoint import ExecutionManager -from .methods import platform_automation_methods, filter_platform_methods +from .methods import platform_automation_methods, filter_platform_methods, sorted_methods diff --git a/apps/assets/automations/methods.py b/apps/assets/automations/methods.py index 1453cc7a1..c922a6d62 100644 --- a/apps/assets/automations/methods.py +++ b/apps/assets/automations/methods.py @@ -68,6 +68,10 @@ def filter_platform_methods(category, tp_name, method=None, methods=None): return methods +def sorted_methods(methods): + return sorted(methods, key=lambda x: x.get('priority', 10)) + + BASE_DIR = os.path.dirname(os.path.abspath(__file__)) platform_automation_methods = get_platform_automation_methods(BASE_DIR) diff --git a/apps/assets/automations/ping/custom/rdp/manifest.yml b/apps/assets/automations/ping/custom/rdp/manifest.yml index b8346c3f2..ad499b90e 100644 --- a/apps/assets/automations/ping/custom/rdp/manifest.yml +++ b/apps/assets/automations/ping/custom/rdp/manifest.yml @@ -7,6 +7,7 @@ type: - windows method: ping protocol: rdp +priority: 1 i18n: Ping by pyfreerdp: diff --git a/apps/assets/automations/ping/custom/ssh/manifest.yml b/apps/assets/automations/ping/custom/ssh/manifest.yml index 7a7068108..c6d08ca12 100644 --- a/apps/assets/automations/ping/custom/ssh/manifest.yml +++ b/apps/assets/automations/ping/custom/ssh/manifest.yml @@ -7,6 +7,7 @@ type: - all method: ping protocol: ssh +priority: 50 i18n: Ping by paramiko: diff --git a/apps/assets/const/types.py b/apps/assets/const/types.py index 220d10731..53f41c218 100644 --- a/apps/assets/const/types.py +++ b/apps/assets/const/types.py @@ -90,7 +90,7 @@ class AllTypes(ChoicesMixin): @classmethod def set_automation_methods(cls, category, tp_name, constraints): - from assets.automations import filter_platform_methods + from assets.automations import filter_platform_methods, sorted_methods automation = constraints.get('automation', {}) automation_methods = {} platform_automation_methods = cls.get_automation_methods() @@ -101,6 +101,7 @@ class AllTypes(ChoicesMixin): methods = filter_platform_methods( category, tp_name, item_name, methods=platform_automation_methods ) + methods = sorted_methods(methods) methods = [{'name': m['name'], 'id': m['id']} for m in methods] automation_methods[item_name + '_methods'] = methods automation.update(automation_methods) diff --git a/apps/assets/migrations/0109_alter_asset_options.py b/apps/assets/migrations/0109_alter_asset_options.py index 4a1c93a15..9140eff74 100644 --- a/apps/assets/migrations/0109_alter_asset_options.py +++ b/apps/assets/migrations/0109_alter_asset_options.py @@ -12,6 +12,6 @@ class Migration(migrations.Migration): operations = [ migrations.AlterModelOptions( name='asset', - options={'ordering': ['name'], 'permissions': [('refresh_assethardwareinfo', 'Can refresh asset hardware info'), ('test_assetconnectivity', 'Can test asset connectivity'), ('match_asset', 'Can match asset'), ('change_assetnodes', 'Can change asset nodes')], 'verbose_name': 'Asset'}, + options={'ordering': [], 'permissions': [('refresh_assethardwareinfo', 'Can refresh asset hardware info'), ('test_assetconnectivity', 'Can test asset connectivity'), ('match_asset', 'Can match asset'), ('change_assetnodes', 'Can change asset nodes')], 'verbose_name': 'Asset'}, ), ] diff --git a/apps/assets/models/asset/common.py b/apps/assets/models/asset/common.py index 558164df6..7d3fb5fd2 100644 --- a/apps/assets/models/asset/common.py +++ b/apps/assets/models/asset/common.py @@ -348,7 +348,7 @@ class Asset(NodesRelationMixin, LabeledMixin, AbsConnectivity, JSONFilterMixin, class Meta: unique_together = [('org_id', 'name')] verbose_name = _("Asset") - ordering = ["name", ] + ordering = [] permissions = [ ('refresh_assethardwareinfo', _('Can refresh asset hardware info')), ('test_assetconnectivity', _('Can test asset connectivity')), diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index 7a15b9349..5d9ec5c1c 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -429,7 +429,7 @@ class NodeAssetsMixin(NodeAllAssetsMappingMixin): @classmethod @timeit - def get_nodes_all_assets(cls, *nodes): + def get_nodes_all_assets(cls, *nodes, distinct=True): from .asset import Asset node_ids = set() descendant_node_query = Q() @@ -439,7 +439,10 @@ class NodeAssetsMixin(NodeAllAssetsMappingMixin): if descendant_node_query: _ids = Node.objects.order_by().filter(descendant_node_query).values_list('id', flat=True) node_ids.update(_ids) - return Asset.objects.order_by().filter(nodes__id__in=node_ids).distinct() + assets = Asset.objects.order_by().filter(nodes__id__in=node_ids) + if distinct: + assets = assets.distinct() + return assets def get_all_asset_ids(self): asset_ids = self.get_all_asset_ids_by_node_key(org_id=self.org_id, node_key=self.key) diff --git a/apps/assets/signal_handlers/asset.py b/apps/assets/signal_handlers/asset.py index 5ab4a4117..7ced509d6 100644 --- a/apps/assets/signal_handlers/asset.py +++ b/apps/assets/signal_handlers/asset.py @@ -63,13 +63,13 @@ def on_asset_create(sender, instance=None, created=False, **kwargs): return logger.info("Asset create signal recv: {}".format(instance)) - ensure_asset_has_node(assets=(instance,)) + ensure_asset_has_node.delay(assets=(instance,)) # 获取资产硬件信息 auto_config = instance.auto_config if auto_config.get('ping_enabled'): logger.debug('Asset {} ping enabled, test connectivity'.format(instance.name)) - test_assets_connectivity_handler(assets=(instance,)) + test_assets_connectivity_handler.delay(assets=(instance,)) if auto_config.get('gather_facts_enabled'): logger.debug('Asset {} gather facts enabled, gather facts'.format(instance.name)) gather_assets_facts_handler(assets=(instance,)) diff --git a/apps/assets/signal_handlers/node_assets_amount.py b/apps/assets/signal_handlers/node_assets_amount.py index ea2b3ba8a..5c4633dbd 100644 --- a/apps/assets/signal_handlers/node_assets_amount.py +++ b/apps/assets/signal_handlers/node_assets_amount.py @@ -2,14 +2,16 @@ # from operator import add, sub +from django.conf import settings from django.db.models.signals import m2m_changed from django.dispatch import receiver from assets.models import Asset, Node from common.const.signals import PRE_CLEAR, POST_ADD, PRE_REMOVE from common.decorators import on_transaction_commit, merge_delay_run +from common.signals import django_ready from common.utils import get_logger -from orgs.utils import tmp_to_org +from orgs.utils import tmp_to_org, tmp_to_root_org from ..tasks import check_node_assets_amount_task logger = get_logger(__file__) @@ -34,7 +36,7 @@ def on_node_asset_change(sender, action, instance, reverse, pk_set, **kwargs): node_ids = [instance.id] else: node_ids = list(pk_set) - update_nodes_assets_amount(node_ids=node_ids) + update_nodes_assets_amount.delay(node_ids=node_ids) @merge_delay_run(ttl=30) @@ -52,3 +54,18 @@ def update_nodes_assets_amount(node_ids=()): node.assets_amount = node.get_assets_amount() Node.objects.bulk_update(nodes, ['assets_amount']) + + +@receiver(django_ready) +def set_assets_size_to_setting(sender, **kwargs): + from assets.models import Asset + try: + with tmp_to_root_org(): + amount = Asset.objects.order_by().count() + except: + amount = 0 + + if amount > 20000: + settings.ASSET_SIZE = 'large' + elif amount > 2000: + settings.ASSET_SIZE = 'medium' diff --git a/apps/assets/signal_handlers/node_assets_mapping.py b/apps/assets/signal_handlers/node_assets_mapping.py index a53e534b6..1177f02d6 100644 --- a/apps/assets/signal_handlers/node_assets_mapping.py +++ b/apps/assets/signal_handlers/node_assets_mapping.py @@ -44,18 +44,18 @@ def on_node_post_create(sender, instance, created, update_fields, **kwargs): need_expire = False if need_expire: - expire_node_assets_mapping(org_ids=(instance.org_id,)) + expire_node_assets_mapping.delay(org_ids=(instance.org_id,)) @receiver(post_delete, sender=Node) def on_node_post_delete(sender, instance, **kwargs): - expire_node_assets_mapping(org_ids=(instance.org_id,)) + expire_node_assets_mapping.delay(org_ids=(instance.org_id,)) @receiver(m2m_changed, sender=Asset.nodes.through) def on_node_asset_change(sender, instance, action='pre_remove', **kwargs): if action.startswith('post'): - expire_node_assets_mapping(org_ids=(instance.org_id,)) + expire_node_assets_mapping.delay(org_ids=(instance.org_id,)) @receiver(django_ready) diff --git a/apps/audits/api.py b/apps/audits/api.py index 209bc30fd..8bdc7e070 100644 --- a/apps/audits/api.py +++ b/apps/audits/api.py @@ -20,6 +20,7 @@ from common.const.http import GET, POST from common.drf.filters import DatetimeRangeFilterBackend from common.permissions import IsServiceAccount from common.plugins.es import QuerySet as ESQuerySet +from common.sessions.cache import user_session_manager from common.storage.ftp_file import FTPFileStorageHandler from common.utils import is_uuid, get_logger, lazyproperty from orgs.mixins.api import OrgReadonlyModelViewSet, OrgModelViewSet @@ -30,7 +31,7 @@ from terminal.models import default_storage from users.models import User from .backends import TYPE_ENGINE_MAPPING from .const import ActivityChoices -from .filters import UserSessionFilterSet +from .filters import UserSessionFilterSet, OperateLogFilterSet from .models import ( FTPLog, UserLoginLog, OperateLog, PasswordChangeLog, ActivityLog, JobLog, UserSession @@ -204,10 +205,7 @@ class OperateLogViewSet(OrgReadonlyModelViewSet): date_range_filter_fields = [ ('datetime', ('date_from', 'date_to')) ] - filterset_fields = [ - 'user', 'action', 'resource_type', 'resource', - 'remote_addr' - ] + filterset_class = OperateLogFilterSet search_fields = ['resource', 'user'] ordering = ['-datetime'] @@ -289,8 +287,7 @@ class UserSessionViewSet(CommonApiMixin, viewsets.ModelViewSet): return Response(status=status.HTTP_200_OK) keys = queryset.values_list('key', flat=True) - session_store_cls = import_module(settings.SESSION_ENGINE).SessionStore for key in keys: - session_store_cls(key).delete() + user_session_manager.decrement_or_remove(key) queryset.delete() return Response(status=status.HTTP_200_OK) diff --git a/apps/audits/filters.py b/apps/audits/filters.py index d24cf72fd..b82eadad3 100644 --- a/apps/audits/filters.py +++ b/apps/audits/filters.py @@ -1,12 +1,13 @@ -from django.core.cache import cache +from django.apps import apps +from django.utils import translation + from django_filters import rest_framework as drf_filters from rest_framework import filters from rest_framework.compat import coreapi, coreschema - from common.drf.filters import BaseFilterSet -from notifications.ws import WS_SESSION_KEY +from common.sessions.cache import user_session_manager from orgs.utils import current_org -from .models import UserSession +from .models import UserSession, OperateLog __all__ = ['CurrentOrgMembersFilter'] @@ -41,15 +42,32 @@ class UserSessionFilterSet(BaseFilterSet): @staticmethod def filter_is_active(queryset, name, is_active): - redis_client = cache.client.get_client() - members = redis_client.smembers(WS_SESSION_KEY) - members = [member.decode('utf-8') for member in members] + keys = user_session_manager.get_active_keys() if is_active: - queryset = queryset.filter(key__in=members) + queryset = queryset.filter(key__in=keys) else: - queryset = queryset.exclude(key__in=members) + queryset = queryset.exclude(key__in=keys) return queryset class Meta: model = UserSession fields = ['id', 'ip', 'city', 'type'] + + +class OperateLogFilterSet(BaseFilterSet): + resource_type = drf_filters.CharFilter(method='filter_resource_type') + + @staticmethod + def filter_resource_type(queryset, name, resource_type): + current_lang = translation.get_language() + with translation.override(current_lang): + mapper = {str(m._meta.verbose_name): m._meta.verbose_name_raw for m in apps.get_models()} + tp = mapper.get(resource_type) + queryset = queryset.filter(resource_type=tp) + return queryset + + class Meta: + model = OperateLog + fields = [ + 'user', 'action', 'resource', 'remote_addr' + ] diff --git a/apps/audits/models.py b/apps/audits/models.py index 64a0ebc5b..c4b4486a5 100644 --- a/apps/audits/models.py +++ b/apps/audits/models.py @@ -4,15 +4,15 @@ from datetime import timedelta from importlib import import_module from django.conf import settings -from django.core.cache import caches, cache +from django.core.cache import caches from django.db import models from django.db.models import Q from django.utils import timezone from django.utils.translation import gettext, gettext_lazy as _ from common.db.encoder import ModelJSONFieldEncoder +from common.sessions.cache import user_session_manager from common.utils import lazyproperty, i18n_trans -from notifications.ws import WS_SESSION_KEY from ops.models import JobExecution from orgs.mixins.models import OrgModelMixin, Organization from orgs.utils import current_org @@ -278,8 +278,7 @@ class UserSession(models.Model): @property def is_active(self): - redis_client = cache.client.get_client() - return redis_client.sismember(WS_SESSION_KEY, self.key) + return user_session_manager.check_active(self.key) @property def date_expired(self): diff --git a/apps/audits/serializers.py b/apps/audits/serializers.py index 78c42fdd0..cda203537 100644 --- a/apps/audits/serializers.py +++ b/apps/audits/serializers.py @@ -23,7 +23,7 @@ class JobLogSerializer(JobExecutionSerializer): class Meta: model = models.JobLog read_only_fields = [ - "id", "material", "time_cost", 'date_start', + "id", "material", 'job_type', "time_cost", 'date_start', 'date_finished', 'date_created', 'is_finished', 'is_success', 'task_id', 'creator_name' diff --git a/apps/audits/tasks.py b/apps/audits/tasks.py index 65243a966..a22eaeb33 100644 --- a/apps/audits/tasks.py +++ b/apps/audits/tasks.py @@ -19,7 +19,7 @@ from ops.celery.decorator import ( from ops.models import CeleryTaskExecution from terminal.models import Session, Command from terminal.backends import server_replay_storage -from .models import UserLoginLog, OperateLog, FTPLog, ActivityLog +from .models import UserLoginLog, OperateLog, FTPLog, ActivityLog, PasswordChangeLog logger = get_logger(__name__) @@ -38,6 +38,14 @@ def clean_operation_log_period(): OperateLog.objects.filter(datetime__lt=expired_day).delete() +def clean_password_change_log_period(): + now = timezone.now() + days = get_log_keep_day('PASSWORD_CHANGE_LOG_KEEP_DAYS') + expired_day = now - datetime.timedelta(days=days) + PasswordChangeLog.objects.filter(datetime__lt=expired_day).delete() + logger.info("Clean password change log done") + + def clean_activity_log_period(): now = timezone.now() days = get_log_keep_day('ACTIVITY_LOG_KEEP_DAYS') @@ -109,6 +117,7 @@ def clean_audits_log_period(): clean_activity_log_period() clean_celery_tasks_period() clean_expired_session_period() + clean_password_change_log_period() @shared_task(verbose_name=_('Upload FTP file to external storage')) diff --git a/apps/authentication/api/connection_token.py b/apps/authentication/api/connection_token.py index 076767946..f76b6e037 100644 --- a/apps/authentication/api/connection_token.py +++ b/apps/authentication/api/connection_token.py @@ -205,7 +205,7 @@ class RDPFileClientProtocolURLMixin: return data def get_smart_endpoint(self, protocol, asset=None): - endpoint = Endpoint.match_by_instance_label(asset, protocol) + endpoint = Endpoint.match_by_instance_label(asset, protocol, self.request) if not endpoint: target_ip = asset.get_target_ip() if asset else '' endpoint = EndpointRule.match_endpoint( @@ -443,7 +443,7 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView self._record_operate_log(acl, asset) for reviewer in reviewers: AssetLoginReminderMsg( - reviewer, asset, user, self.input_username + reviewer, asset, user, account, self.input_username ).publish_async() def create(self, request, *args, **kwargs): diff --git a/apps/authentication/backends/drf.py b/apps/authentication/backends/drf.py index 86999037d..4cf2577c1 100644 --- a/apps/authentication/backends/drf.py +++ b/apps/authentication/backends/drf.py @@ -10,6 +10,7 @@ from rest_framework import authentication, exceptions from common.auth import signature from common.decorators import merge_delay_run from common.utils import get_object_or_none, get_request_ip_or_data, contains_ip +from users.models import User from ..models import AccessKey, PrivateToken @@ -19,22 +20,23 @@ def date_more_than(d, seconds): @merge_delay_run(ttl=60) def update_token_last_used(tokens=()): - for token in tokens: - token.date_last_used = timezone.now() - token.save(update_fields=['date_last_used']) + access_keys_ids = [token.id for token in tokens if isinstance(token, AccessKey)] + private_token_keys = [token.key for token in tokens if isinstance(token, PrivateToken)] + if len(access_keys_ids) > 0: + AccessKey.objects.filter(id__in=access_keys_ids).update(date_last_used=timezone.now()) + if len(private_token_keys) > 0: + PrivateToken.objects.filter(key__in=private_token_keys).update(date_last_used=timezone.now()) @merge_delay_run(ttl=60) def update_user_last_used(users=()): - for user in users: - user.date_api_key_last_used = timezone.now() - user.save(update_fields=['date_api_key_last_used']) + User.objects.filter(id__in=users).update(date_api_key_last_used=timezone.now()) def after_authenticate_update_date(user, token=None): - update_user_last_used(users=(user,)) + update_user_last_used.delay(users=(user.id,)) if token: - update_token_last_used(tokens=(token,)) + update_token_last_used.delay(tokens=(token,)) class AccessTokenAuthentication(authentication.BaseAuthentication): diff --git a/apps/authentication/backends/oauth2/backends.py b/apps/authentication/backends/oauth2/backends.py index 0c40d09bd..16a617b16 100644 --- a/apps/authentication/backends/oauth2/backends.py +++ b/apps/authentication/backends/oauth2/backends.py @@ -98,16 +98,19 @@ class OAuth2Backend(JMSModelBackend): access_token_url = '{url}{separator}{query}'.format( url=settings.AUTH_OAUTH2_ACCESS_TOKEN_ENDPOINT, separator=separator, query=urlencode(query_dict) ) + # token_method -> get, post(post_data), post_json token_method = settings.AUTH_OAUTH2_ACCESS_TOKEN_METHOD.lower() - requests_func = getattr(requests, token_method, requests.get) logger.debug(log_prompt.format('Call the access token endpoint[method: %s]' % token_method)) headers = { 'Accept': 'application/json' } - if token_method == 'post': - access_token_response = requests_func(access_token_url, headers=headers, data=query_dict) + if token_method.startswith('post'): + body_key = 'json' if token_method.endswith('json') else 'data' + access_token_response = requests.post( + access_token_url, headers=headers, **{body_key: query_dict} + ) else: - access_token_response = requests_func(access_token_url, headers=headers) + access_token_response = requests.get(access_token_url, headers=headers) try: access_token_response.raise_for_status() access_token_response_data = access_token_response.json() diff --git a/apps/authentication/forms.py b/apps/authentication/forms.py index 90429bc82..5f56a4a98 100644 --- a/apps/authentication/forms.py +++ b/apps/authentication/forms.py @@ -18,7 +18,7 @@ class EncryptedField(forms.CharField): class UserLoginForm(forms.Form): days_auto_login = int(settings.SESSION_COOKIE_AGE / 3600 / 24) - disable_days_auto_login = settings.SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE \ + disable_days_auto_login = settings.SESSION_EXPIRE_AT_BROWSER_CLOSE \ or days_auto_login < 1 username = forms.CharField( diff --git a/apps/authentication/middleware.py b/apps/authentication/middleware.py index eabb90263..e6182e9bb 100644 --- a/apps/authentication/middleware.py +++ b/apps/authentication/middleware.py @@ -142,23 +142,7 @@ class SessionCookieMiddleware(MiddlewareMixin): return response response.set_cookie(key, value) - @staticmethod - def set_cookie_session_expire(request, response): - if not request.session.get('auth_session_expiration_required'): - return - value = 'age' - if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE or \ - not request.session.get('auto_login', False): - value = 'close' - - age = request.session.get_expiry_age() - expire_timestamp = request.session.get_expiry_date().timestamp() - response.set_cookie('jms_session_expire_timestamp', expire_timestamp) - response.set_cookie('jms_session_expire', value, max_age=age) - request.session.pop('auth_session_expiration_required', None) - def process_response(self, request, response: HttpResponse): self.set_cookie_session_prefix(request, response) self.set_cookie_public_key(request, response) - self.set_cookie_session_expire(request, response) return response diff --git a/apps/authentication/signal_handlers.py b/apps/authentication/signal_handlers.py index 3ac92411f..943d751dd 100644 --- a/apps/authentication/signal_handlers.py +++ b/apps/authentication/signal_handlers.py @@ -37,9 +37,6 @@ def on_user_auth_login_success(sender, user, request, **kwargs): UserSession.objects.filter(key=session_key).delete() cache.set(lock_key, request.session.session_key, None) - # 标记登录,设置 cookie,前端可以控制刷新, Middleware 会拦截这个生成 cookie - request.session['auth_session_expiration_required'] = 1 - @receiver(cas_user_authenticated) def on_cas_user_login_success(sender, request, user, **kwargs): diff --git a/apps/authentication/templates/authentication/login.html b/apps/authentication/templates/authentication/login.html index 4d7489034..ed70b30f7 100644 --- a/apps/authentication/templates/authentication/login.html +++ b/apps/authentication/templates/authentication/login.html @@ -407,6 +407,15 @@ $('#password-hidden').val(passwordEncrypted); //返回给密码输入input $('#login-form').submit(); //post提交 } + function checkHealth() { + let url = "{% url 'health' %}"; + requestApi({ + url: url, + method: "GET", + flash_message: false, + }) + } + setInterval(checkHealth, 30 * 1000); diff --git a/apps/authentication/views/dingtalk.py b/apps/authentication/views/dingtalk.py index 9b7f81e25..8e76795cb 100644 --- a/apps/authentication/views/dingtalk.py +++ b/apps/authentication/views/dingtalk.py @@ -70,11 +70,12 @@ class DingTalkQRMixin(DingTalkBaseMixin, View): self.request.session[DINGTALK_STATE_SESSION_KEY] = state params = { - 'appid': settings.DINGTALK_APPKEY, + 'client_id': settings.DINGTALK_APPKEY, 'response_type': 'code', - 'scope': 'snsapi_login', + 'scope': 'openid', 'state': state, 'redirect_uri': redirect_uri, + 'prompt': 'consent' } url = URL.QR_CONNECT + '?' + urlencode(params) return url diff --git a/apps/common/const/choices.py b/apps/common/const/choices.py index 6db9254b3..ee8519c34 100644 --- a/apps/common/const/choices.py +++ b/apps/common/const/choices.py @@ -19,3 +19,17 @@ class Status(models.TextChoices): failed = 'failed', _("Failed") error = 'error', _("Error") canceled = 'canceled', _("Canceled") + + +COUNTRY_CALLING_CODES = [ + {'name': 'China(中国)', 'value': '+86'}, + {'name': 'HongKong(中国香港)', 'value': '+852'}, + {'name': 'Macao(中国澳门)', 'value': '+853'}, + {'name': 'Taiwan(中国台湾)', 'value': '+886'}, + {'name': 'America(America)', 'value': '+1'}, {'name': 'Russia(Россия)', 'value': '+7'}, + {'name': 'France(français)', 'value': '+33'}, + {'name': 'Britain(Britain)', 'value': '+44'}, + {'name': 'Germany(Deutschland)', 'value': '+49'}, + {'name': 'Japan(日本)', 'value': '+81'}, {'name': 'Korea(한국)', 'value': '+82'}, + {'name': 'India(भारत)', 'value': '+91'} +] diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 1691fad1d..0a620e1f0 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -362,11 +362,15 @@ class RelatedManager: if name is None or val is None: continue - if custom_attr_filter: + custom_filter_q = None + spec_attr_filter = getattr(to_model, "get_{}_filter_attr_q".format(name), None) + if spec_attr_filter: + custom_filter_q = spec_attr_filter(val, match) + elif custom_attr_filter: custom_filter_q = custom_attr_filter(name, val, match) - if custom_filter_q: - filters.append(custom_filter_q) - continue + if custom_filter_q: + filters.append(custom_filter_q) + continue if match == 'ip_in': q = cls.get_ip_in_q(name, val) @@ -464,11 +468,15 @@ class JSONManyToManyDescriptor: rule_value = rule.get('value', '') rule_match = rule.get('match', 'exact') - if custom_attr_filter: - q = custom_attr_filter(rule['name'], rule_value, rule_match) - if q: - custom_q &= q - continue + custom_filter_q = None + spec_attr_filter = getattr(to_model, "get_filter_{}_attr_q".format(rule['name']), None) + if spec_attr_filter: + custom_filter_q = spec_attr_filter(rule_value, rule_match) + elif custom_attr_filter: + custom_filter_q = custom_attr_filter(rule['name'], rule_value, rule_match) + if custom_filter_q: + custom_q &= custom_filter_q + continue if rule_match == 'in': res &= value in rule_value or '*' in rule_value @@ -517,7 +525,6 @@ class JSONManyToManyDescriptor: res &= rule_value.issubset(value) else: res &= bool(value & rule_value) - else: logging.error("unknown match: {}".format(rule['match'])) res &= False diff --git a/apps/common/decorators.py b/apps/common/decorators.py index 7269c9e0d..171a4ff33 100644 --- a/apps/common/decorators.py +++ b/apps/common/decorators.py @@ -3,6 +3,7 @@ import asyncio import functools import inspect +import os import threading import time from concurrent.futures import ThreadPoolExecutor @@ -101,7 +102,11 @@ def run_debouncer_func(cache_key, org, ttl, func, *args, **kwargs): first_run_time = current if current - first_run_time > ttl: + _loop_debouncer_func_args_cache.pop(cache_key, None) + _loop_debouncer_func_task_time_cache.pop(cache_key, None) executor.submit(run_func_partial, *args, **kwargs) + logger.debug('pid {} executor submit run {}'.format( + os.getpid(), func.__name__, )) return loop = _loop_thread.get_loop() @@ -133,13 +138,26 @@ class Debouncer(object): return await self.loop.run_in_executor(self.executor, func) +ignore_err_exceptions = ( + "(3101, 'Plugin instructed the server to rollback the current transaction.')", +) + + def _run_func_with_org(key, org, func, *args, **kwargs): from orgs.utils import set_current_org try: - set_current_org(org) - func(*args, **kwargs) + with transaction.atomic(): + set_current_org(org) + func(*args, **kwargs) except Exception as e: - logger.error('delay run error: %s' % e) + msg = str(e) + log_func = logger.error + if msg in ignore_err_exceptions: + log_func = logger.info + pid = os.getpid() + thread_name = threading.current_thread() + log_func('pid {} thread {} delay run {} error: {}'.format( + pid, thread_name, func.__name__, msg)) _loop_debouncer_func_task_cache.pop(key, None) _loop_debouncer_func_args_cache.pop(key, None) _loop_debouncer_func_task_time_cache.pop(key, None) @@ -181,6 +199,32 @@ def merge_delay_run(ttl=5, key=None): :return: """ + def delay(func, *args, **kwargs): + from orgs.utils import get_current_org + suffix_key_func = key if key else default_suffix_key + org = get_current_org() + func_name = f'{func.__module__}_{func.__name__}' + key_suffix = suffix_key_func(*args, **kwargs) + cache_key = f'MERGE_DELAY_RUN_{func_name}_{key_suffix}' + cache_kwargs = _loop_debouncer_func_args_cache.get(cache_key, {}) + + for k, v in kwargs.items(): + if not isinstance(v, (tuple, list, set)): + raise ValueError('func kwargs value must be list or tuple: %s %s' % (func.__name__, v)) + v = set(v) + if k not in cache_kwargs: + cache_kwargs[k] = v + else: + cache_kwargs[k] = cache_kwargs[k].union(v) + _loop_debouncer_func_args_cache[cache_key] = cache_kwargs + run_debouncer_func(cache_key, org, ttl, func, *args, **cache_kwargs) + + def apply(func, sync=False, *args, **kwargs): + if sync: + return func(*args, **kwargs) + else: + return delay(func, *args, **kwargs) + def inner(func): sigs = inspect.signature(func) if len(sigs.parameters) != 1: @@ -188,27 +232,12 @@ def merge_delay_run(ttl=5, key=None): param = list(sigs.parameters.values())[0] if not isinstance(param.default, tuple): raise ValueError('func default must be tuple: %s' % param.default) - suffix_key_func = key if key else default_suffix_key + func.delay = functools.partial(delay, func) + func.apply = functools.partial(apply, func) @functools.wraps(func) def wrapper(*args, **kwargs): - from orgs.utils import get_current_org - org = get_current_org() - func_name = f'{func.__module__}_{func.__name__}' - key_suffix = suffix_key_func(*args, **kwargs) - cache_key = f'MERGE_DELAY_RUN_{func_name}_{key_suffix}' - cache_kwargs = _loop_debouncer_func_args_cache.get(cache_key, {}) - - for k, v in kwargs.items(): - if not isinstance(v, (tuple, list, set)): - raise ValueError('func kwargs value must be list or tuple: %s %s' % (func.__name__, v)) - v = set(v) - if k not in cache_kwargs: - cache_kwargs[k] = v - else: - cache_kwargs[k] = cache_kwargs[k].union(v) - _loop_debouncer_func_args_cache[cache_key] = cache_kwargs - run_debouncer_func(cache_key, org, ttl, func, *args, **cache_kwargs) + return func(*args, **kwargs) return wrapper diff --git a/apps/common/drf/filters.py b/apps/common/drf/filters.py index 85475f479..803849909 100644 --- a/apps/common/drf/filters.py +++ b/apps/common/drf/filters.py @@ -6,7 +6,7 @@ import logging from django.core.cache import cache from django.core.exceptions import ImproperlyConfigured -from django.db.models import Q, Count +from django.db.models import Q from django_filters import rest_framework as drf_filters from rest_framework import filters from rest_framework.compat import coreapi, coreschema @@ -180,36 +180,30 @@ class LabelFilterBackend(filters.BaseFilterBackend): ] @staticmethod - def filter_resources(resources, labels_id): + def parse_label_ids(labels_id): + from labels.models import Label label_ids = [i.strip() for i in labels_id.split(',')] + cleaned = [] args = [] for label_id in label_ids: kwargs = {} if ':' in label_id: k, v = label_id.split(':', 1) - kwargs['label__name'] = k.strip() + kwargs['name'] = k.strip() if v != '*': - kwargs['label__value'] = v.strip() + kwargs['value'] = v.strip() + args.append(kwargs) else: - kwargs['label_id'] = label_id - args.append(kwargs) + cleaned.append(label_id) - if len(args) == 1: - resources = resources.filter(**args[0]) - return resources - - q = Q() - for kwarg in args: - q |= Q(**kwarg) - - resources = resources.filter(q) \ - .values('res_id') \ - .order_by('res_id') \ - .annotate(count=Count('res_id', distinct=True)) \ - .values('res_id', 'count') \ - .filter(count=len(args)) - return resources + if len(args) != 0: + q = Q() + for kwarg in args: + q |= Q(**kwarg) + ids = Label.objects.filter(q).values_list('id', flat=True) + cleaned.extend(list(ids)) + return cleaned def filter_queryset(self, request, queryset, view): labels_id = request.query_params.get('labels') @@ -230,7 +224,8 @@ class LabelFilterBackend(filters.BaseFilterBackend): resources = labeled_resource_cls.objects.filter( res_type__app_label=app_label, res_type__model=model_name, ) - resources = self.filter_resources(resources, labels_id) + label_ids = self.parse_label_ids(labels_id) + resources = model.filter_resources_by_labels(resources, label_ids) res_ids = resources.values_list('res_id', flat=True) queryset = queryset.filter(id__in=set(res_ids)) return queryset diff --git a/apps/common/drf/renders/base.py b/apps/common/drf/renders/base.py index 2c1038610..d79232679 100644 --- a/apps/common/drf/renders/base.py +++ b/apps/common/drf/renders/base.py @@ -87,7 +87,7 @@ class BaseFileRenderer(BaseRenderer): if value is None: return '-' pk = str(value.get('id', '') or value.get('pk', '')) - name = value.get('name') or value.get('display_name', '') + name = value.get('display_name', '') or value.get('name', '') return '{}({})'.format(name, pk) @staticmethod diff --git a/apps/common/sdk/im/dingtalk/__init__.py b/apps/common/sdk/im/dingtalk/__init__.py index 65d466008..37a3c2dad 100644 --- a/apps/common/sdk/im/dingtalk/__init__.py +++ b/apps/common/sdk/im/dingtalk/__init__.py @@ -28,9 +28,10 @@ class ErrorCode: class URL: - QR_CONNECT = 'https://oapi.dingtalk.com/connect/qrconnect' + QR_CONNECT = 'https://login.dingtalk.com/oauth2/auth' OAUTH_CONNECT = 'https://oapi.dingtalk.com/connect/oauth2/sns_authorize' - GET_USER_INFO_BY_CODE = 'https://oapi.dingtalk.com/sns/getuserinfo_bycode' + GET_USER_ACCESSTOKEN = 'https://api.dingtalk.com/v1.0/oauth2/userAccessToken' + GET_USER_INFO = 'https://api.dingtalk.com/v1.0/contact/users/me' GET_TOKEN = 'https://oapi.dingtalk.com/gettoken' SEND_MESSAGE_BY_TEMPLATE = 'https://oapi.dingtalk.com/topapi/message/corpconversation/sendbytemplate' SEND_MESSAGE = 'https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2' @@ -72,8 +73,9 @@ class DingTalkRequests(BaseRequest): def get(self, url, params=None, with_token=False, with_sign=False, check_errcode_is_0=True, - **kwargs): + **kwargs) -> dict: pass + get = as_request(get) def post(self, url, json=None, params=None, @@ -81,6 +83,7 @@ class DingTalkRequests(BaseRequest): check_errcode_is_0=True, **kwargs) -> dict: pass + post = as_request(post) def _add_sign(self, kwargs: dict): @@ -123,17 +126,22 @@ class DingTalk: ) def get_userinfo_bycode(self, code): - # https://developers.dingtalk.com/document/app/obtain-the-user-information-based-on-the-sns-temporary-authorization?spm=ding_open_doc.document.0.0.3a256573y8Y7yg#topic-1995619 body = { - "tmp_auth_code": code + 'clientId': self._appid, + 'clientSecret': self._appsecret, + 'code': code, + 'grantType': 'authorization_code' } + data = self._request.post(URL.GET_USER_ACCESSTOKEN, json=body, check_errcode_is_0=False) + token = data['accessToken'] - data = self._request.post(URL.GET_USER_INFO_BY_CODE, json=body, with_sign=True) - return data['user_info'] + user = self._request.get(URL.GET_USER_INFO, + headers={'x-acs-dingtalk-access-token': token}, check_errcode_is_0=False) + return user def get_user_id_by_code(self, code): user_info = self.get_userinfo_bycode(code) - unionid = user_info['unionid'] + unionid = user_info['unionId'] userid = self.get_userid_by_unionid(unionid) return userid, None diff --git a/apps/common/sessions/__init__.py b/apps/common/sessions/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/common/sessions/cache.py b/apps/common/sessions/cache.py new file mode 100644 index 000000000..805d6738a --- /dev/null +++ b/apps/common/sessions/cache.py @@ -0,0 +1,56 @@ +import re + +from django.contrib.sessions.backends.cache import ( + SessionStore as DjangoSessionStore +) +from django.core.cache import cache + +from jumpserver.utils import get_current_request + + +class SessionStore(DjangoSessionStore): + ignore_urls = [ + r'^/api/v1/users/profile/' + ] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.ignore_pattern = re.compile('|'.join(self.ignore_urls)) + + def save(self, *args, **kwargs): + request = get_current_request() + if request is None or not self.ignore_pattern.match(request.path): + super().save(*args, **kwargs) + + +class RedisUserSessionManager: + JMS_SESSION_KEY = 'jms_session_key' + + def __init__(self): + self.client = cache.client.get_client() + + def add_or_increment(self, session_key): + self.client.hincrby(self.JMS_SESSION_KEY, session_key, 1) + + def decrement_or_remove(self, session_key): + new_count = self.client.hincrby(self.JMS_SESSION_KEY, session_key, -1) + if new_count <= 0: + self.client.hdel(self.JMS_SESSION_KEY, session_key) + + def check_active(self, session_key): + count = self.client.hget(self.JMS_SESSION_KEY, session_key) + count = 0 if count is None else int(count.decode('utf-8')) + return count > 0 + + def get_active_keys(self): + session_keys = [] + for k, v in self.client.hgetall(self.JMS_SESSION_KEY).items(): + count = int(v.decode('utf-8')) + if count <= 0: + continue + key = k.decode('utf-8') + session_keys.append(key) + return session_keys + + +user_session_manager = RedisUserSessionManager() diff --git a/apps/common/signal_handlers.py b/apps/common/signal_handlers.py index ad765657e..6c5ceae1a 100644 --- a/apps/common/signal_handlers.py +++ b/apps/common/signal_handlers.py @@ -69,7 +69,7 @@ def digest_sql_query(): for query in queries: sql = query['sql'] - print(" # {}: {}".format(query['time'], sql[:1000])) + print(" # {}: {}".format(query['time'], sql[:1000])) if len(queries) < 3: continue print("- Table: {}".format(table_name)) diff --git a/apps/common/utils/file.py b/apps/common/utils/file.py index ac3f5868b..19772d5d7 100644 --- a/apps/common/utils/file.py +++ b/apps/common/utils/file.py @@ -21,6 +21,8 @@ def encrypt_and_compress_zip_file(filename, secret_password, encrypted_filenames with pyzipper.AESZipFile( filename, 'w', compression=pyzipper.ZIP_LZMA, encryption=pyzipper.WZ_AES ) as zf: + if secret_password and isinstance(secret_password, str): + secret_password = secret_password.encode('utf8') zf.setpassword(secret_password) for encrypted_filename in encrypted_filenames: with open(encrypted_filename, 'rb') as f: diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 741a0e5db..d1caba0cd 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -547,7 +547,6 @@ class Config(dict): 'REFERER_CHECK_ENABLED': False, 'SESSION_ENGINE': 'cache', 'SESSION_SAVE_EVERY_REQUEST': True, - 'SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE': False, 'SERVER_REPLAY_STORAGE': {}, 'SECURITY_DATA_CRYPTO_ALGO': None, 'GMSSL_ENABLED': False, @@ -564,8 +563,10 @@ class Config(dict): 'FTP_LOG_KEEP_DAYS': 180, 'CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS': 180, 'JOB_EXECUTION_KEEP_DAYS': 180, + 'PASSWORD_CHANGE_LOG_KEEP_DAYS': 999, 'TICKETS_ENABLED': True, + 'TICKETS_DIRECT_APPROVE': False, # 废弃的 'DEFAULT_ORG_SHOW_ALL_USERS': True, @@ -606,7 +607,9 @@ class Config(dict): 'GPT_MODEL': 'gpt-3.5-turbo', 'VIRTUAL_APP_ENABLED': False, - 'FILE_UPLOAD_SIZE_LIMIT_MB': 200 + 'FILE_UPLOAD_SIZE_LIMIT_MB': 200, + + 'TICKET_APPLY_ASSET_SCOPE': 'all' } old_config_map = { @@ -701,7 +704,8 @@ class Config(dict): def compatible_redis(self): redis_config = { - 'REDIS_PASSWORD': quote(str(self.REDIS_PASSWORD)), + 'REDIS_PASSWORD': str(self.REDIS_PASSWORD), + 'REDIS_PASSWORD_QUOTE': quote(str(self.REDIS_PASSWORD)), } for key, value in redis_config.items(): self[key] = value diff --git a/apps/jumpserver/middleware.py b/apps/jumpserver/middleware.py index 9a49189c8..ad6bb496d 100644 --- a/apps/jumpserver/middleware.py +++ b/apps/jumpserver/middleware.py @@ -66,11 +66,6 @@ class RequestMiddleware: def __call__(self, request): set_current_request(request) response = self.get_response(request) - is_request_api = request.path.startswith('/api') - if not settings.SESSION_EXPIRE_AT_BROWSER_CLOSE and \ - not is_request_api: - age = request.session.get_expiry_age() - request.session.set_expiry(age) return response diff --git a/apps/jumpserver/rewriting/storage/permissions.py b/apps/jumpserver/rewriting/storage/permissions.py index 511545865..7d91c246f 100644 --- a/apps/jumpserver/rewriting/storage/permissions.py +++ b/apps/jumpserver/rewriting/storage/permissions.py @@ -3,6 +3,7 @@ path_perms_map = { 'xpack': '*', 'settings': '*', + 'img': '*', 'replay': 'default', 'applets': 'terminal.view_applet', 'virtual_apps': 'terminal.view_virtualapp', diff --git a/apps/jumpserver/settings/base.py b/apps/jumpserver/settings/base.py index 10188a1a7..6503b2477 100644 --- a/apps/jumpserver/settings/base.py +++ b/apps/jumpserver/settings/base.py @@ -234,11 +234,9 @@ CSRF_COOKIE_NAME = '{}csrftoken'.format(SESSION_COOKIE_NAME_PREFIX) SESSION_COOKIE_NAME = '{}sessionid'.format(SESSION_COOKIE_NAME_PREFIX) SESSION_COOKIE_AGE = CONFIG.SESSION_COOKIE_AGE -SESSION_EXPIRE_AT_BROWSER_CLOSE = True -# 自定义的配置,SESSION_EXPIRE_AT_BROWSER_CLOSE 始终为 True, 下面这个来控制是否强制关闭后过期 cookie -SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE = CONFIG.SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE SESSION_SAVE_EVERY_REQUEST = CONFIG.SESSION_SAVE_EVERY_REQUEST -SESSION_ENGINE = "django.contrib.sessions.backends.{}".format(CONFIG.SESSION_ENGINE) +SESSION_EXPIRE_AT_BROWSER_CLOSE = CONFIG.SESSION_EXPIRE_AT_BROWSER_CLOSE +SESSION_ENGINE = "common.sessions.{}".format(CONFIG.SESSION_ENGINE) MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage' # Database @@ -408,7 +406,7 @@ if REDIS_SENTINEL_SERVICE_NAME and REDIS_SENTINELS: else: REDIS_LOCATION_NO_DB = '%(protocol)s://:%(password)s@%(host)s:%(port)s/{}' % { 'protocol': REDIS_PROTOCOL, - 'password': CONFIG.REDIS_PASSWORD, + 'password': CONFIG.REDIS_PASSWORD_QUOTE, 'host': CONFIG.REDIS_HOST, 'port': CONFIG.REDIS_PORT, } diff --git a/apps/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index 311e54aa8..b564cba25 100644 --- a/apps/jumpserver/settings/custom.py +++ b/apps/jumpserver/settings/custom.py @@ -122,11 +122,11 @@ WS_LISTEN_PORT = CONFIG.WS_LISTEN_PORT LOGIN_LOG_KEEP_DAYS = CONFIG.LOGIN_LOG_KEEP_DAYS TASK_LOG_KEEP_DAYS = CONFIG.TASK_LOG_KEEP_DAYS OPERATE_LOG_KEEP_DAYS = CONFIG.OPERATE_LOG_KEEP_DAYS +PASSWORD_CHANGE_LOG_KEEP_DAYS = CONFIG.PASSWORD_CHANGE_LOG_KEEP_DAYS ACTIVITY_LOG_KEEP_DAYS = CONFIG.ACTIVITY_LOG_KEEP_DAYS FTP_LOG_KEEP_DAYS = CONFIG.FTP_LOG_KEEP_DAYS CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS = CONFIG.CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS JOB_EXECUTION_KEEP_DAYS = CONFIG.JOB_EXECUTION_KEEP_DAYS - ORG_CHANGE_TO_URL = CONFIG.ORG_CHANGE_TO_URL WINDOWS_SKIP_ALL_MANUAL_PASSWORD = CONFIG.WINDOWS_SKIP_ALL_MANUAL_PASSWORD @@ -137,6 +137,7 @@ CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED = CONFIG.CHANGE_AUTH_PLAN_SECURE_MODE_ENABL DATETIME_DISPLAY_FORMAT = '%Y-%m-%d %H:%M:%S' TICKETS_ENABLED = CONFIG.TICKETS_ENABLED +TICKETS_DIRECT_APPROVE = CONFIG.TICKETS_DIRECT_APPROVE REFERER_CHECK_ENABLED = CONFIG.REFERER_CHECK_ENABLED CONNECTION_TOKEN_ENABLED = CONFIG.CONNECTION_TOKEN_ENABLED @@ -214,6 +215,9 @@ PERM_TREE_REGEN_INTERVAL = CONFIG.PERM_TREE_REGEN_INTERVAL MAGNUS_ORACLE_PORTS = CONFIG.MAGNUS_ORACLE_PORTS LIMIT_SUPER_PRIV = CONFIG.LIMIT_SUPER_PRIV +# Asset account may be too many +ASSET_SIZE = 'small' + # Chat AI CHAT_AI_ENABLED = CONFIG.CHAT_AI_ENABLED GPT_API_KEY = CONFIG.GPT_API_KEY @@ -224,3 +228,5 @@ GPT_MODEL = CONFIG.GPT_MODEL VIRTUAL_APP_ENABLED = CONFIG.VIRTUAL_APP_ENABLED FILE_UPLOAD_SIZE_LIMIT_MB = CONFIG.FILE_UPLOAD_SIZE_LIMIT_MB + +TICKET_APPLY_ASSET_SCOPE = CONFIG.TICKET_APPLY_ASSET_SCOPE diff --git a/apps/jumpserver/settings/libs.py b/apps/jumpserver/settings/libs.py index 1f2c333ec..f2ace1279 100644 --- a/apps/jumpserver/settings/libs.py +++ b/apps/jumpserver/settings/libs.py @@ -82,7 +82,6 @@ BOOTSTRAP3 = { # Django channels support websocket REDIS_LAYERS_HOST = { 'db': CONFIG.REDIS_DB_WS, - 'password': CONFIG.REDIS_PASSWORD or None, } REDIS_LAYERS_SSL_PARAMS = {} @@ -97,6 +96,7 @@ if REDIS_USE_SSL: if REDIS_SENTINEL_SERVICE_NAME and REDIS_SENTINELS: REDIS_LAYERS_HOST['sentinels'] = REDIS_SENTINELS + REDIS_LAYERS_HOST['password'] = CONFIG.REDIS_PASSWORD or None REDIS_LAYERS_HOST['master_name'] = REDIS_SENTINEL_SERVICE_NAME REDIS_LAYERS_HOST['sentinel_kwargs'] = { 'password': REDIS_SENTINEL_PASSWORD, @@ -111,7 +111,7 @@ else: # More info see: https://github.com/django/channels_redis/issues/334 # REDIS_LAYERS_HOST['address'] = (CONFIG.REDIS_HOST, CONFIG.REDIS_PORT) REDIS_LAYERS_ADDRESS = '{protocol}://:{password}@{host}:{port}/{db}'.format( - protocol=REDIS_PROTOCOL, password=CONFIG.REDIS_PASSWORD, + protocol=REDIS_PROTOCOL, password=CONFIG.REDIS_PASSWORD_QUOTE, host=CONFIG.REDIS_HOST, port=CONFIG.REDIS_PORT, db=CONFIG.REDIS_DB_WS ) REDIS_LAYERS_HOST['address'] = REDIS_LAYERS_ADDRESS @@ -153,7 +153,7 @@ if REDIS_SENTINEL_SERVICE_NAME and REDIS_SENTINELS: else: CELERY_BROKER_URL = CELERY_BROKER_URL_FORMAT % { 'protocol': REDIS_PROTOCOL, - 'password': CONFIG.REDIS_PASSWORD, + 'password': CONFIG.REDIS_PASSWORD_QUOTE, 'host': CONFIG.REDIS_HOST, 'port': CONFIG.REDIS_PORT, 'db': CONFIG.REDIS_DB_CELERY, @@ -187,6 +187,7 @@ ANSIBLE_LOG_DIR = os.path.join(PROJECT_DIR, 'data', 'ansible') REDIS_HOST = CONFIG.REDIS_HOST REDIS_PORT = CONFIG.REDIS_PORT REDIS_PASSWORD = CONFIG.REDIS_PASSWORD +REDIS_PASSWORD_QUOTE = CONFIG.REDIS_PASSWORD_QUOTE DJANGO_REDIS_SCAN_ITERSIZE = 1000 diff --git a/apps/labels/mixins.py b/apps/labels/mixins.py index 4b775cde5..33e73b60b 100644 --- a/apps/labels/mixins.py +++ b/apps/labels/mixins.py @@ -1,6 +1,6 @@ from django.contrib.contenttypes.fields import GenericRelation from django.db import models -from django.db.models import OneToOneField +from django.db.models import OneToOneField, Count from common.utils import lazyproperty from .models import LabeledResource @@ -36,3 +36,37 @@ class LabeledMixin(models.Model): @res_labels.setter def res_labels(self, value): self.real.labels.set(value, bulk=False) + + @classmethod + def filter_resources_by_labels(cls, resources, label_ids): + return cls._get_filter_res_by_labels_m2m_all(resources, label_ids) + + @classmethod + def _get_filter_res_by_labels_m2m_in(cls, resources, label_ids): + return resources.filter(label_id__in=label_ids) + + @classmethod + def _get_filter_res_by_labels_m2m_all(cls, resources, label_ids): + if len(label_ids) == 1: + return cls._get_filter_res_by_labels_m2m_in(resources, label_ids) + + resources = resources.filter(label_id__in=label_ids) \ + .values('res_id') \ + .order_by('res_id') \ + .annotate(count=Count('res_id', distinct=True)) \ + .values('res_id', 'count') \ + .filter(count=len(label_ids)) + return resources + + @classmethod + def get_labels_filter_attr_q(cls, value, match): + resources = LabeledResource.objects.all() + if not value: + return None + + if match != 'm2m_all': + resources = cls._get_filter_res_by_labels_m2m_in(resources, value) + else: + resources = cls._get_filter_res_by_labels_m2m_all(resources, value) + res_ids = set(resources.values_list('res_id', flat=True)) + return models.Q(id__in=res_ids) diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 0f74a7c63..b9f102de9 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:7879f4eeb499e920ad6c4bfdb0b1f334936ca344c275be056f12fcf7485f2bf6 -size 170948 +oid sha256:d04781f4f0b0de3ac5f707febb222e239553d6103bca0cec41ab2fd5ab044571 +size 173799 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index c6a6dfe37..12f6425f0 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: 2024-01-17 19:11+0800\n" +"POT-Creation-Date: 2024-02-27 16:09+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -22,6 +22,11 @@ msgstr "" msgid "The parameter 'action' must be [{}]" msgstr "パラメータ 'action' は [{}] でなければなりません。" +#: accounts/automations/change_secret/manager.py:201 +#, python-format +msgid "Success: %s, Failed: %s, Total: %s" +msgstr "成功: %s、失敗: %s、合計: %s" + #: accounts/const/account.py:6 #: accounts/serializers/automations/change_secret.py:32 #: assets/models/_user.py:24 audits/signal_handlers/login_log.py:34 @@ -31,7 +36,7 @@ msgstr "パラメータ 'action' は [{}] でなければなりません。" #: settings/serializers/auth/ldap.py:25 settings/serializers/auth/ldap.py:47 #: settings/serializers/msg.py:35 terminal/serializers/storage.py:123 #: terminal/serializers/storage.py:142 users/forms/profile.py:22 -#: users/serializers/user.py:104 +#: users/serializers/user.py:106 #: users/templates/users/_msg_user_created.html:13 #: users/templates/users/user_password_verify.html:18 #: xpack/plugins/cloud/serializers/account_attrs.py:28 @@ -203,8 +208,8 @@ msgstr "作成のみ" #: notifications/backends/__init__.py:10 settings/serializers/msg.py:22 #: settings/serializers/msg.py:64 users/forms/profile.py:102 #: users/forms/profile.py:109 users/models/user.py:802 -#: users/templates/users/forgot_password.html:117 -#: users/views/profile/reset.py:93 +#: users/templates/users/forgot_password.html:160 +#: users/views/profile/reset.py:94 msgid "Email" msgstr "メール" @@ -253,7 +258,7 @@ msgstr "ユーザー %s がパスワードを閲覧/導き出しました" #: perms/models/asset_permission.py:69 perms/serializers/permission.py:36 #: terminal/backends/command/models.py:17 terminal/models/session/session.py:31 #: terminal/notifications.py:155 terminal/serializers/command.py:17 -#: terminal/serializers/session.py:26 +#: terminal/serializers/session.py:28 #: terminal/templates/terminal/_msg_command_warning.html:4 #: terminal/templates/terminal/_msg_session_sharing.html:4 #: tickets/models/ticket/apply_asset.py:16 xpack/plugins/cloud/models.py:256 @@ -360,7 +365,7 @@ msgstr "アカウントバックアップ計画" #: accounts/models/automations/backup_account.py:119 #: assets/models/automations/base.py:115 audits/models.py:65 -#: ops/models/base.py:55 ops/models/celery.py:63 ops/models/job.py:235 +#: ops/models/base.py:55 ops/models/celery.py:86 ops/models/job.py:236 #: ops/templates/ops/celery_task_log.html:75 #: perms/models/asset_permission.py:78 #: settings/templates/ldap/_msg_import_ldap_user.html:5 @@ -397,7 +402,7 @@ msgstr "理由" #: accounts/models/automations/backup_account.py:135 #: accounts/serializers/automations/change_secret.py:105 #: accounts/serializers/automations/change_secret.py:128 -#: ops/serializers/job.py:64 terminal/serializers/session.py:49 +#: ops/serializers/job.py:71 terminal/serializers/session.py:51 msgid "Is success" msgstr "成功は" @@ -471,14 +476,14 @@ msgstr "開始日" #: accounts/models/automations/change_secret.py:42 #: assets/models/automations/base.py:116 ops/models/base.py:56 -#: ops/models/celery.py:64 ops/models/job.py:236 +#: ops/models/celery.py:87 ops/models/job.py:237 #: terminal/models/applet/host.py:142 msgid "Date finished" msgstr "終了日" #: accounts/models/automations/change_secret.py:43 #: assets/models/automations/base.py:113 audits/models.py:208 -#: audits/serializers.py:54 ops/models/base.py:49 ops/models/job.py:227 +#: audits/serializers.py:54 ops/models/base.py:49 ops/models/job.py:228 #: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:140 #: terminal/models/component/status.py:30 #: terminal/models/virtualapp/virtualapp.py:99 @@ -495,7 +500,7 @@ msgstr "ステータス" #: authentication/templates/authentication/passkey.html:173 #: authentication/views/base.py:42 authentication/views/base.py:43 #: authentication/views/base.py:44 common/const/choices.py:20 -#: settings/templates/ldap/_msg_import_ldap_user.html:22 +#: settings/templates/ldap/_msg_import_ldap_user.html:26 msgid "Error" msgstr "間違い" @@ -604,14 +609,14 @@ msgstr "パスワードルール" #: authentication/serializers/connect_token_secret.py:113 #: authentication/serializers/connect_token_secret.py:168 labels/models.py:11 #: ops/mixin.py:21 ops/models/adhoc.py:20 ops/models/celery.py:15 -#: ops/models/celery.py:57 ops/models/job.py:136 ops/models/playbook.py:28 +#: ops/models/celery.py:80 ops/models/job.py:137 ops/models/playbook.py:28 #: ops/serializers/job.py:18 orgs/models.py:82 #: perms/models/asset_permission.py:61 rbac/models/role.py:29 #: settings/models.py:33 settings/models.py:181 settings/serializers/msg.py:89 #: terminal/models/applet/applet.py:33 terminal/models/component/endpoint.py:12 -#: terminal/models/component/endpoint.py:95 +#: terminal/models/component/endpoint.py:109 #: terminal/models/component/storage.py:26 terminal/models/component/task.py:13 -#: terminal/models/component/terminal.py:84 +#: terminal/models/component/terminal.py:85 #: terminal/models/virtualapp/provider.py:10 #: terminal/models/virtualapp/virtualapp.py:19 tickets/api/ticket.py:87 #: users/forms/profile.py:33 users/models/group.py:13 @@ -630,8 +635,8 @@ msgstr "特権アカウント" #: assets/models/label.py:22 #: authentication/serializers/connect_token_secret.py:117 #: terminal/models/applet/applet.py:40 -#: terminal/models/component/endpoint.py:106 -#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:167 +#: terminal/models/component/endpoint.py:120 +#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:169 msgid "Is active" msgstr "アクティブです。" @@ -714,22 +719,22 @@ msgstr "" msgid "Notification of implementation result of encryption change plan" msgstr "暗号化変更プランの実装結果の通知" -#: accounts/notifications.py:65 +#: accounts/notifications.py:66 msgid "" "{} - The encryption change task has been completed. See the attachment for " "details" msgstr "{} -暗号化変更タスクが完了しました。詳細は添付ファイルをご覧ください" -#: accounts/notifications.py:68 +#: accounts/notifications.py:70 msgid "" "{} - The encryption change task has been completed: the encryption password " -"has not been set - please go to personal information -> file encryption " -"password to set the encryption password" +"has not been set - please go to personal information -> set encryption " +"password in preferences" msgstr "" "{} -暗号化変更タスクが完了しました: 暗号化パスワードが設定されていません-個人" -"情報にアクセスしてください-> ファイル暗号化パスワードを設定してください" +"情報にアクセスしてください-> 環境設定で暗号化パスワードを設定する" -#: accounts/notifications.py:79 +#: accounts/notifications.py:82 msgid "Gather account change information" msgstr "アカウント変更情報" @@ -758,11 +763,11 @@ msgstr "カテゴリ" #: assets/serializers/asset/common.py:126 assets/serializers/platform.py:120 #: assets/serializers/platform.py:139 audits/serializers.py:53 #: audits/serializers.py:170 -#: authentication/serializers/connect_token_secret.py:126 ops/models/job.py:144 +#: authentication/serializers/connect_token_secret.py:126 ops/models/job.py:145 #: perms/serializers/user_permission.py:27 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:264 +#: terminal/serializers/session.py:23 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 @@ -778,7 +783,7 @@ msgstr "資産が存在しません" msgid "Has secret" msgstr "エスクローされたパスワード" -#: accounts/serializers/account/account.py:259 ops/models/celery.py:60 +#: accounts/serializers/account/account.py:259 ops/models/celery.py:83 #: tickets/models/comment.py:13 tickets/models/ticket/general.py:45 #: tickets/models/ticket/general.py:279 tickets/serializers/super_ticket.py:14 #: tickets/serializers/ticket/ticket.py:21 @@ -795,7 +800,7 @@ msgstr "編集済み" #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 #: authentication/api/connection_token.py:404 ops/models/base.py:17 -#: ops/models/job.py:146 ops/serializers/job.py:19 +#: ops/models/job.py:147 ops/serializers/job.py:19 #: terminal/templates/terminal/_msg_command_execute_alert.html:16 msgid "Assets" msgstr "資産" @@ -926,11 +931,11 @@ msgstr "关联平台,可以配置推送参数,如果不关联,则使用默 #: accounts/serializers/account/virtual.py:19 assets/models/_user.py:27 #: 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:152 ops/models/playbook.py:31 rbac/models/role.py:37 +#: ops/models/job.py:153 ops/models/playbook.py:31 rbac/models/role.py:37 #: settings/models.py:38 terminal/models/applet/applet.py:45 #: terminal/models/applet/applet.py:321 terminal/models/applet/host.py:143 #: terminal/models/component/endpoint.py:25 -#: terminal/models/component/endpoint.py:105 +#: terminal/models/component/endpoint.py:119 #: terminal/models/session/session.py:46 #: terminal/models/virtualapp/virtualapp.py:28 tickets/models/comment.py:32 #: tickets/models/ticket/general.py:297 users/models/user.py:836 @@ -985,7 +990,7 @@ msgstr "自動タスク実行履歴" #: audits/models.py:64 audits/signal_handlers/activity_log.py:33 #: common/const/choices.py:18 ops/const.py:73 ops/serializers/celery.py:46 #: terminal/const.py:78 terminal/models/session/sharing.py:121 -#: tickets/views/approve.py:117 +#: tickets/views/approve.py:128 msgid "Success" msgstr "成功" @@ -1071,7 +1076,7 @@ msgstr "秘密鍵が無効またはpassphraseエラー" msgid "Acls" msgstr "Acls" -#: acls/const.py:6 audits/const.py:36 terminal/const.py:11 tickets/const.py:45 +#: acls/const.py:6 audits/const.py:36 terminal/const.py:11 tickets/const.py:46 #: tickets/templates/tickets/approve_check_password.html:47 msgid "Reject" msgstr "拒否" @@ -1093,13 +1098,13 @@ msgid "Notifications" msgstr "通知" #: acls/models/base.py:37 assets/models/_user.py:51 -#: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:98 +#: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:112 #: xpack/plugins/cloud/models.py:282 msgid "Priority" msgstr "優先順位" #: acls/models/base.py:38 assets/models/_user.py:51 -#: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:99 +#: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:113 #: xpack/plugins/cloud/models.py:283 msgid "1-100, the lower the value will be match first" msgstr "1-100、低い値は最初に一致します" @@ -1113,7 +1118,7 @@ msgstr "レビュー担当者" #: authentication/models/connection_token.py:53 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:82 terminal/models/session/sharing.py:29 -#: tickets/const.py:37 +#: tickets/const.py:38 msgid "Active" msgstr "アクティブ" @@ -1128,7 +1133,7 @@ msgid "Accounts" msgstr "アカウント" #: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60 -#: ops/serializers/job.py:63 terminal/const.py:86 +#: ops/serializers/job.py:70 terminal/const.py:86 #: 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 @@ -1171,7 +1176,7 @@ msgstr "生成された正規表現が正しくありません: {}" msgid "Command acl" msgstr "コマンドフィルタリング" -#: acls/models/command_acl.py:112 tickets/const.py:11 +#: acls/models/command_acl.py:112 tickets/const.py:12 msgid "Command confirm" msgstr "コマンドの確認" @@ -1192,7 +1197,7 @@ msgstr "ルール" msgid "Login acl" msgstr "ログインacl" -#: acls/models/login_acl.py:27 tickets/const.py:10 +#: acls/models/login_acl.py:27 tickets/const.py:11 msgid "Login confirm" msgstr "ログイン確認" @@ -1200,7 +1205,7 @@ msgstr "ログイン確認" msgid "Login asset acl" msgstr "ログインasset acl" -#: acls/models/login_asset_acl.py:22 tickets/const.py:12 +#: acls/models/login_asset_acl.py:22 tickets/const.py:13 msgid "Login asset confirm" msgstr "ログイン資産の確認" @@ -1325,7 +1330,7 @@ msgstr "アプリケーション" msgid "Can match application" msgstr "アプリケーションを一致させることができます" -#: assets/api/asset/asset.py:179 +#: assets/api/asset/asset.py:180 msgid "Cannot create asset directly, you should create a host or other" msgstr "" "資産を直接作成することはできません。ホストまたはその他を作成する必要がありま" @@ -1465,7 +1470,7 @@ msgid "Kubernetes" msgstr "Kubernetes" #: assets/const/device.py:7 terminal/models/applet/applet.py:26 -#: tickets/const.py:8 +#: tickets/const.py:9 msgid "General" msgstr "一般" @@ -1607,7 +1612,7 @@ msgstr "ボタンセレクターを確認する" msgid "API mode" msgstr "APIモード" -#: assets/const/types.py:247 +#: assets/const/types.py:248 msgid "All types" msgstr "いろんなタイプ" @@ -1630,7 +1635,7 @@ msgstr "SSHパブリックキー" #: assets/models/_user.py:28 assets/models/automations/base.py:114 #: assets/models/cmd_filter.py:41 assets/models/group.py:19 #: audits/models.py:267 common/db/models.py:34 ops/models/base.py:54 -#: ops/models/job.py:234 users/models/user.py:1042 +#: ops/models/job.py:235 users/models/user.py:1042 msgid "Date created" msgstr "作成された日付" @@ -1670,7 +1675,7 @@ msgstr "ユーザーと同じユーザー名" #: authentication/serializers/connect_token_secret.py:114 #: settings/serializers/msg.py:29 terminal/models/applet/applet.py:42 #: terminal/models/virtualapp/virtualapp.py:24 -#: terminal/serializers/session.py:19 terminal/serializers/session.py:45 +#: terminal/serializers/session.py:21 terminal/serializers/session.py:47 #: terminal/serializers/storage.py:71 msgid "Protocol" msgstr "プロトコル" @@ -1744,7 +1749,7 @@ msgid "Domain" msgstr "ドメイン" #: assets/models/asset/common.py:165 assets/models/automations/base.py:18 -#: assets/models/cmd_filter.py:32 assets/models/node.py:546 +#: assets/models/cmd_filter.py:32 assets/models/node.py:549 #: perms/models/asset_permission.py:72 perms/serializers/permission.py:37 #: tickets/models/ticket/apply_asset.py:14 xpack/plugins/cloud/models.py:330 msgid "Node" @@ -1799,7 +1804,7 @@ msgstr "証明書チェックを無視" msgid "Proxy" msgstr "プロキシー" -#: assets/models/automations/base.py:22 ops/models/job.py:230 +#: assets/models/automations/base.py:22 ops/models/job.py:231 #: settings/serializers/auth/sms.py:103 msgid "Parameters" msgstr "パラメータ" @@ -1884,7 +1889,7 @@ msgstr "デフォルトアセットグループ" msgid "System" msgstr "システム" -#: assets/models/label.py:19 assets/models/node.py:532 +#: assets/models/label.py:19 assets/models/node.py:535 #: assets/serializers/cagegory.py:11 assets/serializers/cagegory.py:18 #: assets/serializers/cagegory.py:24 #: authentication/models/connection_token.py:29 @@ -1907,23 +1912,23 @@ msgstr "ラベル" msgid "New node" msgstr "新しいノード" -#: assets/models/node.py:460 audits/backends/db.py:65 audits/backends/db.py:66 +#: assets/models/node.py:463 audits/backends/db.py:65 audits/backends/db.py:66 msgid "empty" msgstr "空" -#: assets/models/node.py:531 perms/models/perm_node.py:28 +#: assets/models/node.py:534 perms/models/perm_node.py:28 msgid "Key" msgstr "キー" -#: assets/models/node.py:533 assets/serializers/node.py:20 +#: assets/models/node.py:536 assets/serializers/node.py:20 msgid "Full value" msgstr "フルバリュー" -#: assets/models/node.py:537 perms/models/perm_node.py:30 +#: assets/models/node.py:540 perms/models/perm_node.py:30 msgid "Parent key" msgstr "親キー" -#: assets/models/node.py:549 +#: assets/models/node.py:552 msgid "Can match node" msgstr "ノードを一致させることができます" @@ -2366,7 +2371,7 @@ msgstr "名前の変更" msgid "Symlink" msgstr "Symlink" -#: audits/const.py:18 audits/const.py:28 terminal/api/session/session.py:146 +#: audits/const.py:18 audits/const.py:28 terminal/api/session/session.py:149 msgid "Download" msgstr "ダウンロード" @@ -2374,7 +2379,7 @@ msgstr "ダウンロード" msgid "Rename dir" msgstr "マップディレクトリ" -#: audits/const.py:23 rbac/tree.py:238 terminal/api/session/session.py:257 +#: audits/const.py:23 rbac/tree.py:238 terminal/api/session/session.py:277 #: terminal/templates/terminal/_msg_command_warning.html:18 #: terminal/templates/terminal/_msg_session_sharing.html:10 msgid "View" @@ -2400,21 +2405,21 @@ msgstr "ログイン" msgid "Change password" msgstr "パスワードを変更する" -#: audits/const.py:37 tickets/const.py:46 +#: audits/const.py:37 tickets/const.py:47 msgid "Approve" msgstr "承認" #: audits/const.py:38 #: authentication/templates/authentication/_access_key_modal.html:155 #: authentication/templates/authentication/_mfa_confirm_modal.html:53 -#: templates/_modal.html:22 tickets/const.py:44 +#: templates/_modal.html:22 tickets/const.py:45 msgid "Close" msgstr "閉じる" #: audits/const.py:43 settings/serializers/terminal.py:6 -#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:174 -#: terminal/models/virtualapp/provider.py:14 terminal/serializers/session.py:52 -#: terminal/serializers/session.py:66 +#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:175 +#: terminal/models/virtualapp/provider.py:14 terminal/serializers/session.py:54 +#: terminal/serializers/session.py:68 msgid "Terminal" msgstr "ターミナル" @@ -2552,16 +2557,16 @@ msgstr "ユーザーログインログ" msgid "Session key" msgstr "セッションID" -#: audits/models.py:306 +#: audits/models.py:305 msgid "User session" msgstr "ユーザーセッション" -#: audits/models.py:308 +#: audits/models.py:307 msgid "Offline user session" msgstr "オフラインユーザセッション" #: audits/serializers.py:33 ops/models/adhoc.py:25 ops/models/base.py:16 -#: ops/models/base.py:53 ops/models/job.py:145 ops/models/job.py:233 +#: ops/models/base.py:53 ops/models/job.py:146 ops/models/job.py:234 #: ops/models/playbook.py:30 terminal/models/session/sharing.py:25 msgid "Creator" msgstr "作成者" @@ -2631,7 +2636,7 @@ msgstr "本を飛ばす" msgid "Slack" msgstr "" -#: audits/signal_handlers/login_log.py:40 authentication/views/dingtalk.py:160 +#: audits/signal_handlers/login_log.py:40 authentication/views/dingtalk.py:161 #: authentication/views/login.py:83 notifications/backends/__init__.py:12 #: settings/serializers/auth/dingtalk.py:10 users/models/user.py:750 #: users/models/user.py:856 @@ -2648,11 +2653,11 @@ msgstr "仮パスワード" msgid "Passkey" msgstr "Passkey" -#: audits/tasks.py:101 +#: audits/tasks.py:109 msgid "Clean audits session task log" msgstr "資産監査セッションタスクログのクリーンアップ" -#: audits/tasks.py:114 +#: audits/tasks.py:123 msgid "Upload FTP file to external storage" msgstr "外部ストレージへのFTPファイルのアップロード" @@ -2699,12 +2704,12 @@ msgstr "ACL アクションはレビューです" msgid "Current user not support mfa type: {}" msgstr "現在のユーザーはmfaタイプをサポートしていません: {}" -#: authentication/api/password.py:33 terminal/api/session/session.py:305 -#: users/views/profile/reset.py:62 +#: authentication/api/password.py:33 terminal/api/session/session.py:325 +#: users/views/profile/reset.py:63 msgid "User does not exist: {}" msgstr "ユーザーが存在しない: {}" -#: authentication/api/password.py:33 users/views/profile/reset.py:163 +#: authentication/api/password.py:33 users/views/profile/reset.py:164 msgid "No user matched" msgstr "ユーザーにマッチしなかった" @@ -2718,8 +2723,8 @@ msgstr "" #: authentication/api/password.py:65 #: authentication/templates/authentication/login.html:361 -#: users/templates/users/forgot_password.html:27 -#: users/templates/users/forgot_password.html:28 +#: users/templates/users/forgot_password.html:41 +#: users/templates/users/forgot_password.html:42 #: users/templates/users/forgot_password_previewing.html:13 #: users/templates/users/forgot_password_previewing.html:14 msgid "Forgot password" @@ -2730,25 +2735,25 @@ msgid "Authentication" msgstr "認証" #: authentication/backends/custom.py:59 -#: authentication/backends/oauth2/backends.py:170 +#: authentication/backends/oauth2/backends.py:173 msgid "User invalid, disabled or expired" msgstr "ユーザーが無効、無効、または期限切れです" -#: authentication/backends/drf.py:50 +#: authentication/backends/drf.py:52 msgid "Invalid token header. No credentials provided." msgstr "無効なトークンヘッダー。資格情報は提供されていません。" -#: authentication/backends/drf.py:53 +#: authentication/backends/drf.py:55 msgid "Invalid token header. Sign string should not contain spaces." msgstr "無効なトークンヘッダー。記号文字列にはスペースを含めないでください。" -#: authentication/backends/drf.py:59 +#: authentication/backends/drf.py:61 msgid "" "Invalid token header. Sign string should not contain invalid characters." msgstr "" "無効なトークンヘッダー。署名文字列に無効な文字を含めることはできません。" -#: authentication/backends/drf.py:72 +#: authentication/backends/drf.py:74 msgid "Invalid token or cache refreshed." msgstr "無効なトークンまたはキャッシュの更新。" @@ -2923,8 +2928,8 @@ msgstr "企業の微信はすでにバインドされています" msgid "WeCom is not bound" msgstr "企業の微信をバインドしていません" -#: authentication/errors/mfa.py:28 authentication/views/dingtalk.py:212 -#: authentication/views/dingtalk.py:254 +#: authentication/errors/mfa.py:28 authentication/views/dingtalk.py:213 +#: authentication/views/dingtalk.py:255 msgid "DingTalk is not bound" msgstr "DingTalkはバインドされていません" @@ -3035,8 +3040,8 @@ msgstr "メッセージ検証コードが無効" #: authentication/mfa/sms.py:12 authentication/serializers/password_mfa.py:16 #: authentication/serializers/password_mfa.py:24 #: settings/serializers/auth/sms.py:32 users/forms/profile.py:104 -#: users/forms/profile.py:109 users/templates/users/forgot_password.html:112 -#: users/views/profile/reset.py:99 +#: users/forms/profile.py:109 users/templates/users/forgot_password.html:155 +#: users/views/profile/reset.py:100 msgid "SMS" msgstr "メッセージ" @@ -3077,7 +3082,7 @@ msgid "Please change your password" msgstr "パスワードを変更してください" #: authentication/models/access_key.py:22 -#: terminal/models/component/endpoint.py:96 +#: terminal/models/component/endpoint.py:110 msgid "IP group" msgstr "IP グループ" @@ -3229,12 +3234,12 @@ msgstr "アクション" #: authentication/serializers/connection_token.py:42 #: perms/serializers/permission.py:40 perms/serializers/permission.py:60 -#: users/serializers/user.py:97 users/serializers/user.py:171 +#: users/serializers/user.py:97 users/serializers/user.py:173 msgid "Is expired" msgstr "期限切れです" #: authentication/serializers/password_mfa.py:29 -#: users/templates/users/forgot_password.html:108 +#: users/templates/users/forgot_password.html:151 msgid "The {} cannot be empty" msgstr "{} 空にしてはならない" @@ -3244,7 +3249,7 @@ msgstr "Access IP" #: authentication/serializers/token.py:92 perms/serializers/permission.py:39 #: perms/serializers/permission.py:61 users/serializers/user.py:98 -#: users/serializers/user.py:168 +#: users/serializers/user.py:170 msgid "Is valid" msgstr "有効です" @@ -3374,7 +3379,7 @@ msgstr "新しいものを要求する" #: authentication/templates/authentication/_msg_reset_password_code.html:12 #: terminal/models/session/sharing.py:27 terminal/models/session/sharing.py:97 #: terminal/templates/terminal/_msg_session_sharing.html:12 -#: users/forms/profile.py:107 users/templates/users/forgot_password.html:66 +#: users/forms/profile.py:107 users/templates/users/forgot_password.html:97 msgid "Verify code" msgstr "コードの確認" @@ -3422,7 +3427,7 @@ msgstr "" "能性があります" #: authentication/templates/authentication/auth_fail_flash_message_standalone.html:28 -#: templates/flash_message_standalone.html:28 tickets/const.py:17 +#: templates/flash_message_standalone.html:28 tickets/const.py:18 msgid "Cancel" msgstr "キャンセル" @@ -3449,7 +3454,7 @@ msgstr "MFA マルチファクタ認証" #: authentication/templates/authentication/login_mfa.html:19 #: users/templates/users/user_otp_check_password.html:12 #: users/templates/users/user_otp_enable_bind.html:24 -#: users/templates/users/user_otp_enable_install_app.html:29 +#: users/templates/users/user_otp_enable_install_app.html:31 #: users/templates/users/user_verify_mfa.html:30 msgid "Next" msgstr "次へ" @@ -3515,7 +3520,7 @@ msgstr "バインド%s成功" msgid "DingTalk Error, Please contact your system administrator" msgstr "DingTalkエラー、システム管理者に連絡してください" -#: authentication/views/dingtalk.py:45 authentication/views/dingtalk.py:211 +#: authentication/views/dingtalk.py:45 authentication/views/dingtalk.py:212 msgid "DingTalk Error" msgstr "DingTalkエラー" @@ -3529,27 +3534,27 @@ msgstr "システム設定が正しくありません。管理者に連絡して msgid "DingTalk is already bound" msgstr "DingTalkはすでにバインドされています" -#: authentication/views/dingtalk.py:129 +#: authentication/views/dingtalk.py:130 msgid "Invalid user_id" msgstr "無効なuser_id" -#: authentication/views/dingtalk.py:145 +#: authentication/views/dingtalk.py:146 msgid "DingTalk query user failed" msgstr "DingTalkクエリユーザーが失敗しました" -#: authentication/views/dingtalk.py:154 +#: authentication/views/dingtalk.py:155 msgid "The DingTalk is already bound to another user" msgstr "DingTalkはすでに別のユーザーにバインドされています" -#: authentication/views/dingtalk.py:161 +#: authentication/views/dingtalk.py:162 msgid "Binding DingTalk successfully" msgstr "DingTalkのバインドに成功" -#: authentication/views/dingtalk.py:213 authentication/views/dingtalk.py:248 +#: authentication/views/dingtalk.py:214 authentication/views/dingtalk.py:249 msgid "Failed to get user from DingTalk" msgstr "DingTalkからユーザーを取得できませんでした" -#: authentication/views/dingtalk.py:255 +#: authentication/views/dingtalk.py:256 msgid "Please login with a password and then bind the DingTalk" msgstr "パスワードでログインし、DingTalkをバインドしてください" @@ -3649,8 +3654,8 @@ msgstr "タイミングトリガー" msgid "Ready" msgstr "の準備を" -#: common/const/choices.py:16 terminal/const.py:77 tickets/const.py:29 -#: tickets/const.py:39 +#: common/const/choices.py:16 terminal/const.py:77 tickets/const.py:30 +#: tickets/const.py:40 msgid "Pending" msgstr "未定" @@ -3704,7 +3709,7 @@ msgstr "テキストフィールドへのマーシャルデータ" msgid "Encrypt field using Secret Key" msgstr "Secret Keyを使用したフィールドの暗号化" -#: common/db/fields.py:573 +#: common/db/fields.py:580 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " @@ -3714,15 +3719,15 @@ msgstr "" "{'type':'ids','ids':[]}或 #タイプ:属性、属性:[#名前:ip、照合:正確、" "値:1.1.1.1}" -#: common/db/fields.py:580 +#: common/db/fields.py:587 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "無効なタイプです。all、ids、またはattrsでなければなりません" -#: common/db/fields.py:583 +#: common/db/fields.py:590 msgid "Invalid ids for ids, should be a list" msgstr "無効なID、リストでなければなりません" -#: common/db/fields.py:585 common/db/fields.py:590 +#: common/db/fields.py:592 common/db/fields.py:597 #: common/serializers/fields.py:133 tickets/serializers/ticket/common.py:58 #: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:79 @@ -3730,11 +3735,11 @@ msgstr "無効なID、リストでなければなりません" msgid "This field is required." msgstr "このフィールドは必須です。" -#: common/db/fields.py:588 common/db/fields.py:593 +#: common/db/fields.py:595 common/db/fields.py:600 msgid "Invalid attrs, should be a list of dict" msgstr "無効な属性、dictリストでなければなりません" -#: common/db/fields.py:595 +#: common/db/fields.py:602 msgid "Invalid attrs, should be has name and value" msgstr "名前と値が必要な無効な属性" @@ -4060,23 +4065,23 @@ msgstr "Ansible 無効" msgid "Skip hosts below:" msgstr "次のホストをスキップします: " -#: ops/api/celery.py:65 ops/api/celery.py:80 +#: ops/api/celery.py:66 ops/api/celery.py:81 msgid "Waiting task start" msgstr "タスク開始待ち" -#: ops/api/celery.py:203 +#: ops/api/celery.py:246 msgid "Task {} not found" msgstr "タスクは存在しません" -#: ops/api/celery.py:208 +#: ops/api/celery.py:251 msgid "Task {} args or kwargs error" msgstr "タスク実行パラメータエラー" -#: ops/api/job.py:132 +#: ops/api/job.py:135 msgid "Duplicate file exists" msgstr "重複したファイルが存在する" -#: ops/api/job.py:137 +#: ops/api/job.py:140 #, python-brace-format msgid "" "File size exceeds maximum limit. Please select a file smaller than {limit}MB" @@ -4084,6 +4089,11 @@ msgstr "" "ファイルサイズが最大制限を超えています。{limit}MB より小さいファイルを選択し" "てください。" +#: ops/api/job.py:204 +msgid "" +"The task is being created and cannot be interrupted. Please try again later." +msgstr "タスクを作成中で、中断できません。後でもう一度お試しください。" + #: ops/api/playbook.py:39 msgid "Currently playbook is being used in a job" msgstr "現在プレイブックは1つのジョブで使用されています" @@ -4152,7 +4162,7 @@ msgstr "VCS" msgid "Adhoc" msgstr "コマンド#コマンド#" -#: ops/const.py:39 ops/models/job.py:143 +#: ops/const.py:39 ops/models/job.py:144 msgid "Playbook" msgstr "Playbook" @@ -4237,11 +4247,11 @@ msgstr "定期的または定期的に設定を行う必要があります" msgid "Pattern" msgstr "パターン" -#: ops/models/adhoc.py:23 ops/models/job.py:140 +#: ops/models/adhoc.py:23 ops/models/job.py:141 msgid "Module" msgstr "モジュール" -#: ops/models/adhoc.py:24 ops/models/celery.py:58 ops/models/job.py:138 +#: ops/models/adhoc.py:24 ops/models/celery.py:81 ops/models/job.py:139 #: terminal/models/component/task.py:14 msgid "Args" msgstr "アルグ" @@ -4260,12 +4270,12 @@ msgstr "最後の実行" msgid "Date last run" msgstr "最終実行日" -#: ops/models/base.py:51 ops/models/job.py:231 +#: ops/models/base.py:51 ops/models/job.py:232 #: xpack/plugins/cloud/models.py:202 msgid "Result" msgstr "結果" -#: ops/models/base.py:52 ops/models/job.py:232 +#: ops/models/base.py:52 ops/models/job.py:233 msgid "Summary" msgstr "概要" @@ -4273,68 +4283,68 @@ msgstr "概要" msgid "Date last publish" msgstr "発売日" -#: ops/models/celery.py:47 +#: ops/models/celery.py:70 msgid "Celery Task" msgstr "Celery タスク#タスク#" -#: ops/models/celery.py:50 +#: ops/models/celery.py:73 msgid "Can view task monitor" msgstr "タスクモニターを表示できます" -#: ops/models/celery.py:59 terminal/models/component/task.py:15 +#: ops/models/celery.py:82 terminal/models/component/task.py:15 msgid "Kwargs" msgstr "クワーグ" -#: ops/models/celery.py:61 terminal/models/session/sharing.py:128 -#: tickets/const.py:25 +#: ops/models/celery.py:84 terminal/models/session/sharing.py:128 +#: tickets/const.py:26 msgid "Finished" msgstr "終了" -#: ops/models/celery.py:62 +#: ops/models/celery.py:85 msgid "Date published" msgstr "発売日" -#: ops/models/celery.py:87 +#: ops/models/celery.py:110 msgid "Celery Task Execution" msgstr "Celery タスク実行" -#: ops/models/job.py:141 +#: ops/models/job.py:142 msgid "Chdir" msgstr "実行ディレクトリ" -#: ops/models/job.py:142 +#: ops/models/job.py:143 msgid "Timeout (Seconds)" msgstr "タイムアウト(秒)" -#: ops/models/job.py:147 +#: ops/models/job.py:148 msgid "Use Parameter Define" msgstr "パラメータ定義を使用する" -#: ops/models/job.py:148 +#: ops/models/job.py:149 msgid "Parameters define" msgstr "パラメータ定義" -#: ops/models/job.py:149 +#: ops/models/job.py:150 msgid "Runas" msgstr "ユーザーとして実行" -#: ops/models/job.py:151 +#: ops/models/job.py:152 msgid "Runas policy" msgstr "ユーザー ポリシー" -#: ops/models/job.py:215 +#: ops/models/job.py:216 msgid "Job" msgstr "ジョブ#ジョブ#" -#: ops/models/job.py:238 +#: ops/models/job.py:239 msgid "Material" msgstr "Material" -#: ops/models/job.py:240 +#: ops/models/job.py:241 msgid "Material Type" msgstr "Material を選択してオプションを設定します。" -#: ops/models/job.py:557 +#: ops/models/job.py:567 msgid "Job Execution" msgstr "ジョブ実行" @@ -4378,15 +4388,15 @@ msgstr "{max_threshold} を超えるCPUロード: => {value}" msgid "Run after save" msgstr "保存後に実行" -#: ops/serializers/job.py:62 +#: ops/serializers/job.py:69 msgid "Job type" msgstr "タスクの種類" -#: ops/serializers/job.py:65 terminal/serializers/session.py:53 +#: ops/serializers/job.py:72 terminal/serializers/session.py:55 msgid "Is finished" msgstr "終了しました" -#: ops/serializers/job.py:66 +#: ops/serializers/job.py:73 #: settings/templates/ldap/_msg_import_ldap_user.html:7 msgid "Time cost" msgstr "時を過ごす" @@ -4520,7 +4530,7 @@ msgstr "グローバル組織を表示できます" msgid "Can view all joined org" msgstr "参加しているすべての組織を表示できます" -#: orgs/models.py:233 +#: orgs/models.py:236 msgid "Can not delete virtual org" msgstr "仮想組織を削除できませんでした" @@ -4605,7 +4615,7 @@ msgid "today" msgstr "今日" #: perms/notifications.py:12 perms/notifications.py:44 -#: settings/serializers/feature.py:117 +#: settings/serializers/feature.py:118 msgid "day" msgstr "日" @@ -4666,7 +4676,7 @@ msgstr "内部の役割は、破壊することはできません" msgid "The role has been bound to users, can't be destroy" msgstr "ロールはユーザーにバインドされており、破壊することはできません" -#: rbac/api/role.py:100 +#: rbac/api/role.py:102 msgid "Internal role, can't be update" msgstr "内部ロール、更新できません" @@ -4877,21 +4887,13 @@ msgstr "テストの成功" msgid "Test mail sent to {}, please check" msgstr "{}に送信されたテストメールを確認してください" -#: settings/api/ldap.py:101 +#: settings/api/ldap.py:89 msgid "" "Users are not synchronized, please click the user synchronization button" msgstr "" "ユーザーは同期されていません。「ユーザーを同期」ボタンをクリックしてくださ" "い。" -#: settings/api/ldap.py:137 -msgid "Get ldap users is None" -msgstr "Ldapユーザーを取得するにはNone" - -#: settings/api/ldap.py:147 -msgid "Imported {} users successfully (Organization: {})" -msgstr "{} 人のユーザーを正常にインポートしました (組織: {})" - #: settings/api/sms.py:142 msgid "Invalid SMS platform" msgstr "無効なショートメッセージプラットフォーム" @@ -5504,26 +5506,30 @@ msgid "Operate log keep days (day)" msgstr "ログ管理日を操作する(天)" #: settings/serializers/cleaning.py:27 +msgid "password change log keep days (day)" +msgstr "パスワード変更ログ(天)" + +#: settings/serializers/cleaning.py:31 msgid "FTP log keep days (day)" msgstr "ダウンロードのアップロード(天)" -#: settings/serializers/cleaning.py:31 +#: settings/serializers/cleaning.py:35 msgid "Cloud sync record keep days (day)" msgstr "クラウド同期レコードは日数を保持します(天)" -#: settings/serializers/cleaning.py:35 +#: settings/serializers/cleaning.py:39 msgid "job execution keep days (day)" msgstr "ジョブセンターの実行履歴 (天) " -#: settings/serializers/cleaning.py:39 +#: settings/serializers/cleaning.py:43 msgid "Activity log keep days (day)" msgstr "活動ログは日数を保持します(天)" -#: settings/serializers/cleaning.py:42 +#: settings/serializers/cleaning.py:46 msgid "Session keep duration (day)" msgstr "セッション維持期間(天)" -#: settings/serializers/cleaning.py:44 +#: settings/serializers/cleaning.py:48 msgid "" "Session, record, command will be delete if more than duration, only in " "database, OSS will not be affected." @@ -5594,39 +5600,43 @@ msgstr "GPTモデル" msgid "Enable tickets" msgstr "チケットを有効にする" -#: settings/serializers/feature.py:114 +#: settings/serializers/feature.py:112 +msgid "No login approval" +msgstr "ログイン承認なし" + +#: settings/serializers/feature.py:115 msgid "Ticket authorize default time" msgstr "デフォルト製造オーダ承認時間" -#: settings/serializers/feature.py:117 +#: settings/serializers/feature.py:118 msgid "hour" msgstr "時" -#: settings/serializers/feature.py:118 +#: settings/serializers/feature.py:119 msgid "Ticket authorize default time unit" msgstr "デフォルト製造オーダ承認時間単位" -#: settings/serializers/feature.py:123 +#: settings/serializers/feature.py:124 msgid "Feature" msgstr "機能" -#: settings/serializers/feature.py:126 +#: settings/serializers/feature.py:127 msgid "Operation center" msgstr "職業センター" -#: settings/serializers/feature.py:127 +#: settings/serializers/feature.py:128 msgid "Allow user run batch command or not using ansible" msgstr "ユーザー実行バッチコマンドを許可するか、ansibleを使用しない" -#: settings/serializers/feature.py:131 +#: settings/serializers/feature.py:132 msgid "Operation center command blacklist" msgstr "オペレーション センター コマンド ブラックリスト" -#: settings/serializers/feature.py:132 +#: settings/serializers/feature.py:133 msgid "Commands that are not allowed execute." msgstr "実行が許可されていないコマンド" -#: settings/serializers/feature.py:137 +#: settings/serializers/feature.py:138 #: terminal/models/virtualapp/provider.py:17 #: terminal/models/virtualapp/virtualapp.py:36 #: terminal/models/virtualapp/virtualapp.py:97 @@ -5634,7 +5644,7 @@ msgstr "実行が許可されていないコマンド" msgid "Virtual app" msgstr "仮想アプリケーション" -#: settings/serializers/feature.py:140 +#: settings/serializers/feature.py:141 msgid "Enable virtual app" msgstr "仮想アプリケーションの有効化" @@ -6112,6 +6122,10 @@ msgstr "組織が同期されました" msgid "Synced User" msgstr "同期されたユーザー" +#: settings/templates/ldap/_msg_import_ldap_user.html:22 +msgid "No user synchronization required" +msgstr "ユーザーの同期は必要ありません" + #: settings/utils/ldap.py:494 msgid "ldap:// or ldaps:// protocol is used." msgstr "ldap:// または ldaps:// プロトコルが使用されます。" @@ -6213,6 +6227,14 @@ msgstr "認証に失敗しました (不明): {}" msgid "Authentication success: {}" msgstr "認証成功: {}" +#: settings/ws.py:236 +msgid "Get ldap users is None" +msgstr "Ldapユーザーを取得するにはNone" + +#: settings/ws.py:246 +msgid "Imported {} users successfully (Organization: {})" +msgstr "{} 人のユーザーを正常にインポートしました (組織: {})" + #: templates/_csv_import_export.html:8 msgid "Export" msgstr "エクスポート" @@ -6356,12 +6378,12 @@ msgid "Send verification code" msgstr "確認コードを送信" #: templates/_mfa_login_field.html:106 -#: users/templates/users/forgot_password.html:130 +#: users/templates/users/forgot_password.html:174 msgid "Wait: " msgstr "待つ:" #: templates/_mfa_login_field.html:116 -#: users/templates/users/forgot_password.html:146 +#: users/templates/users/forgot_password.html:190 msgid "The verification code has been sent" msgstr "確認コードが送信されました" @@ -6415,13 +6437,13 @@ msgstr "" msgid "Offline video player" msgstr "オフラインビデオプレーヤー" -#: terminal/api/applet/applet.py:50 terminal/api/applet/applet.py:53 +#: terminal/api/applet/applet.py:52 terminal/api/applet/applet.py:55 #: terminal/api/virtualapp/virtualapp.py:43 #: terminal/api/virtualapp/virtualapp.py:46 msgid "Invalid zip file" msgstr "zip ファイルが無効です" -#: terminal/api/applet/applet.py:72 +#: terminal/api/applet/applet.py:74 msgid "This is enterprise edition applet" msgstr "これはエンタープライズ版アプレットです" @@ -6461,20 +6483,20 @@ msgstr "テストに失敗しました:構成を確認してください" msgid "Have online sessions" msgstr "オンラインセッションを持つ" -#: terminal/api/session/session.py:46 +#: terminal/api/session/session.py:48 #, python-format msgid "User %s %s session %s replay" msgstr "ユーザー%s %sこのセッション %s の録画です" -#: terminal/api/session/session.py:297 +#: terminal/api/session/session.py:317 msgid "Session does not exist: {}" msgstr "セッションが存在しません: {}" -#: terminal/api/session/session.py:300 +#: terminal/api/session/session.py:320 msgid "Session is finished or the protocol not supported" msgstr "セッションが終了したか、プロトコルがサポートされていません" -#: terminal/api/session/session.py:313 +#: terminal/api/session/session.py:333 msgid "User does not have permission" msgstr "ユーザーに権限がありません" @@ -6725,14 +6747,14 @@ msgid "SQLServer port" msgstr "SQLServer ポート" #: terminal/models/component/endpoint.py:30 -#: terminal/models/component/endpoint.py:103 +#: terminal/models/component/endpoint.py:117 #: 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 "エンドポイント" -#: terminal/models/component/endpoint.py:109 +#: terminal/models/component/endpoint.py:123 msgid "Endpoint rule" msgstr "エンドポイントルール" @@ -6769,28 +6791,28 @@ msgid "Default storage" msgstr "デフォルトのストレージ" #: terminal/models/component/storage.py:140 -#: terminal/models/component/terminal.py:90 +#: terminal/models/component/terminal.py:91 msgid "Command storage" msgstr "コマンドストレージ" #: terminal/models/component/storage.py:204 -#: terminal/models/component/terminal.py:91 +#: terminal/models/component/terminal.py:92 msgid "Replay storage" msgstr "再生ストレージ" -#: terminal/models/component/terminal.py:87 +#: terminal/models/component/terminal.py:88 msgid "type" msgstr "タイプ" -#: terminal/models/component/terminal.py:89 terminal/serializers/command.py:76 +#: terminal/models/component/terminal.py:90 terminal/serializers/command.py:76 msgid "Remote Address" msgstr "リモートアドレス" -#: terminal/models/component/terminal.py:92 +#: terminal/models/component/terminal.py:93 msgid "Application User" msgstr "ユーザーの適用" -#: terminal/models/component/terminal.py:176 +#: terminal/models/component/terminal.py:177 msgid "Can view terminal config" msgstr "ターミナル構成を表示できます" @@ -6822,11 +6844,11 @@ msgstr "ログイン元" msgid "Replay" msgstr "リプレイ" -#: terminal/models/session/session.py:47 terminal/serializers/session.py:65 +#: terminal/models/session/session.py:47 terminal/serializers/session.py:67 msgid "Command amount" msgstr "コマンド量" -#: terminal/models/session/session.py:48 terminal/serializers/session.py:28 +#: terminal/models/session/session.py:48 terminal/serializers/session.py:30 msgid "Error reason" msgstr "間違った理由" @@ -7145,31 +7167,31 @@ msgstr "" msgid "Asset IP" msgstr "資産 IP" -#: terminal/serializers/session.py:23 terminal/serializers/session.py:50 +#: terminal/serializers/session.py:25 terminal/serializers/session.py:52 msgid "Can replay" msgstr "再生できます" -#: terminal/serializers/session.py:24 terminal/serializers/session.py:51 +#: terminal/serializers/session.py:26 terminal/serializers/session.py:53 msgid "Can join" msgstr "参加できます" -#: terminal/serializers/session.py:25 terminal/serializers/session.py:54 +#: terminal/serializers/session.py:27 terminal/serializers/session.py:56 msgid "Can terminate" msgstr "終了できます" -#: terminal/serializers/session.py:46 +#: terminal/serializers/session.py:48 msgid "User ID" msgstr "ユーザーID" -#: terminal/serializers/session.py:47 +#: terminal/serializers/session.py:49 msgid "Asset ID" msgstr "資産ID" -#: terminal/serializers/session.py:48 +#: terminal/serializers/session.py:50 msgid "Login from display" msgstr "表示からのログイン" -#: terminal/serializers/session.py:55 +#: terminal/serializers/session.py:57 msgid "Terminal display" msgstr "ターミナルディスプレイ" @@ -7276,6 +7298,99 @@ msgstr "コンテナステータス" msgid "Container Ports" msgstr "コンテナポート" +#: terminal/session_lifecycle.py:30 +#, python-format +msgid "Connect to asset %s success" +msgstr "アセット %s への接続に成功しました" + +#: terminal/session_lifecycle.py:38 +#, python-format +msgid "Connect to asset %s finished: %s" +msgstr "アセット %s への接続が完了しました: %s" + +#: terminal/session_lifecycle.py:48 +#, python-format +msgid "User %s create share link" +msgstr "ユーザー %s が共有リンクを作成しました" + +#: terminal/session_lifecycle.py:57 +#, python-format +msgid "User %s join session" +msgstr "ユーザー %s がセッションに参加しました" + +#: terminal/session_lifecycle.py:69 +#, python-format +msgid "User %s leave session" +msgstr "ユーザー %s がセッションを離れました" + +#: terminal/session_lifecycle.py:81 +#, python-format +msgid "User %s join to monitor session" +msgstr "ユーザー %s がモニターセッションに参加しました" + +#: terminal/session_lifecycle.py:93 +#, python-format +msgid "User %s exit to monitor session" +msgstr "ユーザー %s がモニターセッションを離れました" + +#: terminal/session_lifecycle.py:105 +msgid "Replay start to convert" +msgstr "リプレイの変換が開始されました" + +#: terminal/session_lifecycle.py:113 +msgid "Replay successfully converted to MP4 format" +msgstr "リプレイが正常にMP4形式に変換されました" + +#: terminal/session_lifecycle.py:121 +#, python-format +msgid "Replay failed to convert to MP4 format: %s" +msgstr "リプレイのMP4形式への変換に失敗しました: %s" + +#: terminal/session_lifecycle.py:129 +msgid "Replay start to upload" +msgstr "リプレイのアップロードが開始されました" + +#: terminal/session_lifecycle.py:137 +msgid "Replay successfully uploaded" +msgstr "リプレイが正常にアップロードされました" + +#: terminal/session_lifecycle.py:145 +#, python-format +msgid "Replay failed to upload: %s" +msgstr "リプレイのアップロードに失敗しました: %s" + +#: terminal/session_lifecycle.py:152 +msgid "connect failed" +msgstr "接続に失敗しました" + +#: terminal/session_lifecycle.py:153 +msgid "connection disconnect" +msgstr "接続が切断されました" + +#: terminal/session_lifecycle.py:154 +msgid "user closed" +msgstr "ユーザーが閉じました" + +#: terminal/session_lifecycle.py:155 +msgid "idle disconnect" +msgstr "アイドル状態で切断されました" + +#: terminal/session_lifecycle.py:156 +msgid "admin terminated" +msgstr "管理者によって切断されました" + +#: terminal/session_lifecycle.py:157 +msgid "maximum session time has been reached" +msgstr "最大セッション時間に達しました" + +#: terminal/session_lifecycle.py:158 +msgid "permission has expired" +msgstr "許可が期限切れです" + +#: terminal/session_lifecycle.py:159 +msgid "storage is null" +msgstr "ストレージが空です" + #: terminal/tasks.py:33 msgid "Periodic delete terminal status" msgstr "端末の状態を定期的にクリーンアップする" @@ -7334,54 +7449,66 @@ msgstr "応募者" msgid "Tickets" msgstr "チケット" -#: tickets/const.py:9 +#: tickets/const.py:10 msgid "Apply for asset" msgstr "資産の申請" -#: tickets/const.py:16 tickets/const.py:24 tickets/const.py:43 +#: tickets/const.py:17 tickets/const.py:25 tickets/const.py:44 msgid "Open" msgstr "オープン" -#: tickets/const.py:18 tickets/const.py:31 +#: tickets/const.py:19 tickets/const.py:32 msgid "Reopen" msgstr "再オープン" -#: tickets/const.py:19 tickets/const.py:32 +#: tickets/const.py:20 tickets/const.py:33 msgid "Approved" msgstr "承認済み" -#: tickets/const.py:20 tickets/const.py:33 +#: tickets/const.py:21 tickets/const.py:34 msgid "Rejected" msgstr "拒否" -#: tickets/const.py:30 tickets/const.py:38 +#: tickets/const.py:31 tickets/const.py:39 msgid "Closed" msgstr "クローズ" -#: tickets/const.py:50 +#: tickets/const.py:51 msgid "One level" msgstr "1つのレベル" -#: tickets/const.py:51 +#: tickets/const.py:52 msgid "Two level" msgstr "2つのレベル" -#: tickets/const.py:55 +#: tickets/const.py:56 msgid "Org admin" msgstr "Org admin" -#: tickets/const.py:56 +#: tickets/const.py:57 msgid "Custom user" msgstr "カスタムユーザー" -#: tickets/const.py:57 +#: tickets/const.py:58 msgid "Super admin" msgstr "スーパー管理者" -#: tickets/const.py:58 +#: tickets/const.py:59 msgid "Super admin and org admin" msgstr "スーパーadminとorg admin" +#: tickets/const.py:63 +msgid "All assets" +msgstr "すべての資産" + +#: tickets/const.py:64 +msgid "Permed assets" +msgstr "許可された資産" + +#: tickets/const.py:65 +msgid "Permed valid assets" +msgstr "有効な許可を受けた資産" + #: tickets/errors.py:9 msgid "Ticket already closed" msgstr "チケットはすでに閉じています" @@ -7557,19 +7684,19 @@ msgstr "チケット基本情報" msgid "Ticket applied info" msgstr "チケット適用情報" -#: tickets/notifications.py:111 +#: tickets/notifications.py:105 msgid "Your has a new ticket, applicant - {}" msgstr "新しいチケットがあります- {}" -#: tickets/notifications.py:115 +#: tickets/notifications.py:109 msgid "{}: New Ticket - {} ({})" msgstr "新しいチケット- {} ({})" -#: tickets/notifications.py:159 +#: tickets/notifications.py:155 msgid "Your ticket has been processed, processor - {}" msgstr "チケットが処理されました。プロセッサー- {}" -#: tickets/notifications.py:163 +#: tickets/notifications.py:159 msgid "Ticket has processed - {} ({})" msgstr "チケットが処理済み- {} ({})" @@ -7635,7 +7762,7 @@ msgid "Ticket information" msgstr "作業指示情報" #: tickets/templates/tickets/approve_check_password.html:28 -#: tickets/views/approve.py:40 tickets/views/approve.py:77 +#: tickets/views/approve.py:43 tickets/views/approve.py:80 msgid "Ticket approval" msgstr "作業指示の承認" @@ -7643,26 +7770,26 @@ msgstr "作業指示の承認" msgid "Approval" msgstr "承認" -#: tickets/views/approve.py:41 +#: tickets/views/approve.py:44 msgid "" "This ticket does not exist, the process has ended, or this link has expired" msgstr "" "このワークシートが存在しないか、ワークシートが終了したか、このリンクが無効に" "なっています" -#: tickets/views/approve.py:69 +#: tickets/views/approve.py:72 msgid "Click the button below to approve or reject" msgstr "下のボタンをクリックして同意または拒否。" -#: tickets/views/approve.py:78 +#: tickets/views/approve.py:81 msgid "After successful authentication, this ticket can be approved directly" msgstr "認証に成功した後、作業指示書は直接承認することができる。" -#: tickets/views/approve.py:95 +#: tickets/views/approve.py:105 msgid "Illegal approval action" msgstr "無効な承認アクション" -#: tickets/views/approve.py:108 +#: tickets/views/approve.py:119 msgid "This user is not authorized to approve this ticket" msgstr "このユーザーはこの作業指示を承認する権限がありません" @@ -7818,7 +7945,7 @@ msgstr "ユーザー設定" msgid "Force enable" msgstr "強制有効" -#: users/models/user.py:812 users/serializers/user.py:169 +#: users/models/user.py:812 users/serializers/user.py:171 msgid "Is service account" msgstr "サービスアカウントです" @@ -7830,7 +7957,7 @@ msgstr "アバター" msgid "Wechat" msgstr "微信" -#: users/models/user.py:820 users/serializers/user.py:106 +#: users/models/user.py:820 users/serializers/user.py:108 msgid "Phone" msgstr "電話" @@ -7841,7 +7968,7 @@ msgstr "OTP 秘密" # msgid "Private key" # msgstr "ssh秘密鍵" #: users/models/user.py:838 users/serializers/profile.py:128 -#: users/serializers/user.py:166 +#: users/serializers/user.py:168 msgid "Is first login" msgstr "最初のログインです" @@ -7892,7 +8019,7 @@ msgstr "ユーザーパスワード履歴" msgid "Reset password" msgstr "パスワードのリセット" -#: users/notifications.py:85 users/views/profile/reset.py:230 +#: users/notifications.py:85 users/views/profile/reset.py:231 msgid "Reset password success" msgstr "パスワードのリセット成功" @@ -8035,35 +8162,43 @@ msgstr "MFAフォース有効化" msgid "Login blocked" msgstr "ログインがロックされました" -#: users/serializers/user.py:99 users/serializers/user.py:175 +#: users/serializers/user.py:99 users/serializers/user.py:177 msgid "Is OTP bound" msgstr "仮想MFAがバインドされているか" +#: users/serializers/user.py:100 +msgid "Super Administrator" +msgstr "スーパーアドミニストレーター" + #: users/serializers/user.py:101 +msgid "Organization Administrator" +msgstr "組織管理者" + +#: users/serializers/user.py:103 msgid "Can public key authentication" msgstr "公開鍵認証が可能" -#: users/serializers/user.py:170 +#: users/serializers/user.py:172 msgid "Is org admin" msgstr "組織管理者です" -#: users/serializers/user.py:172 +#: users/serializers/user.py:174 msgid "Avatar url" msgstr "アバターURL" -#: users/serializers/user.py:176 +#: users/serializers/user.py:178 msgid "MFA level" msgstr "MFA レベル" -#: users/serializers/user.py:287 +#: users/serializers/user.py:289 msgid "Select users" msgstr "ユーザーの選択" -#: users/serializers/user.py:288 +#: users/serializers/user.py:290 msgid "For security, only list several users" msgstr "セキュリティのために、複数のユーザーのみをリストします" -#: users/serializers/user.py:321 +#: users/serializers/user.py:323 msgid "name not unique" msgstr "名前が一意ではない" @@ -8158,28 +8293,28 @@ msgstr "あなたのssh公開鍵はサイト管理者によってリセットさ msgid "click here to set your password" msgstr "ここをクリックしてパスワードを設定してください" -#: users/templates/users/forgot_password.html:32 +#: users/templates/users/forgot_password.html:46 msgid "Input your email account, that will send a email to your" msgstr "あなたのメールを入力し、それはあなたにメールを送信します" -#: users/templates/users/forgot_password.html:35 +#: users/templates/users/forgot_password.html:49 msgid "" "Enter your mobile number and a verification code will be sent to your phone" msgstr "携帯電話番号を入力すると、認証コードが携帯電話に送信されます" -#: users/templates/users/forgot_password.html:57 +#: users/templates/users/forgot_password.html:71 msgid "Email account" msgstr "メールアドレス" -#: users/templates/users/forgot_password.html:61 +#: users/templates/users/forgot_password.html:92 msgid "Mobile number" msgstr "携帯番号" -#: users/templates/users/forgot_password.html:69 +#: users/templates/users/forgot_password.html:100 msgid "Send" msgstr "送信" -#: users/templates/users/forgot_password.html:73 +#: users/templates/users/forgot_password.html:104 #: users/templates/users/forgot_password_previewing.html:30 msgid "Submit" msgstr "送信" @@ -8273,7 +8408,7 @@ msgstr "Androidのダウンロード" msgid "iPhone downloads" msgstr "IPhoneのダウンロード" -#: users/templates/users/user_otp_enable_install_app.html:26 +#: users/templates/users/user_otp_enable_install_app.html:27 msgid "" "After installation, click the next step to enter the binding page (if " "installed, go to the next step directly)." @@ -8301,32 +8436,32 @@ msgstr "" msgid "Open MFA Authenticator and enter the 6-bit dynamic code" msgstr "MFA Authenticatorを開き、6ビットの動的コードを入力します" -#: users/views/profile/otp.py:85 +#: users/views/profile/otp.py:106 msgid "Already bound" msgstr "すでにバインド済み" -#: users/views/profile/otp.py:86 +#: users/views/profile/otp.py:107 msgid "MFA already bound, disable first, then bound" msgstr "" "MFAはすでにバインドされており、最初に無効にしてからバインドされています。" -#: users/views/profile/otp.py:113 +#: users/views/profile/otp.py:134 msgid "OTP enable success" msgstr "OTP有効化成功" -#: users/views/profile/otp.py:114 +#: users/views/profile/otp.py:135 msgid "OTP enable success, return login page" msgstr "OTP有効化成功、ログインページを返す" -#: users/views/profile/otp.py:156 +#: users/views/profile/otp.py:177 msgid "Disable OTP" msgstr "OTPの無効化" -#: users/views/profile/otp.py:162 +#: users/views/profile/otp.py:183 msgid "OTP disable success" msgstr "OTP無効化成功" -#: users/views/profile/otp.py:163 +#: users/views/profile/otp.py:184 msgid "OTP disable success, return login page" msgstr "OTP無効化成功、ログインページを返す" @@ -8334,7 +8469,7 @@ msgstr "OTP無効化成功、ログインページを返す" msgid "Password invalid" msgstr "パスワード無効" -#: users/views/profile/reset.py:65 +#: users/views/profile/reset.py:66 msgid "" "Non-local users can log in only from third-party platforms and cannot change " "their passwords: {}" @@ -8342,23 +8477,23 @@ msgstr "" "ローカル以外のユーザーは、サードパーティ プラットフォームからのログインのみが" "許可され、パスワードの変更はサポートされていません: {}" -#: users/views/profile/reset.py:185 users/views/profile/reset.py:196 +#: users/views/profile/reset.py:186 users/views/profile/reset.py:197 msgid "Token invalid or expired" msgstr "トークンが無効または期限切れ" -#: users/views/profile/reset.py:201 +#: users/views/profile/reset.py:202 msgid "User auth from {}, go there change password" msgstr "ユーザー認証ソース {}, 対応するシステムにパスワードを変更してください" -#: users/views/profile/reset.py:208 +#: users/views/profile/reset.py:209 msgid "* Your password does not meet the requirements" msgstr "* パスワードが要件を満たしていない" -#: users/views/profile/reset.py:214 +#: users/views/profile/reset.py:215 msgid "* The new password cannot be the last {} passwords" msgstr "* 新しいパスワードを最後の {} パスワードにすることはできません" -#: users/views/profile/reset.py:231 +#: users/views/profile/reset.py:232 msgid "Reset password success, return to login page" msgstr "パスワードの成功をリセットし、ログインページに戻る" @@ -8511,7 +8646,7 @@ msgstr "そして" msgid "Or" msgstr "または" -#: xpack/plugins/cloud/manager.py:56 +#: xpack/plugins/cloud/manager.py:57 msgid "Account unavailable" msgstr "利用できないアカウント" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index bf09fbd89..3905e0b73 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:19d3a111cc245f9a9d36b860fd95447df916ad66c918bef672bacdad6bc77a8f -size 140119 +oid sha256:e66a6fa05d25f1c502f95001b5ff0d0a310affd32eac939fd7b840845028074f +size 142298 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 73f1032a6..9bf7548c0 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: 2024-01-17 19:11+0800\n" +"POT-Creation-Date: 2024-02-27 16:09+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -21,6 +21,11 @@ msgstr "" msgid "The parameter 'action' must be [{}]" msgstr "参数 'action' 必须是 [{}]" +#: accounts/automations/change_secret/manager.py:201 +#, python-format +msgid "Success: %s, Failed: %s, Total: %s" +msgstr "成功: %s, 失败: %s, 总数: %s" + #: accounts/const/account.py:6 #: accounts/serializers/automations/change_secret.py:32 #: assets/models/_user.py:24 audits/signal_handlers/login_log.py:34 @@ -30,7 +35,7 @@ msgstr "参数 'action' 必须是 [{}]" #: settings/serializers/auth/ldap.py:25 settings/serializers/auth/ldap.py:47 #: settings/serializers/msg.py:35 terminal/serializers/storage.py:123 #: terminal/serializers/storage.py:142 users/forms/profile.py:22 -#: users/serializers/user.py:104 +#: users/serializers/user.py:106 #: users/templates/users/_msg_user_created.html:13 #: users/templates/users/user_password_verify.html:18 #: xpack/plugins/cloud/serializers/account_attrs.py:28 @@ -202,8 +207,8 @@ msgstr "仅创建" #: notifications/backends/__init__.py:10 settings/serializers/msg.py:22 #: settings/serializers/msg.py:64 users/forms/profile.py:102 #: users/forms/profile.py:109 users/models/user.py:802 -#: users/templates/users/forgot_password.html:117 -#: users/views/profile/reset.py:93 +#: users/templates/users/forgot_password.html:160 +#: users/views/profile/reset.py:94 msgid "Email" msgstr "邮箱" @@ -252,7 +257,7 @@ msgstr "用户 %s 查看/导出 了密码" #: perms/models/asset_permission.py:69 perms/serializers/permission.py:36 #: terminal/backends/command/models.py:17 terminal/models/session/session.py:31 #: terminal/notifications.py:155 terminal/serializers/command.py:17 -#: terminal/serializers/session.py:26 +#: terminal/serializers/session.py:28 #: terminal/templates/terminal/_msg_command_warning.html:4 #: terminal/templates/terminal/_msg_session_sharing.html:4 #: tickets/models/ticket/apply_asset.py:16 xpack/plugins/cloud/models.py:256 @@ -359,7 +364,7 @@ msgstr "账号备份计划" #: accounts/models/automations/backup_account.py:119 #: assets/models/automations/base.py:115 audits/models.py:65 -#: ops/models/base.py:55 ops/models/celery.py:63 ops/models/job.py:235 +#: ops/models/base.py:55 ops/models/celery.py:86 ops/models/job.py:236 #: ops/templates/ops/celery_task_log.html:75 #: perms/models/asset_permission.py:78 #: settings/templates/ldap/_msg_import_ldap_user.html:5 @@ -396,7 +401,7 @@ msgstr "原因" #: accounts/models/automations/backup_account.py:135 #: accounts/serializers/automations/change_secret.py:105 #: accounts/serializers/automations/change_secret.py:128 -#: ops/serializers/job.py:64 terminal/serializers/session.py:49 +#: ops/serializers/job.py:71 terminal/serializers/session.py:51 msgid "Is success" msgstr "是否成功" @@ -470,14 +475,14 @@ msgstr "开始日期" #: accounts/models/automations/change_secret.py:42 #: assets/models/automations/base.py:116 ops/models/base.py:56 -#: ops/models/celery.py:64 ops/models/job.py:236 +#: ops/models/celery.py:87 ops/models/job.py:237 #: terminal/models/applet/host.py:142 msgid "Date finished" msgstr "结束日期" #: accounts/models/automations/change_secret.py:43 #: assets/models/automations/base.py:113 audits/models.py:208 -#: audits/serializers.py:54 ops/models/base.py:49 ops/models/job.py:227 +#: audits/serializers.py:54 ops/models/base.py:49 ops/models/job.py:228 #: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:140 #: terminal/models/component/status.py:30 #: terminal/models/virtualapp/virtualapp.py:99 @@ -494,7 +499,7 @@ msgstr "状态" #: authentication/templates/authentication/passkey.html:173 #: authentication/views/base.py:42 authentication/views/base.py:43 #: authentication/views/base.py:44 common/const/choices.py:20 -#: settings/templates/ldap/_msg_import_ldap_user.html:22 +#: settings/templates/ldap/_msg_import_ldap_user.html:26 msgid "Error" msgstr "错误" @@ -603,14 +608,14 @@ msgstr "密码规则" #: authentication/serializers/connect_token_secret.py:113 #: authentication/serializers/connect_token_secret.py:168 labels/models.py:11 #: ops/mixin.py:21 ops/models/adhoc.py:20 ops/models/celery.py:15 -#: ops/models/celery.py:57 ops/models/job.py:136 ops/models/playbook.py:28 +#: ops/models/celery.py:80 ops/models/job.py:137 ops/models/playbook.py:28 #: ops/serializers/job.py:18 orgs/models.py:82 #: perms/models/asset_permission.py:61 rbac/models/role.py:29 #: settings/models.py:33 settings/models.py:181 settings/serializers/msg.py:89 #: terminal/models/applet/applet.py:33 terminal/models/component/endpoint.py:12 -#: terminal/models/component/endpoint.py:95 +#: terminal/models/component/endpoint.py:109 #: terminal/models/component/storage.py:26 terminal/models/component/task.py:13 -#: terminal/models/component/terminal.py:84 +#: terminal/models/component/terminal.py:85 #: terminal/models/virtualapp/provider.py:10 #: terminal/models/virtualapp/virtualapp.py:19 tickets/api/ticket.py:87 #: users/forms/profile.py:33 users/models/group.py:13 @@ -629,8 +634,8 @@ msgstr "特权账号" #: assets/models/label.py:22 #: authentication/serializers/connect_token_secret.py:117 #: terminal/models/applet/applet.py:40 -#: terminal/models/component/endpoint.py:106 -#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:167 +#: terminal/models/component/endpoint.py:120 +#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:169 msgid "Is active" msgstr "激活" @@ -712,22 +717,22 @@ msgstr "" msgid "Notification of implementation result of encryption change plan" msgstr "改密计划任务结果通知" -#: accounts/notifications.py:65 +#: accounts/notifications.py:66 msgid "" "{} - The encryption change task has been completed. See the attachment for " "details" msgstr "{} - 改密任务已完成, 详情见附件" -#: accounts/notifications.py:68 +#: accounts/notifications.py:70 msgid "" "{} - The encryption change task has been completed: the encryption password " -"has not been set - please go to personal information -> file encryption " -"password to set the encryption password" +"has not been set - please go to personal information -> set encryption " +"password in preferences" msgstr "" -"{} - 改密任务已完成: 未设置加密密码 - 请前往个人信息 -> 文件加密密码中设置加" -"密密码" +"{} - 改密任务已完成: 未设置加密密码 - 请前往个人信息 -> 偏好设置中设置加密密" +"码" -#: accounts/notifications.py:79 +#: accounts/notifications.py:82 msgid "Gather account change information" msgstr "账号变更信息" @@ -756,11 +761,11 @@ msgstr "类别" #: assets/serializers/asset/common.py:126 assets/serializers/platform.py:120 #: assets/serializers/platform.py:139 audits/serializers.py:53 #: audits/serializers.py:170 -#: authentication/serializers/connect_token_secret.py:126 ops/models/job.py:144 +#: authentication/serializers/connect_token_secret.py:126 ops/models/job.py:145 #: perms/serializers/user_permission.py:27 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:264 +#: terminal/serializers/session.py:23 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 @@ -776,7 +781,7 @@ msgstr "资产不存在" msgid "Has secret" msgstr "已托管密码" -#: accounts/serializers/account/account.py:259 ops/models/celery.py:60 +#: accounts/serializers/account/account.py:259 ops/models/celery.py:83 #: tickets/models/comment.py:13 tickets/models/ticket/general.py:45 #: tickets/models/ticket/general.py:279 tickets/serializers/super_ticket.py:14 #: tickets/serializers/ticket/ticket.py:21 @@ -793,7 +798,7 @@ msgstr "已修改" #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 #: authentication/api/connection_token.py:404 ops/models/base.py:17 -#: ops/models/job.py:146 ops/serializers/job.py:19 +#: ops/models/job.py:147 ops/serializers/job.py:19 #: terminal/templates/terminal/_msg_command_execute_alert.html:16 msgid "Assets" msgstr "资产" @@ -924,11 +929,11 @@ msgstr "关联平台,可配置推送参数,如果不关联,将使用默认 #: accounts/serializers/account/virtual.py:19 assets/models/_user.py:27 #: 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:152 ops/models/playbook.py:31 rbac/models/role.py:37 +#: ops/models/job.py:153 ops/models/playbook.py:31 rbac/models/role.py:37 #: settings/models.py:38 terminal/models/applet/applet.py:45 #: terminal/models/applet/applet.py:321 terminal/models/applet/host.py:143 #: terminal/models/component/endpoint.py:25 -#: terminal/models/component/endpoint.py:105 +#: terminal/models/component/endpoint.py:119 #: terminal/models/session/session.py:46 #: terminal/models/virtualapp/virtualapp.py:28 tickets/models/comment.py:32 #: tickets/models/ticket/general.py:297 users/models/user.py:836 @@ -982,7 +987,7 @@ msgstr "自动化任务执行历史" #: audits/models.py:64 audits/signal_handlers/activity_log.py:33 #: common/const/choices.py:18 ops/const.py:73 ops/serializers/celery.py:46 #: terminal/const.py:78 terminal/models/session/sharing.py:121 -#: tickets/views/approve.py:117 +#: tickets/views/approve.py:128 msgid "Success" msgstr "成功" @@ -1067,7 +1072,7 @@ msgstr "密钥不合法或密钥密码错误" msgid "Acls" msgstr "访问控制" -#: acls/const.py:6 audits/const.py:36 terminal/const.py:11 tickets/const.py:45 +#: acls/const.py:6 audits/const.py:36 terminal/const.py:11 tickets/const.py:46 #: tickets/templates/tickets/approve_check_password.html:47 msgid "Reject" msgstr "拒绝" @@ -1089,13 +1094,13 @@ msgid "Notifications" msgstr "通知" #: acls/models/base.py:37 assets/models/_user.py:51 -#: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:98 +#: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:112 #: xpack/plugins/cloud/models.py:282 msgid "Priority" msgstr "优先级" #: acls/models/base.py:38 assets/models/_user.py:51 -#: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:99 +#: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:113 #: xpack/plugins/cloud/models.py:283 msgid "1-100, the lower the value will be match first" msgstr "优先级可选范围为 1-100 (数值越小越优先)" @@ -1109,7 +1114,7 @@ msgstr "审批人" #: authentication/models/connection_token.py:53 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:82 terminal/models/session/sharing.py:29 -#: tickets/const.py:37 +#: tickets/const.py:38 msgid "Active" msgstr "激活中" @@ -1124,7 +1129,7 @@ msgid "Accounts" msgstr "账号管理" #: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60 -#: ops/serializers/job.py:63 terminal/const.py:86 +#: ops/serializers/job.py:70 terminal/const.py:86 #: 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 @@ -1167,7 +1172,7 @@ msgstr "生成的正则表达式有误" msgid "Command acl" msgstr "命令过滤" -#: acls/models/command_acl.py:112 tickets/const.py:11 +#: acls/models/command_acl.py:112 tickets/const.py:12 msgid "Command confirm" msgstr "命令复核" @@ -1188,7 +1193,7 @@ msgstr "规则" msgid "Login acl" msgstr "登录访问控制" -#: acls/models/login_acl.py:27 tickets/const.py:10 +#: acls/models/login_acl.py:27 tickets/const.py:11 msgid "Login confirm" msgstr "登录复核" @@ -1196,7 +1201,7 @@ msgstr "登录复核" msgid "Login asset acl" msgstr "登录资产访问控制" -#: acls/models/login_asset_acl.py:22 tickets/const.py:12 +#: acls/models/login_asset_acl.py:22 tickets/const.py:13 msgid "Login asset confirm" msgstr "登录资产复核" @@ -1319,7 +1324,7 @@ msgstr "应用程序" msgid "Can match application" msgstr "匹配应用" -#: assets/api/asset/asset.py:179 +#: assets/api/asset/asset.py:180 msgid "Cannot create asset directly, you should create a host or other" msgstr "不能直接创建资产, 你应该创建主机或其他资产" @@ -1457,7 +1462,7 @@ msgid "Kubernetes" msgstr "Kubernetes" #: assets/const/device.py:7 terminal/models/applet/applet.py:26 -#: tickets/const.py:8 +#: tickets/const.py:9 msgid "General" msgstr "一般" @@ -1597,7 +1602,7 @@ msgstr "确认按钮选择器" msgid "API mode" msgstr "API 模式" -#: assets/const/types.py:247 +#: assets/const/types.py:248 msgid "All types" msgstr "所有类型" @@ -1622,7 +1627,7 @@ msgstr "SSH公钥" #: assets/models/_user.py:28 assets/models/automations/base.py:114 #: assets/models/cmd_filter.py:41 assets/models/group.py:19 #: audits/models.py:267 common/db/models.py:34 ops/models/base.py:54 -#: ops/models/job.py:234 users/models/user.py:1042 +#: ops/models/job.py:235 users/models/user.py:1042 msgid "Date created" msgstr "创建日期" @@ -1662,7 +1667,7 @@ msgstr "用户名与用户相同" #: authentication/serializers/connect_token_secret.py:114 #: settings/serializers/msg.py:29 terminal/models/applet/applet.py:42 #: terminal/models/virtualapp/virtualapp.py:24 -#: terminal/serializers/session.py:19 terminal/serializers/session.py:45 +#: terminal/serializers/session.py:21 terminal/serializers/session.py:47 #: terminal/serializers/storage.py:71 msgid "Protocol" msgstr "协议" @@ -1736,7 +1741,7 @@ msgid "Domain" msgstr "网域" #: assets/models/asset/common.py:165 assets/models/automations/base.py:18 -#: assets/models/cmd_filter.py:32 assets/models/node.py:546 +#: assets/models/cmd_filter.py:32 assets/models/node.py:549 #: perms/models/asset_permission.py:72 perms/serializers/permission.py:37 #: tickets/models/ticket/apply_asset.py:14 xpack/plugins/cloud/models.py:330 msgid "Node" @@ -1791,7 +1796,7 @@ msgstr "忽略证书校验" msgid "Proxy" msgstr "代理" -#: assets/models/automations/base.py:22 ops/models/job.py:230 +#: assets/models/automations/base.py:22 ops/models/job.py:231 #: settings/serializers/auth/sms.py:103 msgid "Parameters" msgstr "参数" @@ -1876,7 +1881,7 @@ msgstr "默认资产组" msgid "System" msgstr "系统" -#: assets/models/label.py:19 assets/models/node.py:532 +#: assets/models/label.py:19 assets/models/node.py:535 #: assets/serializers/cagegory.py:11 assets/serializers/cagegory.py:18 #: assets/serializers/cagegory.py:24 #: authentication/models/connection_token.py:29 @@ -1899,23 +1904,23 @@ msgstr "标签" msgid "New node" msgstr "新节点" -#: assets/models/node.py:460 audits/backends/db.py:65 audits/backends/db.py:66 +#: assets/models/node.py:463 audits/backends/db.py:65 audits/backends/db.py:66 msgid "empty" msgstr "空" -#: assets/models/node.py:531 perms/models/perm_node.py:28 +#: assets/models/node.py:534 perms/models/perm_node.py:28 msgid "Key" msgstr "键" -#: assets/models/node.py:533 assets/serializers/node.py:20 +#: assets/models/node.py:536 assets/serializers/node.py:20 msgid "Full value" msgstr "全称" -#: assets/models/node.py:537 perms/models/perm_node.py:30 +#: assets/models/node.py:540 perms/models/perm_node.py:30 msgid "Parent key" msgstr "ssh私钥" -#: assets/models/node.py:549 +#: assets/models/node.py:552 msgid "Can match node" msgstr "可以匹配节点" @@ -2349,7 +2354,7 @@ msgstr "重命名" msgid "Symlink" msgstr "建立软链接" -#: audits/const.py:18 audits/const.py:28 terminal/api/session/session.py:146 +#: audits/const.py:18 audits/const.py:28 terminal/api/session/session.py:149 msgid "Download" msgstr "下载" @@ -2357,7 +2362,7 @@ msgstr "下载" msgid "Rename dir" msgstr "映射目录" -#: audits/const.py:23 rbac/tree.py:238 terminal/api/session/session.py:257 +#: audits/const.py:23 rbac/tree.py:238 terminal/api/session/session.py:277 #: terminal/templates/terminal/_msg_command_warning.html:18 #: terminal/templates/terminal/_msg_session_sharing.html:10 msgid "View" @@ -2383,21 +2388,21 @@ msgstr "登录" msgid "Change password" msgstr "改密" -#: audits/const.py:37 tickets/const.py:46 +#: audits/const.py:37 tickets/const.py:47 msgid "Approve" msgstr "同意" #: audits/const.py:38 #: authentication/templates/authentication/_access_key_modal.html:155 #: authentication/templates/authentication/_mfa_confirm_modal.html:53 -#: templates/_modal.html:22 tickets/const.py:44 +#: templates/_modal.html:22 tickets/const.py:45 msgid "Close" msgstr "关闭" #: audits/const.py:43 settings/serializers/terminal.py:6 -#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:174 -#: terminal/models/virtualapp/provider.py:14 terminal/serializers/session.py:52 -#: terminal/serializers/session.py:66 +#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:175 +#: terminal/models/virtualapp/provider.py:14 terminal/serializers/session.py:54 +#: terminal/serializers/session.py:68 msgid "Terminal" msgstr "终端" @@ -2535,16 +2540,16 @@ msgstr "用户登录日志" msgid "Session key" msgstr "会话标识" -#: audits/models.py:306 +#: audits/models.py:305 msgid "User session" msgstr "用户会话" -#: audits/models.py:308 +#: audits/models.py:307 msgid "Offline user session" msgstr "下线用户会话" #: audits/serializers.py:33 ops/models/adhoc.py:25 ops/models/base.py:16 -#: ops/models/base.py:53 ops/models/job.py:145 ops/models/job.py:233 +#: ops/models/base.py:53 ops/models/job.py:146 ops/models/job.py:234 #: ops/models/playbook.py:30 terminal/models/session/sharing.py:25 msgid "Creator" msgstr "创建者" @@ -2614,7 +2619,7 @@ msgstr "飞书" msgid "Slack" msgstr "" -#: audits/signal_handlers/login_log.py:40 authentication/views/dingtalk.py:160 +#: audits/signal_handlers/login_log.py:40 authentication/views/dingtalk.py:161 #: authentication/views/login.py:83 notifications/backends/__init__.py:12 #: settings/serializers/auth/dingtalk.py:10 users/models/user.py:750 #: users/models/user.py:856 @@ -2631,11 +2636,11 @@ msgstr "临时密码" msgid "Passkey" msgstr "Passkey" -#: audits/tasks.py:101 +#: audits/tasks.py:109 msgid "Clean audits session task log" msgstr "清理资产审计会话任务日志" -#: audits/tasks.py:114 +#: audits/tasks.py:123 msgid "Upload FTP file to external storage" msgstr "上传 FTP 文件到外部存储" @@ -2680,12 +2685,12 @@ msgstr "ACL 动作是复核" msgid "Current user not support mfa type: {}" msgstr "当前用户不支持 MFA 类型: {}" -#: authentication/api/password.py:33 terminal/api/session/session.py:305 -#: users/views/profile/reset.py:62 +#: authentication/api/password.py:33 terminal/api/session/session.py:325 +#: users/views/profile/reset.py:63 msgid "User does not exist: {}" msgstr "用户不存在: {}" -#: authentication/api/password.py:33 users/views/profile/reset.py:163 +#: authentication/api/password.py:33 users/views/profile/reset.py:164 msgid "No user matched" msgstr "没有匹配到用户" @@ -2697,8 +2702,8 @@ msgstr "用户来自 {} 请去相应系统修改密码" #: authentication/api/password.py:65 #: authentication/templates/authentication/login.html:361 -#: users/templates/users/forgot_password.html:27 -#: users/templates/users/forgot_password.html:28 +#: users/templates/users/forgot_password.html:41 +#: users/templates/users/forgot_password.html:42 #: users/templates/users/forgot_password_previewing.html:13 #: users/templates/users/forgot_password_previewing.html:14 msgid "Forgot password" @@ -2709,24 +2714,24 @@ msgid "Authentication" msgstr "认证" #: authentication/backends/custom.py:59 -#: authentication/backends/oauth2/backends.py:170 +#: authentication/backends/oauth2/backends.py:173 msgid "User invalid, disabled or expired" msgstr "用户无效,已禁用或已过期" -#: authentication/backends/drf.py:50 +#: authentication/backends/drf.py:52 msgid "Invalid token header. No credentials provided." msgstr "无效的令牌头。没有提供任何凭据。" -#: authentication/backends/drf.py:53 +#: authentication/backends/drf.py:55 msgid "Invalid token header. Sign string should not contain spaces." msgstr "无效的令牌头。符号字符串不应包含空格。" -#: authentication/backends/drf.py:59 +#: authentication/backends/drf.py:61 msgid "" "Invalid token header. Sign string should not contain invalid characters." msgstr "无效的令牌头。符号字符串不应包含无效字符。" -#: authentication/backends/drf.py:72 +#: authentication/backends/drf.py:74 msgid "Invalid token or cache refreshed." msgstr "刷新的令牌或缓存无效。" @@ -2895,8 +2900,8 @@ msgstr "企业微信已经绑定" msgid "WeCom is not bound" msgstr "没有绑定企业微信" -#: authentication/errors/mfa.py:28 authentication/views/dingtalk.py:212 -#: authentication/views/dingtalk.py:254 +#: authentication/errors/mfa.py:28 authentication/views/dingtalk.py:213 +#: authentication/views/dingtalk.py:255 msgid "DingTalk is not bound" msgstr "钉钉没有绑定" @@ -3005,8 +3010,8 @@ msgstr "短信验证码校验失败" #: authentication/mfa/sms.py:12 authentication/serializers/password_mfa.py:16 #: authentication/serializers/password_mfa.py:24 #: settings/serializers/auth/sms.py:32 users/forms/profile.py:104 -#: users/forms/profile.py:109 users/templates/users/forgot_password.html:112 -#: users/views/profile/reset.py:99 +#: users/forms/profile.py:109 users/templates/users/forgot_password.html:155 +#: users/views/profile/reset.py:100 msgid "SMS" msgstr "短信" @@ -3045,7 +3050,7 @@ msgid "Please change your password" msgstr "请修改密码" #: authentication/models/access_key.py:22 -#: terminal/models/component/endpoint.py:96 +#: terminal/models/component/endpoint.py:110 msgid "IP group" msgstr "IPグループ" @@ -3197,12 +3202,12 @@ msgstr "动作" #: authentication/serializers/connection_token.py:42 #: perms/serializers/permission.py:40 perms/serializers/permission.py:60 -#: users/serializers/user.py:97 users/serializers/user.py:171 +#: users/serializers/user.py:97 users/serializers/user.py:173 msgid "Is expired" msgstr "已过期" #: authentication/serializers/password_mfa.py:29 -#: users/templates/users/forgot_password.html:108 +#: users/templates/users/forgot_password.html:151 msgid "The {} cannot be empty" msgstr "{} 不能为空" @@ -3212,7 +3217,7 @@ msgstr "IP 白名单" #: authentication/serializers/token.py:92 perms/serializers/permission.py:39 #: perms/serializers/permission.py:61 users/serializers/user.py:98 -#: users/serializers/user.py:168 +#: users/serializers/user.py:170 msgid "Is valid" msgstr "是否有效" @@ -3338,7 +3343,7 @@ msgstr "重新申请" #: authentication/templates/authentication/_msg_reset_password_code.html:12 #: terminal/models/session/sharing.py:27 terminal/models/session/sharing.py:97 #: terminal/templates/terminal/_msg_session_sharing.html:12 -#: users/forms/profile.py:107 users/templates/users/forgot_password.html:66 +#: users/forms/profile.py:107 users/templates/users/forgot_password.html:97 msgid "Verify code" msgstr "验证码" @@ -3382,7 +3387,7 @@ msgid "" msgstr "如果这次公钥更新不是由你发起的,那么你的账号可能存在安全问题" #: authentication/templates/authentication/auth_fail_flash_message_standalone.html:28 -#: templates/flash_message_standalone.html:28 tickets/const.py:17 +#: templates/flash_message_standalone.html:28 tickets/const.py:18 msgid "Cancel" msgstr "取消" @@ -3407,7 +3412,7 @@ msgstr "MFA 多因子认证" #: authentication/templates/authentication/login_mfa.html:19 #: users/templates/users/user_otp_check_password.html:12 #: users/templates/users/user_otp_enable_bind.html:24 -#: users/templates/users/user_otp_enable_install_app.html:29 +#: users/templates/users/user_otp_enable_install_app.html:31 #: users/templates/users/user_verify_mfa.html:30 msgid "Next" msgstr "下一步" @@ -3471,7 +3476,7 @@ msgstr "绑定 %s 成功" msgid "DingTalk Error, Please contact your system administrator" msgstr "钉钉错误,请联系系统管理员" -#: authentication/views/dingtalk.py:45 authentication/views/dingtalk.py:211 +#: authentication/views/dingtalk.py:45 authentication/views/dingtalk.py:212 msgid "DingTalk Error" msgstr "钉钉错误" @@ -3485,27 +3490,27 @@ msgstr "企业配置错误,请联系系统管理员" msgid "DingTalk is already bound" msgstr "钉钉已经绑定" -#: authentication/views/dingtalk.py:129 +#: authentication/views/dingtalk.py:130 msgid "Invalid user_id" msgstr "无效的 user_id" -#: authentication/views/dingtalk.py:145 +#: authentication/views/dingtalk.py:146 msgid "DingTalk query user failed" msgstr "钉钉查询用户失败" -#: authentication/views/dingtalk.py:154 +#: authentication/views/dingtalk.py:155 msgid "The DingTalk is already bound to another user" msgstr "该钉钉已经绑定其他用户" -#: authentication/views/dingtalk.py:161 +#: authentication/views/dingtalk.py:162 msgid "Binding DingTalk successfully" msgstr "绑定 钉钉 成功" -#: authentication/views/dingtalk.py:213 authentication/views/dingtalk.py:248 +#: authentication/views/dingtalk.py:214 authentication/views/dingtalk.py:249 msgid "Failed to get user from DingTalk" msgstr "从钉钉获取用户失败" -#: authentication/views/dingtalk.py:255 +#: authentication/views/dingtalk.py:256 msgid "Please login with a password and then bind the DingTalk" msgstr "请使用密码登录,然后绑定钉钉" @@ -3605,8 +3610,8 @@ msgstr "定时触发" msgid "Ready" msgstr "准备" -#: common/const/choices.py:16 terminal/const.py:77 tickets/const.py:29 -#: tickets/const.py:39 +#: common/const/choices.py:16 terminal/const.py:77 tickets/const.py:30 +#: tickets/const.py:40 msgid "Pending" msgstr "待定的" @@ -3660,7 +3665,7 @@ msgstr "编码数据为 text" msgid "Encrypt field using Secret Key" msgstr "加密的字段" -#: common/db/fields.py:573 +#: common/db/fields.py:580 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " @@ -3670,15 +3675,15 @@ msgstr "" "{'type': 'attrs', 'attrs': [{'name': 'ip', 'match': 'exact', 'value': " "'1.1.1.1'}}" -#: common/db/fields.py:580 +#: common/db/fields.py:587 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "无效类型,应为 all、ids 或 attrs" -#: common/db/fields.py:583 +#: common/db/fields.py:590 msgid "Invalid ids for ids, should be a list" msgstr "无效的ID,应为列表" -#: common/db/fields.py:585 common/db/fields.py:590 +#: common/db/fields.py:592 common/db/fields.py:597 #: common/serializers/fields.py:133 tickets/serializers/ticket/common.py:58 #: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:79 @@ -3686,11 +3691,11 @@ msgstr "无效的ID,应为列表" msgid "This field is required." msgstr "该字段是必填项。" -#: common/db/fields.py:588 common/db/fields.py:593 +#: common/db/fields.py:595 common/db/fields.py:600 msgid "Invalid attrs, should be a list of dict" msgstr "无效的属性,应为dict列表" -#: common/db/fields.py:595 +#: common/db/fields.py:602 msgid "Invalid attrs, should be has name and value" msgstr "无效属性,应具有名称和值" @@ -4011,28 +4016,33 @@ msgstr "Ansible 已禁用" msgid "Skip hosts below:" msgstr "跳过以下主机: " -#: ops/api/celery.py:65 ops/api/celery.py:80 +#: ops/api/celery.py:66 ops/api/celery.py:81 msgid "Waiting task start" msgstr "等待任务开始" -#: ops/api/celery.py:203 +#: ops/api/celery.py:246 msgid "Task {} not found" msgstr "任务 {} 不存在" -#: ops/api/celery.py:208 +#: ops/api/celery.py:251 msgid "Task {} args or kwargs error" msgstr "任务 {} 执行参数错误" -#: ops/api/job.py:132 +#: ops/api/job.py:135 msgid "Duplicate file exists" msgstr "存在同名文件" -#: ops/api/job.py:137 +#: ops/api/job.py:140 #, python-brace-format msgid "" "File size exceeds maximum limit. Please select a file smaller than {limit}MB" msgstr "文件大小超过最大限制。请选择小于 {limit}MB 的文件。" +#: ops/api/job.py:204 +msgid "" +"The task is being created and cannot be interrupted. Please try again later." +msgstr "正在创建任务,无法中断,请稍后重试。" + #: ops/api/playbook.py:39 msgid "Currently playbook is being used in a job" msgstr "当前 playbook 正在作业中使用" @@ -4101,7 +4111,7 @@ msgstr "VCS" msgid "Adhoc" msgstr "命令" -#: ops/const.py:39 ops/models/job.py:143 +#: ops/const.py:39 ops/models/job.py:144 msgid "Playbook" msgstr "Playbook" @@ -4186,11 +4196,11 @@ msgstr "需要周期或定期设置" msgid "Pattern" msgstr "模式" -#: ops/models/adhoc.py:23 ops/models/job.py:140 +#: ops/models/adhoc.py:23 ops/models/job.py:141 msgid "Module" msgstr "模块" -#: ops/models/adhoc.py:24 ops/models/celery.py:58 ops/models/job.py:138 +#: ops/models/adhoc.py:24 ops/models/celery.py:81 ops/models/job.py:139 #: terminal/models/component/task.py:14 msgid "Args" msgstr "参数" @@ -4209,12 +4219,12 @@ msgstr "最后执行" msgid "Date last run" msgstr "最后运行日期" -#: ops/models/base.py:51 ops/models/job.py:231 +#: ops/models/base.py:51 ops/models/job.py:232 #: xpack/plugins/cloud/models.py:202 msgid "Result" msgstr "结果" -#: ops/models/base.py:52 ops/models/job.py:232 +#: ops/models/base.py:52 ops/models/job.py:233 msgid "Summary" msgstr "汇总" @@ -4222,68 +4232,68 @@ msgstr "汇总" msgid "Date last publish" msgstr "发布日期" -#: ops/models/celery.py:47 +#: ops/models/celery.py:70 msgid "Celery Task" msgstr "Celery 任务" -#: ops/models/celery.py:50 +#: ops/models/celery.py:73 msgid "Can view task monitor" msgstr "可以查看任务监控" -#: ops/models/celery.py:59 terminal/models/component/task.py:15 +#: ops/models/celery.py:82 terminal/models/component/task.py:15 msgid "Kwargs" msgstr "其它参数" -#: ops/models/celery.py:61 terminal/models/session/sharing.py:128 -#: tickets/const.py:25 +#: ops/models/celery.py:84 terminal/models/session/sharing.py:128 +#: tickets/const.py:26 msgid "Finished" msgstr "结束" -#: ops/models/celery.py:62 +#: ops/models/celery.py:85 msgid "Date published" msgstr "发布日期" -#: ops/models/celery.py:87 +#: ops/models/celery.py:110 msgid "Celery Task Execution" msgstr "Celery 任务执行" -#: ops/models/job.py:141 +#: ops/models/job.py:142 msgid "Chdir" msgstr "运行目录" -#: ops/models/job.py:142 +#: ops/models/job.py:143 msgid "Timeout (Seconds)" msgstr "超时时间 (秒)" -#: ops/models/job.py:147 +#: ops/models/job.py:148 msgid "Use Parameter Define" msgstr "使用参数定义" -#: ops/models/job.py:148 +#: ops/models/job.py:149 msgid "Parameters define" msgstr "参数定义" -#: ops/models/job.py:149 +#: ops/models/job.py:150 msgid "Runas" msgstr "运行用户" -#: ops/models/job.py:151 +#: ops/models/job.py:152 msgid "Runas policy" msgstr "用户策略" -#: ops/models/job.py:215 +#: ops/models/job.py:216 msgid "Job" msgstr "作业" -#: ops/models/job.py:238 +#: ops/models/job.py:239 msgid "Material" msgstr "Material" -#: ops/models/job.py:240 +#: ops/models/job.py:241 msgid "Material Type" msgstr "Material 类型" -#: ops/models/job.py:557 +#: ops/models/job.py:567 msgid "Job Execution" msgstr "作业执行" @@ -4327,15 +4337,15 @@ msgstr "CPU 使用率超过 {max_threshold}: => {value}" msgid "Run after save" msgstr "保存后执行" -#: ops/serializers/job.py:62 +#: ops/serializers/job.py:69 msgid "Job type" msgstr "任务类型" -#: ops/serializers/job.py:65 terminal/serializers/session.py:53 +#: ops/serializers/job.py:72 terminal/serializers/session.py:55 msgid "Is finished" msgstr "是否完成" -#: ops/serializers/job.py:66 +#: ops/serializers/job.py:73 #: settings/templates/ldap/_msg_import_ldap_user.html:7 msgid "Time cost" msgstr "花费时间" @@ -4468,7 +4478,7 @@ msgstr "可以查看全局组织" msgid "Can view all joined org" msgstr "可以查看所有加入的组织" -#: orgs/models.py:233 +#: orgs/models.py:236 msgid "Can not delete virtual org" msgstr "无法删除虚拟组织" @@ -4553,7 +4563,7 @@ msgid "today" msgstr "今天" #: perms/notifications.py:12 perms/notifications.py:44 -#: settings/serializers/feature.py:117 +#: settings/serializers/feature.py:118 msgid "day" msgstr "天" @@ -4614,7 +4624,7 @@ msgstr "内部角色,不能删除" msgid "The role has been bound to users, can't be destroy" msgstr "角色已绑定用户,不能删除" -#: rbac/api/role.py:100 +#: rbac/api/role.py:102 msgid "Internal role, can't be update" msgstr "内部角色,不能更新" @@ -4824,19 +4834,11 @@ msgstr "测试成功" msgid "Test mail sent to {}, please check" msgstr "邮件已经发送{}, 请检查" -#: settings/api/ldap.py:101 +#: settings/api/ldap.py:89 msgid "" "Users are not synchronized, please click the user synchronization button" msgstr "用户未同步,请点击同步用户按钮" -#: settings/api/ldap.py:137 -msgid "Get ldap users is None" -msgstr "获取 LDAP 用户为 None" - -#: settings/api/ldap.py:147 -msgid "Imported {} users successfully (Organization: {})" -msgstr "成功导入 {} 个用户 ( 组织: {} )" - #: settings/api/sms.py:142 msgid "Invalid SMS platform" msgstr "无效的短信平台" @@ -5446,26 +5448,30 @@ msgid "Operate log keep days (day)" msgstr "操作日志 (天)" #: settings/serializers/cleaning.py:27 +msgid "password change log keep days (day)" +msgstr "改密日志 (天)" + +#: settings/serializers/cleaning.py:31 msgid "FTP log keep days (day)" msgstr "上传下载 (天)" -#: settings/serializers/cleaning.py:31 +#: settings/serializers/cleaning.py:35 msgid "Cloud sync record keep days (day)" msgstr "云同步记录 (天)" -#: settings/serializers/cleaning.py:35 +#: settings/serializers/cleaning.py:39 msgid "job execution keep days (day)" msgstr "作业中心执行历史 (天)" -#: settings/serializers/cleaning.py:39 +#: settings/serializers/cleaning.py:43 msgid "Activity log keep days (day)" msgstr "活动记录 (天)" -#: settings/serializers/cleaning.py:42 +#: settings/serializers/cleaning.py:46 msgid "Session keep duration (day)" msgstr "会话日志 (天)" -#: settings/serializers/cleaning.py:44 +#: settings/serializers/cleaning.py:48 msgid "" "Session, record, command will be delete if more than duration, only in " "database, OSS will not be affected." @@ -5534,39 +5540,43 @@ msgstr "GPT 模型" msgid "Enable tickets" msgstr "启用工单" -#: settings/serializers/feature.py:114 +#: settings/serializers/feature.py:112 +msgid "No login approval" +msgstr "免登录审批" + +#: settings/serializers/feature.py:115 msgid "Ticket authorize default time" msgstr "默认工单授权时间" -#: settings/serializers/feature.py:117 +#: settings/serializers/feature.py:118 msgid "hour" msgstr "时" -#: settings/serializers/feature.py:118 +#: settings/serializers/feature.py:119 msgid "Ticket authorize default time unit" msgstr "默认工单授权时间单位" -#: settings/serializers/feature.py:123 +#: settings/serializers/feature.py:124 msgid "Feature" msgstr "功能" -#: settings/serializers/feature.py:126 +#: settings/serializers/feature.py:127 msgid "Operation center" msgstr "作业中心" -#: settings/serializers/feature.py:127 +#: settings/serializers/feature.py:128 msgid "Allow user run batch command or not using ansible" msgstr "是否允许用户使用 ansible 执行批量命令" -#: settings/serializers/feature.py:131 +#: settings/serializers/feature.py:132 msgid "Operation center command blacklist" msgstr "作业中心命令黑名单" -#: settings/serializers/feature.py:132 +#: settings/serializers/feature.py:133 msgid "Commands that are not allowed execute." msgstr "不允许执行的命令" -#: settings/serializers/feature.py:137 +#: settings/serializers/feature.py:138 #: terminal/models/virtualapp/provider.py:17 #: terminal/models/virtualapp/virtualapp.py:36 #: terminal/models/virtualapp/virtualapp.py:97 @@ -5574,7 +5584,7 @@ msgstr "不允许执行的命令" msgid "Virtual app" msgstr "虚拟应用" -#: settings/serializers/feature.py:140 +#: settings/serializers/feature.py:141 msgid "Enable virtual app" msgstr "启用虚拟应用" @@ -6028,6 +6038,10 @@ msgstr "已同步组织" msgid "Synced User" msgstr "已同步用户" +#: settings/templates/ldap/_msg_import_ldap_user.html:22 +msgid "No user synchronization required" +msgstr "没有用户需要同步" + #: settings/utils/ldap.py:494 msgid "ldap:// or ldaps:// protocol is used." msgstr "使用 ldap:// 或 ldaps:// 协议" @@ -6129,6 +6143,14 @@ msgstr "认证失败: (未知): {}" msgid "Authentication success: {}" msgstr "认证成功: {}" +#: settings/ws.py:236 +msgid "Get ldap users is None" +msgstr "获取 LDAP 用户为 None" + +#: settings/ws.py:246 +msgid "Imported {} users successfully (Organization: {})" +msgstr "成功导入 {} 个用户 ( 组织: {} )" + #: templates/_csv_import_export.html:8 msgid "Export" msgstr "导出" @@ -6267,12 +6289,12 @@ msgid "Send verification code" msgstr "发送验证码" #: templates/_mfa_login_field.html:106 -#: users/templates/users/forgot_password.html:130 +#: users/templates/users/forgot_password.html:174 msgid "Wait: " msgstr "等待:" #: templates/_mfa_login_field.html:116 -#: users/templates/users/forgot_password.html:146 +#: users/templates/users/forgot_password.html:190 msgid "The verification code has been sent" msgstr "验证码已发送" @@ -6321,13 +6343,13 @@ msgstr "OpenSSH 是在 windows 远程应用发布服务器中用来连接远程 msgid "Offline video player" msgstr "离线录像播放器" -#: terminal/api/applet/applet.py:50 terminal/api/applet/applet.py:53 +#: terminal/api/applet/applet.py:52 terminal/api/applet/applet.py:55 #: terminal/api/virtualapp/virtualapp.py:43 #: terminal/api/virtualapp/virtualapp.py:46 msgid "Invalid zip file" msgstr "无效的 zip 文件" -#: terminal/api/applet/applet.py:72 +#: terminal/api/applet/applet.py:74 msgid "This is enterprise edition applet" msgstr "企业版远程应用,在社区版中不能使用" @@ -6367,20 +6389,20 @@ msgstr "测试失败:请检查配置" msgid "Have online sessions" msgstr "有在线会话" -#: terminal/api/session/session.py:46 +#: terminal/api/session/session.py:48 #, python-format msgid "User %s %s session %s replay" msgstr "用户 %s %s 了会话 %s 的录像" -#: terminal/api/session/session.py:297 +#: terminal/api/session/session.py:317 msgid "Session does not exist: {}" msgstr "会话不存在: {}" -#: terminal/api/session/session.py:300 +#: terminal/api/session/session.py:320 msgid "Session is finished or the protocol not supported" msgstr "会话已经完成或协议不支持" -#: terminal/api/session/session.py:313 +#: terminal/api/session/session.py:333 msgid "User does not have permission" msgstr "用户没有权限" @@ -6631,14 +6653,14 @@ msgid "SQLServer port" msgstr "SQLServer 端口" #: terminal/models/component/endpoint.py:30 -#: terminal/models/component/endpoint.py:103 +#: terminal/models/component/endpoint.py:117 #: 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 "端点" -#: terminal/models/component/endpoint.py:109 +#: terminal/models/component/endpoint.py:123 msgid "Endpoint rule" msgstr "端点规则" @@ -6675,28 +6697,28 @@ msgid "Default storage" msgstr "默认存储" #: terminal/models/component/storage.py:140 -#: terminal/models/component/terminal.py:90 +#: terminal/models/component/terminal.py:91 msgid "Command storage" msgstr "命令存储" #: terminal/models/component/storage.py:204 -#: terminal/models/component/terminal.py:91 +#: terminal/models/component/terminal.py:92 msgid "Replay storage" msgstr "录像存储" -#: terminal/models/component/terminal.py:87 +#: terminal/models/component/terminal.py:88 msgid "type" msgstr "类型" -#: terminal/models/component/terminal.py:89 terminal/serializers/command.py:76 +#: terminal/models/component/terminal.py:90 terminal/serializers/command.py:76 msgid "Remote Address" msgstr "远端地址" -#: terminal/models/component/terminal.py:92 +#: terminal/models/component/terminal.py:93 msgid "Application User" msgstr "应用用户" -#: terminal/models/component/terminal.py:176 +#: terminal/models/component/terminal.py:177 msgid "Can view terminal config" msgstr "可以查看终端配置" @@ -6728,11 +6750,11 @@ msgstr "登录来源" msgid "Replay" msgstr "回放" -#: terminal/models/session/session.py:47 terminal/serializers/session.py:65 +#: terminal/models/session/session.py:47 terminal/serializers/session.py:67 msgid "Command amount" msgstr "命令数量" -#: terminal/models/session/session.py:48 terminal/serializers/session.py:28 +#: terminal/models/session/session.py:48 terminal/serializers/session.py:30 msgid "Error reason" msgstr "错误原因" @@ -7044,31 +7066,31 @@ msgstr "如果不同端点下的资产 IP 有冲突,使用资产标签实现" msgid "Asset IP" msgstr "资产 IP" -#: terminal/serializers/session.py:23 terminal/serializers/session.py:50 +#: terminal/serializers/session.py:25 terminal/serializers/session.py:52 msgid "Can replay" msgstr "是否可重放" -#: terminal/serializers/session.py:24 terminal/serializers/session.py:51 +#: terminal/serializers/session.py:26 terminal/serializers/session.py:53 msgid "Can join" msgstr "是否可加入" -#: terminal/serializers/session.py:25 terminal/serializers/session.py:54 +#: terminal/serializers/session.py:27 terminal/serializers/session.py:56 msgid "Can terminate" msgstr "是否可中断" -#: terminal/serializers/session.py:46 +#: terminal/serializers/session.py:48 msgid "User ID" msgstr "用户 ID" -#: terminal/serializers/session.py:47 +#: terminal/serializers/session.py:49 msgid "Asset ID" msgstr "资产 ID" -#: terminal/serializers/session.py:48 +#: terminal/serializers/session.py:50 msgid "Login from display" msgstr "登录来源名称" -#: terminal/serializers/session.py:55 +#: terminal/serializers/session.py:57 msgid "Terminal display" msgstr "终端显示" @@ -7175,6 +7197,99 @@ msgstr "容器状态" msgid "Container Ports" msgstr "容器端口" +#: terminal/session_lifecycle.py:30 +#, python-format +msgid "Connect to asset %s success" +msgstr "连接资产 %s 成功" + +#: terminal/session_lifecycle.py:38 +#, python-format +msgid "Connect to asset %s finished: %s" +msgstr "连接资产 %s 结束: %s" + +#: terminal/session_lifecycle.py:48 +#, python-format +msgid "User %s create share link" +msgstr "用户 %s 创建分享链接" + +#: terminal/session_lifecycle.py:57 +#, python-format +msgid "User %s join session" +msgstr "用户 %s 加入会话" + +#: terminal/session_lifecycle.py:69 +#, python-format +msgid "User %s leave session" +msgstr "用户 %s 离开会话" + +#: terminal/session_lifecycle.py:81 +#, python-format +msgid "User %s join to monitor session" +msgstr "用户 %s 监控会话" + +#: terminal/session_lifecycle.py:93 +#, python-format +msgid "User %s exit to monitor session" +msgstr "用户 %s 离开监控会话" + +#: terminal/session_lifecycle.py:105 +msgid "Replay start to convert" +msgstr "录像开始转化" + +#: terminal/session_lifecycle.py:113 +msgid "Replay successfully converted to MP4 format" +msgstr "录像成功转换成 MP4 格式" + +#: terminal/session_lifecycle.py:121 +#, python-format +msgid "Replay failed to convert to MP4 format: %s" +msgstr "录像转换成 MP4 格式失败: %s" + +#: terminal/session_lifecycle.py:129 +msgid "Replay start to upload" +msgstr "录像开始上传" + +#: terminal/session_lifecycle.py:137 +msgid "Replay successfully uploaded" +msgstr "录像成功上传" + +#: terminal/session_lifecycle.py:145 +#, python-format +msgid "Replay failed to upload: %s" +msgstr "录像上传失败:%s" + +#: terminal/session_lifecycle.py:152 +msgid "connect failed" +msgstr "连接失败" + +#: terminal/session_lifecycle.py:153 +msgid "connection disconnect" +msgstr "连接断开" + +#: terminal/session_lifecycle.py:154 +msgid "user closed" +msgstr "用户关闭" + +#: terminal/session_lifecycle.py:155 +msgid "idle disconnect" +msgstr "空闲断开" + +#: terminal/session_lifecycle.py:156 +msgid "admin terminated" +msgstr "管理员终断连接" + +#: terminal/session_lifecycle.py:157 +msgid "maximum session time has been reached" +msgstr "超过会话最大连接时间" + +#: terminal/session_lifecycle.py:158 +msgid "permission has expired" +msgstr "授权已过期" + +#: terminal/session_lifecycle.py:159 +msgid "storage is null" +msgstr "存储为空" + #: terminal/tasks.py:33 msgid "Periodic delete terminal status" msgstr "周期清理终端状态" @@ -7230,54 +7345,66 @@ msgstr "申请人" msgid "Tickets" msgstr "工单管理" -#: tickets/const.py:9 +#: tickets/const.py:10 msgid "Apply for asset" msgstr "申请资产" -#: tickets/const.py:16 tickets/const.py:24 tickets/const.py:43 +#: tickets/const.py:17 tickets/const.py:25 tickets/const.py:44 msgid "Open" msgstr "打开" -#: tickets/const.py:18 tickets/const.py:31 +#: tickets/const.py:19 tickets/const.py:32 msgid "Reopen" msgstr "重新打开" -#: tickets/const.py:19 tickets/const.py:32 +#: tickets/const.py:20 tickets/const.py:33 msgid "Approved" msgstr "已同意" -#: tickets/const.py:20 tickets/const.py:33 +#: tickets/const.py:21 tickets/const.py:34 msgid "Rejected" msgstr "已拒绝" -#: tickets/const.py:30 tickets/const.py:38 +#: tickets/const.py:31 tickets/const.py:39 msgid "Closed" msgstr "关闭的" -#: tickets/const.py:50 +#: tickets/const.py:51 msgid "One level" msgstr "1 级" -#: tickets/const.py:51 +#: tickets/const.py:52 msgid "Two level" msgstr "2 级" -#: tickets/const.py:55 +#: tickets/const.py:56 msgid "Org admin" msgstr "组织管理员" -#: tickets/const.py:56 +#: tickets/const.py:57 msgid "Custom user" msgstr "自定义用户" -#: tickets/const.py:57 +#: tickets/const.py:58 msgid "Super admin" msgstr "超级管理员" -#: tickets/const.py:58 +#: tickets/const.py:59 msgid "Super admin and org admin" msgstr "组织管理员或超级管理员" +#: tickets/const.py:63 +msgid "All assets" +msgstr "所有资产" + +#: tickets/const.py:64 +msgid "Permed assets" +msgstr "授权的资产" + +#: tickets/const.py:65 +msgid "Permed valid assets" +msgstr "有效授权的资产" + #: tickets/errors.py:9 msgid "Ticket already closed" msgstr "工单已经关闭" @@ -7452,19 +7579,19 @@ msgstr "工单基本信息" msgid "Ticket applied info" msgstr "工单申请信息" -#: tickets/notifications.py:111 +#: tickets/notifications.py:105 msgid "Your has a new ticket, applicant - {}" msgstr "你有一个新的工单, 申请人 - {}" -#: tickets/notifications.py:115 +#: tickets/notifications.py:109 msgid "{}: New Ticket - {} ({})" msgstr "新工单 - {} ({})" -#: tickets/notifications.py:159 +#: tickets/notifications.py:155 msgid "Your ticket has been processed, processor - {}" msgstr "你的工单已被处理, 处理人 - {}" -#: tickets/notifications.py:163 +#: tickets/notifications.py:159 msgid "Ticket has processed - {} ({})" msgstr "你的工单已被处理, 处理人 - {} ({})" @@ -7530,7 +7657,7 @@ msgid "Ticket information" msgstr "工单信息" #: tickets/templates/tickets/approve_check_password.html:28 -#: tickets/views/approve.py:40 tickets/views/approve.py:77 +#: tickets/views/approve.py:43 tickets/views/approve.py:80 msgid "Ticket approval" msgstr "工单审批" @@ -7538,24 +7665,24 @@ msgstr "工单审批" msgid "Approval" msgstr "同意" -#: tickets/views/approve.py:41 +#: tickets/views/approve.py:44 msgid "" "This ticket does not exist, the process has ended, or this link has expired" msgstr "工单不存在,或者工单流程已经结束,或者此链接已经过期" -#: tickets/views/approve.py:69 +#: tickets/views/approve.py:72 msgid "Click the button below to approve or reject" msgstr "点击下方按钮同意或者拒绝" -#: tickets/views/approve.py:78 +#: tickets/views/approve.py:81 msgid "After successful authentication, this ticket can be approved directly" msgstr "认证成功后,工单可直接审批" -#: tickets/views/approve.py:95 +#: tickets/views/approve.py:105 msgid "Illegal approval action" msgstr "无效的审批动作" -#: tickets/views/approve.py:108 +#: tickets/views/approve.py:119 msgid "This user is not authorized to approve this ticket" msgstr "此用户无权审批此工单" @@ -7711,7 +7838,7 @@ msgstr "用户设置" msgid "Force enable" msgstr "强制启用" -#: users/models/user.py:812 users/serializers/user.py:169 +#: users/models/user.py:812 users/serializers/user.py:171 msgid "Is service account" msgstr "服务账号" @@ -7723,7 +7850,7 @@ msgstr "头像" msgid "Wechat" msgstr "微信" -#: users/models/user.py:820 users/serializers/user.py:106 +#: users/models/user.py:820 users/serializers/user.py:108 msgid "Phone" msgstr "手机" @@ -7734,7 +7861,7 @@ msgstr "OTP 密钥" # msgid "Private key" # msgstr "ssh私钥" #: users/models/user.py:838 users/serializers/profile.py:128 -#: users/serializers/user.py:166 +#: users/serializers/user.py:168 msgid "Is first login" msgstr "首次登录" @@ -7785,7 +7912,7 @@ msgstr "用户密码历史" msgid "Reset password" msgstr "重置密码" -#: users/notifications.py:85 users/views/profile/reset.py:230 +#: users/notifications.py:85 users/views/profile/reset.py:231 msgid "Reset password success" msgstr "重置密码成功" @@ -7924,35 +8051,43 @@ msgstr "强制 MFA" msgid "Login blocked" msgstr "登录被锁定" -#: users/serializers/user.py:99 users/serializers/user.py:175 +#: users/serializers/user.py:99 users/serializers/user.py:177 msgid "Is OTP bound" msgstr "是否绑定了虚拟 MFA" +#: users/serializers/user.py:100 +msgid "Super Administrator" +msgstr "超级管理员" + #: users/serializers/user.py:101 +msgid "Organization Administrator" +msgstr "组织管理员" + +#: users/serializers/user.py:103 msgid "Can public key authentication" msgstr "可以使用公钥认证" -#: users/serializers/user.py:170 +#: users/serializers/user.py:172 msgid "Is org admin" msgstr "组织管理员" -#: users/serializers/user.py:172 +#: users/serializers/user.py:174 msgid "Avatar url" msgstr "头像路径" -#: users/serializers/user.py:176 +#: users/serializers/user.py:178 msgid "MFA level" msgstr "MFA 级别" -#: users/serializers/user.py:287 +#: users/serializers/user.py:289 msgid "Select users" msgstr "选择用户" -#: users/serializers/user.py:288 +#: users/serializers/user.py:290 msgid "For security, only list several users" msgstr "为了安全,仅列出几个用户" -#: users/serializers/user.py:321 +#: users/serializers/user.py:323 msgid "name not unique" msgstr "名称重复" @@ -8044,28 +8179,28 @@ msgstr "你的 SSH 密钥已经被管理员重置" msgid "click here to set your password" msgstr "点击这里设置密码" -#: users/templates/users/forgot_password.html:32 +#: users/templates/users/forgot_password.html:46 msgid "Input your email account, that will send a email to your" msgstr "输入您的邮箱, 将会发一封重置邮件到您的邮箱中" -#: users/templates/users/forgot_password.html:35 +#: users/templates/users/forgot_password.html:49 msgid "" "Enter your mobile number and a verification code will be sent to your phone" msgstr "输入您的手机号码,验证码将发送到您的手机" -#: users/templates/users/forgot_password.html:57 +#: users/templates/users/forgot_password.html:71 msgid "Email account" msgstr "邮箱账号" -#: users/templates/users/forgot_password.html:61 +#: users/templates/users/forgot_password.html:92 msgid "Mobile number" msgstr "手机号码" -#: users/templates/users/forgot_password.html:69 +#: users/templates/users/forgot_password.html:100 msgid "Send" msgstr "发送" -#: users/templates/users/forgot_password.html:73 +#: users/templates/users/forgot_password.html:104 #: users/templates/users/forgot_password_previewing.html:30 msgid "Submit" msgstr "提交" @@ -8155,7 +8290,7 @@ msgstr "Android手机下载" msgid "iPhone downloads" msgstr "iPhone手机下载" -#: users/templates/users/user_otp_enable_install_app.html:26 +#: users/templates/users/user_otp_enable_install_app.html:27 msgid "" "After installation, click the next step to enter the binding page (if " "installed, go to the next step directly)." @@ -8180,31 +8315,31 @@ msgstr "账号保护已开启,请根据提示完成以下操作" msgid "Open MFA Authenticator and enter the 6-bit dynamic code" msgstr "请打开 MFA 验证器,输入 6 位动态码" -#: users/views/profile/otp.py:85 +#: users/views/profile/otp.py:106 msgid "Already bound" msgstr "已经绑定" -#: users/views/profile/otp.py:86 +#: users/views/profile/otp.py:107 msgid "MFA already bound, disable first, then bound" msgstr "MFA(OTP) 已经绑定,请先禁用,再绑定" -#: users/views/profile/otp.py:113 +#: users/views/profile/otp.py:134 msgid "OTP enable success" msgstr "MFA(OTP) 启用成功" -#: users/views/profile/otp.py:114 +#: users/views/profile/otp.py:135 msgid "OTP enable success, return login page" msgstr "MFA(OTP) 启用成功,返回到登录页面" -#: users/views/profile/otp.py:156 +#: users/views/profile/otp.py:177 msgid "Disable OTP" msgstr "禁用虚拟 MFA(OTP)" -#: users/views/profile/otp.py:162 +#: users/views/profile/otp.py:183 msgid "OTP disable success" msgstr "MFA(OTP) 禁用成功" -#: users/views/profile/otp.py:163 +#: users/views/profile/otp.py:184 msgid "OTP disable success, return login page" msgstr "MFA(OTP) 禁用成功,返回登录页面" @@ -8212,29 +8347,29 @@ msgstr "MFA(OTP) 禁用成功,返回登录页面" msgid "Password invalid" msgstr "用户名或密码无效" -#: users/views/profile/reset.py:65 +#: users/views/profile/reset.py:66 msgid "" "Non-local users can log in only from third-party platforms and cannot change " "their passwords: {}" msgstr "非本地用户仅允许从第三方平台登录,不支持修改密码: {}" -#: users/views/profile/reset.py:185 users/views/profile/reset.py:196 +#: users/views/profile/reset.py:186 users/views/profile/reset.py:197 msgid "Token invalid or expired" msgstr "令牌错误或失效" -#: users/views/profile/reset.py:201 +#: users/views/profile/reset.py:202 msgid "User auth from {}, go there change password" msgstr "用户认证源来自 {}, 请去相应系统修改密码" -#: users/views/profile/reset.py:208 +#: users/views/profile/reset.py:209 msgid "* Your password does not meet the requirements" msgstr "* 您的密码不符合要求" -#: users/views/profile/reset.py:214 +#: users/views/profile/reset.py:215 msgid "* The new password cannot be the last {} passwords" msgstr "* 新密码不能是最近 {} 次的密码" -#: users/views/profile/reset.py:231 +#: users/views/profile/reset.py:232 msgid "Reset password success, return to login page" msgstr "重置密码成功,返回到登录页面" @@ -8387,7 +8522,7 @@ msgstr "与" msgid "Or" msgstr "或" -#: xpack/plugins/cloud/manager.py:56 +#: xpack/plugins/cloud/manager.py:57 msgid "Account unavailable" msgstr "账号无效" diff --git a/apps/notifications/ws.py b/apps/notifications/ws.py index 019b0b409..653b068d4 100644 --- a/apps/notifications/ws.py +++ b/apps/notifications/ws.py @@ -1,28 +1,32 @@ import json +import time +from threading import Thread from channels.generic.websocket import JsonWebsocketConsumer -from django.core.cache import cache +from django.conf import settings from common.db.utils import safe_db_connection +from common.sessions.cache import user_session_manager from common.utils import get_logger from .signal_handlers import new_site_msg_chan from .site_msg import SiteMessageUtil logger = get_logger(__name__) -WS_SESSION_KEY = 'ws_session_key' class SiteMsgWebsocket(JsonWebsocketConsumer): sub = None refresh_every_seconds = 10 + @property + def session(self): + return self.scope['session'] + def connect(self): user = self.scope["user"] if user.is_authenticated: self.accept() - session = self.scope['session'] - redis_client = cache.client.get_client() - redis_client.sadd(WS_SESSION_KEY, session.session_key) + user_session_manager.add_or_increment(self.session.session_key) self.sub = self.watch_recv_new_site_msg() else: self.close() @@ -66,6 +70,32 @@ class SiteMsgWebsocket(JsonWebsocketConsumer): if not self.sub: return self.sub.unsubscribe() - session = self.scope['session'] - redis_client = cache.client.get_client() - redis_client.srem(WS_SESSION_KEY, session.session_key) + + user_session_manager.decrement_or_remove(self.session.session_key) + if self.should_delete_session(): + thread = Thread(target=self.delay_delete_session) + thread.start() + + def should_delete_session(self): + return (self.session.modified or settings.SESSION_SAVE_EVERY_REQUEST) and \ + not self.session.is_empty() and \ + self.session.get_expire_at_browser_close() and \ + not user_session_manager.check_active(self.session.session_key) + + def delay_delete_session(self): + timeout = 6 + check_interval = 0.5 + + start_time = time.time() + while time.time() - start_time < timeout: + time.sleep(check_interval) + if user_session_manager.check_active(self.session.session_key): + return + + self.delete_session() + + def delete_session(self): + try: + self.session.delete() + except Exception as e: + logger.info(f'delete session error: {e}') diff --git a/apps/ops/ansible/callback.py b/apps/ops/ansible/callback.py index d5fb3a35e..d05158725 100644 --- a/apps/ops/ansible/callback.py +++ b/apps/ops/ansible/callback.py @@ -1,3 +1,4 @@ +import os from collections import defaultdict from functools import reduce @@ -29,6 +30,8 @@ class DefaultCallback: ) self.status = 'running' self.finished = False + self.local_pid = 0 + self.private_data_dir = None @property def host_results(self): @@ -45,6 +48,9 @@ class DefaultCallback: event = data.get('event', None) if not event: return + pid = data.get('pid', None) + if pid: + self.write_pid(pid) event_data = data.get('event_data', {}) host = event_data.get('remote_addr', '') task = event_data.get('task', '') @@ -152,3 +158,11 @@ class DefaultCallback: def status_handler(self, data, **kwargs): status = data.get('status', '') self.status = self.STATUS_MAPPER.get(status, 'unknown') + + rc = kwargs.get('runner_config', None) + self.private_data_dir = rc.private_data_dir if rc else '/tmp/' + + def write_pid(self, pid): + pid_filepath = os.path.join(self.private_data_dir, 'local.pid') + with open(pid_filepath, 'w') as f: + f.write(str(pid)) diff --git a/apps/ops/api/celery.py b/apps/ops/api/celery.py index 797d00c5e..dd66a886e 100644 --- a/apps/ops/api/celery.py +++ b/apps/ops/api/celery.py @@ -2,6 +2,7 @@ # import os import re +from collections import defaultdict from celery.result import AsyncResult from django.shortcuts import get_object_or_404 @@ -166,16 +167,58 @@ class CeleryTaskViewSet( i.next_exec_time = now + next_run_at return queryset + def generate_summary_state(self, execution_qs): + model = self.get_queryset().model + executions = execution_qs.order_by('-date_published').values('name', 'state') + summary_state_dict = defaultdict( + lambda: { + 'states': [], 'state': 'green', + 'summary': {'total': 0, 'success': 0} + } + ) + for execution in executions: + name = execution['name'] + state = execution['state'] + + summary = summary_state_dict[name]['summary'] + + summary['total'] += 1 + summary['success'] += 1 if state == 'SUCCESS' else 0 + + states = summary_state_dict[name].get('states') + if states is not None and len(states) >= 5: + color = model.compute_state_color(states) + summary_state_dict[name]['state'] = color + summary_state_dict[name].pop('states', None) + elif isinstance(states, list): + states.append(state) + + return summary_state_dict + + def loading_summary_state(self, queryset): + if isinstance(queryset, list): + names = [i.name for i in queryset] + execution_qs = CeleryTaskExecution.objects.filter(name__in=names) + else: + execution_qs = CeleryTaskExecution.objects.all() + summary_state_dict = self.generate_summary_state(execution_qs) + for i in queryset: + i.summary = summary_state_dict.get(i.name, {}).get('summary', {}) + i.state = summary_state_dict.get(i.name, {}).get('state', 'green') + return queryset + def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: page = self.generate_execute_time(page) + page = self.loading_summary_state(page) serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) queryset = self.generate_execute_time(queryset) + queryset = self.loading_summary_state(queryset) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) diff --git a/apps/ops/api/job.py b/apps/ops/api/job.py index eb908d04c..a2a0c00ee 100644 --- a/apps/ops/api/job.py +++ b/apps/ops/api/job.py @@ -1,9 +1,11 @@ import json import os +from celery.result import AsyncResult from django.conf import settings from django.db import transaction from django.db.models import Count +from django.http import Http404 from django.shortcuts import get_object_or_404 from django.utils._os import safe_join from django.utils.translation import gettext_lazy as _ @@ -14,9 +16,10 @@ from rest_framework.views import APIView from assets.models import Asset from common.const.http import POST from common.permissions import IsValidUser +from ops.celery import app from ops.const import Types from ops.models import Job, JobExecution -from ops.serializers.job import JobSerializer, JobExecutionSerializer, FileSerializer +from ops.serializers.job import JobSerializer, JobExecutionSerializer, FileSerializer, JobTaskStopSerializer __all__ = [ 'JobViewSet', 'JobExecutionViewSet', 'JobRunVariableHelpAPIView', @@ -187,6 +190,33 @@ class JobExecutionViewSet(OrgBulkModelViewSet): queryset = queryset.filter(creator=self.request.user) return queryset + @action(methods=[POST], detail=False, serializer_class=JobTaskStopSerializer, permission_classes=[IsValidUser, ], + url_path='stop') + def stop(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + if not serializer.is_valid(): + return Response({'error': serializer.errors}, status=400) + task_id = serializer.validated_data['task_id'] + try: + instance = get_object_or_404(JobExecution, task_id=task_id, creator=request.user) + except Http404: + return Response( + {'error': _('The task is being created and cannot be interrupted. Please try again later.')}, + status=400 + ) + + task = AsyncResult(task_id, app=app) + inspect = app.control.inspect() + for worker in inspect.registered().keys(): + if task_id not in [at['id'] for at in inspect.active().get(worker, [])]: + # 在队列中未执行使用revoke执行 + task.revoke(terminate=True) + instance.set_error('Job stop by "revoke task {}"'.format(task_id)) + return Response({'task_id': task_id}, status=200) + + instance.stop() + return Response({'task_id': task_id}, status=200) + class JobAssetDetail(APIView): rbac_perms = { diff --git a/apps/ops/models/celery.py b/apps/ops/models/celery.py index f17ffe685..ef1fab463 100644 --- a/apps/ops/models/celery.py +++ b/apps/ops/models/celery.py @@ -15,6 +15,9 @@ class CeleryTask(models.Model): name = models.CharField(max_length=1024, verbose_name=_('Name')) date_last_publish = models.DateTimeField(null=True, verbose_name=_("Date last publish")) + __summary = None + __state = None + @property def meta(self): task = app.tasks.get(self.name, None) @@ -25,23 +28,43 @@ class CeleryTask(models.Model): @property def summary(self): + if self.__summary is not None: + return self.__summary executions = CeleryTaskExecution.objects.filter(name=self.name) total = executions.count() success = executions.filter(state='SUCCESS').count() return {'total': total, 'success': success} + @summary.setter + def summary(self, value): + self.__summary = value + + @staticmethod + def compute_state_color(states: list, default_count=5): + color = 'green' + states = states[:default_count] + if not states: + return color + if states[0] == 'FAILURE': + color = 'red' + elif 'FAILURE' in states: + color = 'yellow' + return color + @property def state(self): - last_five_executions = CeleryTaskExecution.objects.filter(name=self.name).order_by('-date_published')[:5] + if self.__state is not None: + return self.__state + last_five_executions = CeleryTaskExecution.objects.filter( + name=self.name + ).order_by('-date_published').values('state')[:5] + states = [i['state'] for i in last_five_executions] + color = self.compute_state_color(states) + return color - if len(last_five_executions) > 0: - if last_five_executions[0].state == 'FAILURE': - return "red" - - for execution in last_five_executions: - if execution.state == 'FAILURE': - return "yellow" - return "green" + @state.setter + def state(self, value): + self.__state = value class Meta: verbose_name = _("Celery Task") diff --git a/apps/ops/models/job.py b/apps/ops/models/job.py index 9fcc079ca..f7831251b 100644 --- a/apps/ops/models/job.py +++ b/apps/ops/models/job.py @@ -67,6 +67,7 @@ class JMSPermedInventory(JMSInventory): 'postgresql': ['postgresql'], 'sqlserver': ['sqlserver'], 'ssh': ['shell', 'python', 'win_shell', 'raw'], + 'winrm': ['win_shell', 'shell'], } if self.module not in protocol_supported_modules_mapping.get(protocol.name, []): @@ -553,6 +554,15 @@ class JobExecution(JMSOrgBaseModel): finally: ssh_tunnel.local_gateway_clean(runner) + def stop(self): + with open(os.path.join(self.private_dir, 'local.pid')) as f: + try: + pid = f.read() + os.kill(int(pid), 9) + except Exception as e: + print(e) + self.set_error('Job stop by "kill -9 {}"'.format(pid)) + class Meta: verbose_name = _("Job Execution") ordering = ['-date_created'] diff --git a/apps/ops/serializers/job.py b/apps/ops/serializers/job.py index 75729f988..ce4faee55 100644 --- a/apps/ops/serializers/job.py +++ b/apps/ops/serializers/job.py @@ -57,6 +57,13 @@ class FileSerializer(serializers.Serializer): ref_name = "JobFileSerializer" +class JobTaskStopSerializer(serializers.Serializer): + task_id = serializers.CharField(max_length=128) + + class Meta: + ref_name = "JobTaskStopSerializer" + + class JobExecutionSerializer(BulkOrgResourceModelSerializer): creator = ReadableHiddenField(default=serializers.CurrentUserDefault()) job_type = serializers.ReadOnlyField(label=_("Job type")) diff --git a/apps/orgs/models.py b/apps/orgs/models.py index e667ac4d7..223e41e38 100644 --- a/apps/orgs/models.py +++ b/apps/orgs/models.py @@ -173,6 +173,9 @@ class Organization(OrgRoleMixin, JMSBaseModel): def is_default(self): return str(self.id) == self.DEFAULT_ID + def is_system(self): + return str(self.id) == self.SYSTEM_ID + @property def internal(self): return str(self.id) in self.INTERNAL_IDS diff --git a/apps/orgs/signal_handlers/cache.py b/apps/orgs/signal_handlers/cache.py index 4dc3c796e..aec38527a 100644 --- a/apps/orgs/signal_handlers/cache.py +++ b/apps/orgs/signal_handlers/cache.py @@ -87,7 +87,8 @@ class OrgResourceStatisticsRefreshUtil: if not cache_field_name: return org = getattr(instance, 'org', None) - cls.refresh_org_fields(((org, cache_field_name),)) + cache_field_name = tuple(cache_field_name) + cls.refresh_org_fields.delay(org_fields=((org, cache_field_name),)) @receiver(post_save) diff --git a/apps/orgs/utils.py b/apps/orgs/utils.py index 583bd2e7c..0efdcc2a7 100644 --- a/apps/orgs/utils.py +++ b/apps/orgs/utils.py @@ -6,6 +6,7 @@ from functools import wraps from inspect import signature from werkzeug.local import LocalProxy +from django.conf import settings from common.local import thread_local from .models import Organization @@ -14,7 +15,6 @@ from .models import Organization def get_org_from_request(request): # query中优先级最高 oid = request.GET.get("oid") - # 其次header if not oid: oid = request.META.get("HTTP_X_JMS_ORG") @@ -24,14 +24,33 @@ def get_org_from_request(request): # 其次session if not oid: oid = request.session.get("oid") + + if oid and oid.lower() == 'default': + return Organization.default() + + if oid and oid.lower() == 'root': + return Organization.root() + + if oid and oid.lower() == 'system': + return Organization.system() + + org = Organization.get_instance(oid) + + if org and org.internal: + # 内置组织直接返回 + return org + + if not settings.XPACK_ENABLED: + # 社区版用户只能使用默认组织 + return Organization.default() + + if not org and request.user.is_authenticated: + # 企业版用户优先从自己有权限的组织中获取 + org = request.user.orgs.first() + + if not org: + org = Organization.default() - if not oid: - oid = Organization.DEFAULT_ID - if oid.lower() == "default": - oid = Organization.DEFAULT_ID - elif oid.lower() == "root": - oid = Organization.ROOT_ID - org = Organization.get_instance(oid, default=Organization.default()) return org diff --git a/apps/perms/api/user_permission/assets.py b/apps/perms/api/user_permission/assets.py index 6db934c3b..676a21e5e 100644 --- a/apps/perms/api/user_permission/assets.py +++ b/apps/perms/api/user_permission/assets.py @@ -1,9 +1,11 @@ import abc +from django.conf import settings from rest_framework.generics import ListAPIView, RetrieveAPIView from assets.api.asset.asset import AssetFilterSet from assets.models import Asset, Node +from common.api.mixin import ExtraFilterFieldsMixin from common.utils import get_logger, lazyproperty, is_uuid from orgs.utils import tmp_to_root_org from perms import serializers @@ -37,8 +39,8 @@ class UserPermedAssetRetrieveApi(SelfOrPKUserMixin, RetrieveAPIView): return asset -class BaseUserPermedAssetsApi(SelfOrPKUserMixin, ListAPIView): - ordering = ('name',) +class BaseUserPermedAssetsApi(SelfOrPKUserMixin, ExtraFilterFieldsMixin, ListAPIView): + ordering = [] search_fields = ('name', 'address', 'comment') ordering_fields = ("name", "address") filterset_class = AssetFilterSet @@ -47,6 +49,8 @@ class BaseUserPermedAssetsApi(SelfOrPKUserMixin, ListAPIView): def get_queryset(self): if getattr(self, 'swagger_fake_view', False): return Asset.objects.none() + if settings.ASSET_SIZE == 'small': + self.ordering = ['name'] assets = self.get_assets() assets = self.serializer_class.setup_eager_loading(assets) return assets diff --git a/apps/perms/serializers/user_permission.py b/apps/perms/serializers/user_permission.py index 0bd9bdc02..e3441a04d 100644 --- a/apps/perms/serializers/user_permission.py +++ b/apps/perms/serializers/user_permission.py @@ -8,9 +8,9 @@ from rest_framework import serializers from accounts.models import Account from assets.const import Category, AllTypes from assets.models import Node, Asset, Platform -from assets.serializers.asset.common import AssetLabelSerializer, AssetProtocolsPermsSerializer -from common.serializers.fields import ObjectRelatedField, LabeledChoiceField +from assets.serializers.asset.common import AssetProtocolsPermsSerializer from common.serializers import ResourceLabelsMixin +from common.serializers.fields import ObjectRelatedField, LabeledChoiceField from orgs.mixins.serializers import OrgResourceModelSerializerMixin from perms.serializers.permission import ActionChoicesField diff --git a/apps/perms/utils/permission.py b/apps/perms/utils/permission.py index 036dabef2..859f579be 100644 --- a/apps/perms/utils/permission.py +++ b/apps/perms/utils/permission.py @@ -13,7 +13,7 @@ class AssetPermissionUtil(object): """ 资产授权相关的方法工具 """ @timeit - def get_permissions_for_user(self, user, with_group=True, flat=False): + def get_permissions_for_user(self, user, with_group=True, flat=False, with_expired=False): """ 获取用户的授权规则 """ perm_ids = set() # user @@ -25,7 +25,7 @@ class AssetPermissionUtil(object): groups = user.groups.all() group_perm_ids = self.get_permissions_for_user_groups(groups, flat=True) perm_ids.update(group_perm_ids) - perms = self.get_permissions(ids=perm_ids) + perms = self.get_permissions(ids=perm_ids, with_expired=with_expired) if flat: return perms.values_list('id', flat=True) return perms @@ -102,6 +102,8 @@ class AssetPermissionUtil(object): return model.objects.filter(id__in=ids) @staticmethod - def get_permissions(ids): - perms = AssetPermission.objects.filter(id__in=ids).valid().order_by('-date_expired') - return perms + def get_permissions(ids, with_expired=False): + perms = AssetPermission.objects.filter(id__in=ids) + if not with_expired: + perms = perms.valid() + return perms.order_by('-date_expired') diff --git a/apps/perms/utils/user_perm.py b/apps/perms/utils/user_perm.py index d06f18a83..1fc4e86bf 100644 --- a/apps/perms/utils/user_perm.py +++ b/apps/perms/utils/user_perm.py @@ -7,10 +7,10 @@ from django.db.models import Q from rest_framework.utils.encoders import JSONEncoder from assets.const import AllTypes -from assets.models import FavoriteAsset, Asset +from assets.models import FavoriteAsset, Asset, Node from common.utils.common import timeit, get_logger from orgs.utils import current_org, tmp_to_root_org -from perms.models import PermNode, UserAssetGrantedTreeNodeRelation +from perms.models import PermNode, UserAssetGrantedTreeNodeRelation, AssetPermission from .permission import AssetPermissionUtil __all__ = ['AssetPermissionPermAssetUtil', 'UserPermAssetUtil', 'UserPermNodeUtil'] @@ -21,38 +21,37 @@ logger = get_logger(__name__) class AssetPermissionPermAssetUtil: def __init__(self, perm_ids): - self.perm_ids = perm_ids + self.perm_ids = set(perm_ids) def get_all_assets(self): node_assets = self.get_perm_nodes_assets() direct_assets = self.get_direct_assets() # 比原来的查到所有 asset id 再搜索块很多,因为当资产量大的时候,搜索会很慢 - return (node_assets | direct_assets).distinct() + return (node_assets | direct_assets).order_by().distinct() - @timeit - def get_perm_nodes_assets(self, flat=False): - """ 获取所有授权节点下的资产 """ - from assets.models import Node - from ..models import AssetPermission + def get_perm_nodes(self): + """ 获取所有授权节点 """ nodes_ids = AssetPermission.objects \ .filter(id__in=self.perm_ids) \ .values_list('nodes', flat=True) + nodes_ids = set(nodes_ids) nodes = Node.objects.filter(id__in=nodes_ids).only('id', 'key') - assets = PermNode.get_nodes_all_assets(*nodes) - if flat: - return set(assets.values_list('id', flat=True)) + return nodes + + @timeit + def get_perm_nodes_assets(self): + """ 获取所有授权节点下的资产 """ + nodes = self.get_perm_nodes() + assets = PermNode.get_nodes_all_assets(*nodes, distinct=False) return assets @timeit - def get_direct_assets(self, flat=False): + def get_direct_assets(self): """ 获取直接授权的资产 """ - from ..models import AssetPermission - asset_ids = AssetPermission.objects \ - .filter(id__in=self.perm_ids) \ - .values_list('assets', flat=True) - assets = Asset.objects.filter(id__in=asset_ids).distinct() - if flat: - return set(assets.values_list('id', flat=True)) + asset_ids = AssetPermission.assets.through.objects \ + .filter(assetpermission_id__in=self.perm_ids) \ + .values_list('asset_id', flat=True) + assets = Asset.objects.filter(id__in=asset_ids) return assets diff --git a/apps/perms/utils/user_perm_tree.py b/apps/perms/utils/user_perm_tree.py index 13577a9b1..01090176e 100644 --- a/apps/perms/utils/user_perm_tree.py +++ b/apps/perms/utils/user_perm_tree.py @@ -72,7 +72,7 @@ class UserPermTreeRefreshUtil(_UserPermTreeCacheMixin): @timeit def refresh_if_need(self, force=False): - built_just_now = cache.get(self.cache_key_time) + built_just_now = False if settings.ASSET_SIZE == 'small' else cache.get(self.cache_key_time) if built_just_now: logger.info('Refresh user perm tree just now, pass: {}'.format(built_just_now)) return @@ -80,12 +80,18 @@ class UserPermTreeRefreshUtil(_UserPermTreeCacheMixin): if not to_refresh_orgs: logger.info('Not have to refresh orgs') return + logger.info("Delay refresh user orgs: {} {}".format(self.user, [o.name for o in to_refresh_orgs])) - refresh_user_orgs_perm_tree(user_orgs=((self.user, tuple(to_refresh_orgs)),)) - refresh_user_favorite_assets(users=(self.user,)) + sync = True if settings.ASSET_SIZE == 'small' else False + refresh_user_orgs_perm_tree.apply(sync=sync, user_orgs=((self.user, tuple(to_refresh_orgs)),)) + refresh_user_favorite_assets.apply(sync=sync, users=(self.user,)) @timeit def refresh_tree_manual(self): + """ + 用来手动 debug + :return: + """ built_just_now = cache.get(self.cache_key_time) if built_just_now: logger.info('Refresh just now, pass: {}'.format(built_just_now)) @@ -105,8 +111,9 @@ class UserPermTreeRefreshUtil(_UserPermTreeCacheMixin): return self._clean_user_perm_tree_for_legacy_org() - ttl = settings.PERM_TREE_REGEN_INTERVAL - cache.set(self.cache_key_time, int(time.time()), ttl) + if settings.ASSET_SIZE != 'small': + ttl = settings.PERM_TREE_REGEN_INTERVAL + cache.set(self.cache_key_time, int(time.time()), ttl) lock = UserGrantedTreeRebuildLock(self.user.id) got = lock.acquire(blocking=False) @@ -187,13 +194,20 @@ class UserPermTreeExpireUtil(_UserPermTreeCacheMixin): @on_transaction_commit def expire_perm_tree_for_users_orgs(self, user_ids, org_ids): + user_ids = list(user_ids) org_ids = [str(oid) for oid in org_ids] with self.client.pipeline() as p: for uid in user_ids: cache_key = self.get_cache_key(uid) p.srem(cache_key, *org_ids) p.execute() - logger.info('Expire perm tree for users: [{}], orgs: [{}]'.format(user_ids, org_ids)) + users_display = ','.join([str(i) for i in user_ids[:3]]) + if len(user_ids) > 3: + users_display += '...' + orgs_display = ','.join([str(i) for i in org_ids[:3]]) + if len(org_ids) > 3: + orgs_display += '...' + logger.info('Expire perm tree for users: [{}], orgs: [{}]'.format(users_display, orgs_display)) def expire_perm_tree_for_all_user(self): keys = self.client.keys(self.cache_key_all_user) diff --git a/apps/settings/api/ldap.py b/apps/settings/api/ldap.py index f13a2e9af..f8b052a90 100644 --- a/apps/settings/api/ldap.py +++ b/apps/settings/api/ldap.py @@ -1,28 +1,16 @@ # -*- coding: utf-8 -*- -# -import threading - -from django.conf import settings from django.utils.translation import gettext_lazy as _ from rest_framework import generics -from rest_framework.generics import CreateAPIView -from rest_framework.views import Response, APIView +from rest_framework.views import Response -from common.api import AsyncApiMixin from common.utils import get_logger -from orgs.models import Organization -from orgs.utils import current_org from users.models import User from ..models import Setting -from ..serializers import ( - LDAPTestConfigSerializer, LDAPUserSerializer, - LDAPTestLoginSerializer -) -from ..tasks import sync_ldap_user +from ..serializers import LDAPUserSerializer from ..utils import ( - LDAPServerUtil, LDAPCacheUtil, LDAPImportUtil, LDAPSyncUtil, - LDAP_USE_CACHE_FLAGS, LDAPTestUtil + LDAPServerUtil, LDAPCacheUtil, + LDAP_USE_CACHE_FLAGS ) logger = get_logger(__file__) @@ -100,49 +88,3 @@ class LDAPUserListApi(generics.ListAPIView): else: data = {'msg': _('Users are not synchronized, please click the user synchronization button')} return Response(data=data, status=400) - - -class LDAPUserImportAPI(APIView): - perm_model = Setting - rbac_perms = { - 'POST': 'settings.change_auth' - } - - def get_orgs(self): - org_ids = self.request.data.get('org_ids') - if org_ids: - orgs = list(Organization.objects.filter(id__in=org_ids)) - else: - orgs = [current_org] - return orgs - - def get_ldap_users(self): - username_list = self.request.data.get('username_list', []) - cache_police = self.request.query_params.get('cache_police', True) - if '*' in username_list: - users = LDAPServerUtil().search() - elif cache_police in LDAP_USE_CACHE_FLAGS: - users = LDAPCacheUtil().search(search_users=username_list) - else: - users = LDAPServerUtil().search(search_users=username_list) - return users - - def post(self, request): - try: - users = self.get_ldap_users() - except Exception as e: - return Response({'error': str(e)}, status=400) - - if users is None: - return Response({'msg': _('Get ldap users is None')}, status=400) - - orgs = self.get_orgs() - new_users, errors = LDAPImportUtil().perform_import(users, orgs) - if errors: - return Response({'errors': errors}, status=400) - - count = users if users is None else len(users) - orgs_name = ', '.join([str(org) for org in orgs]) - return Response({ - 'msg': _('Imported {} users successfully (Organization: {})').format(count, orgs_name) - }) diff --git a/apps/settings/api/public.py b/apps/settings/api/public.py index 81abfeb99..9808ea1c6 100644 --- a/apps/settings/api/public.py +++ b/apps/settings/api/public.py @@ -3,6 +3,7 @@ from rest_framework import generics from rest_framework.permissions import AllowAny from authentication.permissions import IsValidUserOrConnectionToken +from common.const.choices import COUNTRY_CALLING_CODES from common.utils import get_logger, lazyproperty from common.utils.timezone import local_now from .. import serializers @@ -24,7 +25,8 @@ class OpenPublicSettingApi(generics.RetrieveAPIView): def get_object(self): return { "XPACK_ENABLED": settings.XPACK_ENABLED, - "INTERFACE": self.interface_setting + "INTERFACE": self.interface_setting, + "COUNTRY_CALLING_CODES": COUNTRY_CALLING_CODES } diff --git a/apps/settings/serializers/auth/oauth2.py b/apps/settings/serializers/auth/oauth2.py index 56ddd6a66..b5a0dbb62 100644 --- a/apps/settings/serializers/auth/oauth2.py +++ b/apps/settings/serializers/auth/oauth2.py @@ -43,7 +43,7 @@ class OAuth2SettingSerializer(serializers.Serializer): ) AUTH_OAUTH2_ACCESS_TOKEN_METHOD = serializers.ChoiceField( default='GET', label=_('Client authentication method'), - choices=(('GET', 'GET'), ('POST', 'POST')) + choices=(('GET', 'GET'), ('POST', 'POST-DATA'), ('POST_JSON', 'POST-JSON')) ) AUTH_OAUTH2_PROVIDER_USERINFO_ENDPOINT = serializers.CharField( required=True, max_length=1024, label=_('Provider userinfo endpoint') diff --git a/apps/settings/serializers/cleaning.py b/apps/settings/serializers/cleaning.py index 17aa94710..156c007d1 100644 --- a/apps/settings/serializers/cleaning.py +++ b/apps/settings/serializers/cleaning.py @@ -22,6 +22,10 @@ class CleaningSerializer(serializers.Serializer): min_value=MIN_VALUE, max_value=9999, label=_("Operate log keep days (day)"), ) + PASSWORD_CHANGE_LOG_KEEP_DAYS = serializers.IntegerField( + min_value=MIN_VALUE, max_value=9999, + label=_("password change log keep days (day)"), + ) FTP_LOG_KEEP_DAYS = serializers.IntegerField( min_value=MIN_VALUE, max_value=9999, label=_("FTP log keep days (day)"), diff --git a/apps/settings/serializers/feature.py b/apps/settings/serializers/feature.py index a1a734d54..ca3987029 100644 --- a/apps/settings/serializers/feature.py +++ b/apps/settings/serializers/feature.py @@ -109,6 +109,7 @@ class TicketSettingSerializer(serializers.Serializer): PREFIX_TITLE = _('Ticket') TICKETS_ENABLED = serializers.BooleanField(required=False, default=True, label=_("Enable tickets")) + TICKETS_DIRECT_APPROVE = serializers.BooleanField(required=False, default=False, label=_("No login approval")) TICKET_AUTHORIZE_DEFAULT_TIME = serializers.IntegerField( min_value=1, max_value=999999, required=False, label=_("Ticket authorize default time") diff --git a/apps/settings/serializers/public.py b/apps/settings/serializers/public.py index 6e5a74c8e..b4d66671e 100644 --- a/apps/settings/serializers/public.py +++ b/apps/settings/serializers/public.py @@ -11,6 +11,7 @@ __all__ = [ class PublicSettingSerializer(serializers.Serializer): XPACK_ENABLED = serializers.BooleanField() INTERFACE = serializers.DictField() + COUNTRY_CALLING_CODES = serializers.ListField() class PrivateSettingSerializer(PublicSettingSerializer): @@ -50,6 +51,7 @@ class PrivateSettingSerializer(PublicSettingSerializer): ANNOUNCEMENT = serializers.DictField() TICKETS_ENABLED = serializers.BooleanField() + TICKETS_DIRECT_APPROVE = serializers.BooleanField() CONNECTION_TOKEN_REUSABLE = serializers.BooleanField() CACHE_LOGIN_PASSWORD_ENABLED = serializers.BooleanField() VAULT_ENABLED = serializers.BooleanField() diff --git a/apps/settings/templates/ldap/_msg_import_ldap_user.html b/apps/settings/templates/ldap/_msg_import_ldap_user.html index f801dde36..feb00cd34 100644 --- a/apps/settings/templates/ldap/_msg_import_ldap_user.html +++ b/apps/settings/templates/ldap/_msg_import_ldap_user.html @@ -14,9 +14,13 @@ {% trans "Synced User" %}:
    - {% for user in users %} -
  • {{ user }}
  • - {% endfor %} + {% if users %} + {% for user in users %} +
  • {{ user }}
  • + {% endfor %} + {% else %} +
  • {% trans 'No user synchronization required' %}
  • + {% endif %}
{% if errors %} {% trans 'Error' %}: diff --git a/apps/settings/urls/api_urls.py b/apps/settings/urls/api_urls.py index fdfae5146..15b97c82c 100644 --- a/apps/settings/urls/api_urls.py +++ b/apps/settings/urls/api_urls.py @@ -12,7 +12,6 @@ router.register(r'chatai-prompts', api.ChatPromptViewSet, 'chatai-prompt') urlpatterns = [ path('mail/testing/', api.MailTestingAPI.as_view(), name='mail-testing'), path('ldap/users/', api.LDAPUserListApi.as_view(), name='ldap-user-list'), - path('ldap/users/import/', api.LDAPUserImportAPI.as_view(), name='ldap-user-import'), path('wecom/testing/', api.WeComTestingAPI.as_view(), name='wecom-testing'), path('dingtalk/testing/', api.DingTalkTestingAPI.as_view(), name='dingtalk-testing'), path('feishu/testing/', api.FeiShuTestingAPI.as_view(), name='feishu-testing'), diff --git a/apps/settings/ws.py b/apps/settings/ws.py index 0f8f344fe..7e4f8853b 100644 --- a/apps/settings/ws.py +++ b/apps/settings/ws.py @@ -6,6 +6,7 @@ import asyncio from channels.generic.websocket import AsyncJsonWebsocketConsumer from django.core.cache import cache from django.conf import settings +from django.utils.translation import gettext_lazy as _ from common.db.utils import close_old_connections from common.utils import get_logger @@ -13,9 +14,12 @@ from settings.serializers import ( LDAPTestConfigSerializer, LDAPTestLoginSerializer ) +from orgs.models import Organization +from orgs.utils import current_org from settings.tasks import sync_ldap_user from settings.utils import ( - LDAPSyncUtil, LDAPTestUtil + LDAPServerUtil, LDAPCacheUtil, LDAPImportUtil, LDAPSyncUtil, + LDAP_USE_CACHE_FLAGS, LDAPTestUtil ) from .tools import ( verbose_ping, verbose_telnet, verbose_nmap, @@ -27,9 +31,11 @@ logger = get_logger(__name__) CACHE_KEY_LDAP_TEST_CONFIG_MSG = 'CACHE_KEY_LDAP_TEST_CONFIG_MSG' CACHE_KEY_LDAP_TEST_LOGIN_MSG = 'CACHE_KEY_LDAP_TEST_LOGIN_MSG' CACHE_KEY_LDAP_SYNC_USER_MSG = 'CACHE_KEY_LDAP_SYNC_USER_MSG' +CACHE_KEY_LDAP_IMPORT_USER_MSG = 'CACHE_KEY_LDAP_IMPORT_USER_MSG' CACHE_KEY_LDAP_TEST_CONFIG_TASK_STATUS = 'CACHE_KEY_LDAP_TEST_CONFIG_TASK_STATUS' CACHE_KEY_LDAP_TEST_LOGIN_TASK_STATUS = 'CACHE_KEY_LDAP_TEST_LOGIN_TASK_STATUS' CACHE_KEY_LDAP_SYNC_USER_TASK_STATUS = 'CACHE_KEY_LDAP_SYNC_USER_TASK_STATUS' +CACHE_KEY_LDAP_IMPORT_USER_TASK_STATUS = 'CACHE_KEY_LDAP_IMPORT_USER_TASK_STATUS' TASK_STATUS_IS_RUNNING = 'RUNNING' TASK_STATUS_IS_OVER = 'OVER' @@ -117,6 +123,8 @@ class LdapWebsocket(AsyncJsonWebsocketConsumer): ok, msg = cache.get(CACHE_KEY_LDAP_TEST_CONFIG_MSG) elif msg_type == 'sync_user': ok, msg = cache.get(CACHE_KEY_LDAP_SYNC_USER_MSG) + elif msg_type == 'import_user': + ok, msg = cache.get(CACHE_KEY_LDAP_IMPORT_USER_MSG) else: ok, msg = cache.get(CACHE_KEY_LDAP_TEST_LOGIN_MSG) await self.send_msg(ok, msg) @@ -165,8 +173,8 @@ class LdapWebsocket(AsyncJsonWebsocketConsumer): cache.set(task_key, TASK_STATUS_IS_OVER, ttl) @staticmethod - def set_task_msg(task_key, ok, msg): - cache.set(task_key, (ok, msg), 120) + def set_task_msg(task_key, ok, msg, ttl=120): + cache.set(task_key, (ok, msg), ttl) def run_testing_config(self, data): while True: @@ -207,3 +215,53 @@ class LdapWebsocket(AsyncJsonWebsocketConsumer): ok = False if msg else True self.set_task_status_over(CACHE_KEY_LDAP_SYNC_USER_TASK_STATUS) self.set_task_msg(CACHE_KEY_LDAP_SYNC_USER_MSG, ok, msg) + + def run_import_user(self, data): + while True: + if self.task_is_over(CACHE_KEY_LDAP_IMPORT_USER_TASK_STATUS): + break + else: + ok, msg = self.import_user(data) + self.set_task_status_over(CACHE_KEY_LDAP_IMPORT_USER_TASK_STATUS, 3) + self.set_task_msg(CACHE_KEY_LDAP_IMPORT_USER_MSG, ok, msg, 3) + + def import_user(self, data): + ok = False + org_ids = data.get('org_ids') + username_list = data.get('username_list', []) + cache_police = data.get('cache_police', True) + try: + users = self.get_ldap_users(username_list, cache_police) + if users is None: + msg = _('Get ldap users is None') + + orgs = self.get_orgs(org_ids) + new_users, error_msg = LDAPImportUtil().perform_import(users, orgs) + if error_msg: + msg = error_msg + + count = users if users is None else len(users) + orgs_name = ', '.join([str(org) for org in orgs]) + ok = True + msg = _('Imported {} users successfully (Organization: {})').format(count, orgs_name) + except Exception as e: + msg = str(e) + return ok, msg + + @staticmethod + def get_orgs(org_ids): + if org_ids: + orgs = list(Organization.objects.filter(id__in=org_ids)) + else: + orgs = [current_org] + return orgs + + @staticmethod + def get_ldap_users(username_list, cache_police): + if '*' in username_list: + users = LDAPServerUtil().search() + elif cache_police in LDAP_USE_CACHE_FLAGS: + users = LDAPCacheUtil().search(search_users=username_list) + else: + users = LDAPServerUtil().search(search_users=username_list) + return users diff --git a/apps/terminal/api/applet/applet.py b/apps/terminal/api/applet/applet.py index 7f68d67d3..1a6b31815 100644 --- a/apps/terminal/api/applet/applet.py +++ b/apps/terminal/api/applet/applet.py @@ -9,7 +9,7 @@ from django.conf import settings from django.core.files.storage import default_storage from django.http import HttpResponse from django.shortcuts import get_object_or_404 -from django.utils.translation import gettext as _ +from django.utils.translation import gettext as _, get_language from rest_framework import viewsets from rest_framework.decorators import action from rest_framework.request import Request @@ -19,6 +19,8 @@ from rest_framework.serializers import ValidationError from common.api import JMSBulkModelViewSet from common.serializers import FileSerializer from common.utils import is_uuid +from common.utils.http import is_true +from common.utils.yml import yaml_load_with_i18n from terminal import serializers from terminal.models import AppletPublication, Applet @@ -106,9 +108,66 @@ class AppletViewSet(DownloadUploadMixin, JMSBulkModelViewSet): def get_object(self): pk = self.kwargs.get('pk') if not is_uuid(pk): - return get_object_or_404(Applet, name=pk) + obj = get_object_or_404(Applet, name=pk) else: - return get_object_or_404(Applet, pk=pk) + obj = get_object_or_404(Applet, pk=pk) + return self.trans_object(obj) + + def get_queryset(self): + queryset = super().get_queryset() + queryset = self.trans_queryset(queryset) + return queryset + + @staticmethod + def read_manifest_with_i18n(obj, lang='zh'): + path = os.path.join(obj.path, 'manifest.yml') + if os.path.exists(path): + with open(path, encoding='utf8') as f: + manifest = yaml_load_with_i18n(f, lang) + else: + manifest = {} + return manifest + + def trans_queryset(self, queryset): + for obj in queryset: + self.trans_object(obj) + return queryset + + @staticmethod + def readme(obj, lang=''): + lang = lang[:2] + readme_file = os.path.join(obj.path, f'README_{lang.upper()}.md') + if os.path.isfile(readme_file): + with open(readme_file, 'r') as f: + return f.read() + return '' + + def trans_object(self, obj): + lang = get_language() + manifest = self.read_manifest_with_i18n(obj, lang) + obj.display_name = manifest.get('display_name', obj.display_name) + obj.comment = manifest.get('comment', obj.comment) + obj.readme = self.readme(obj, lang) + return obj + + def is_record_found(self, obj, search): + combine_fields = ' '.join([getattr(obj, f, '') for f in self.search_fields]) + return search in combine_fields + + def filter_queryset(self, queryset): + search = self.request.query_params.get('search') + if search: + queryset = [i for i in queryset if self.is_record_found(i, search)] + + for field in self.filterset_fields: + field_value = self.request.query_params.get(field) + if not field_value: + continue + if field in ['is_active', 'builtin']: + field_value = is_true(field_value) + queryset = [i for i in queryset if getattr(i, field, '') == field_value] + + return queryset def perform_destroy(self, instance): if not instance.name: diff --git a/apps/terminal/api/component/endpoint.py b/apps/terminal/api/component/endpoint.py index b40aba9aa..9b573fc58 100644 --- a/apps/terminal/api/component/endpoint.py +++ b/apps/terminal/api/component/endpoint.py @@ -42,7 +42,7 @@ class SmartEndpointViewMixin: return endpoint def match_endpoint_by_label(self): - return Endpoint.match_by_instance_label(self.target_instance, self.target_protocol) + return Endpoint.match_by_instance_label(self.target_instance, self.target_protocol, self.request) def match_endpoint_by_target_ip(self): target_ip = self.request.GET.get('target_ip', '') # 支持target_ip参数,用来方便测试 diff --git a/apps/terminal/api/session/session.py b/apps/terminal/api/session/session.py index 8865801ac..400735f53 100644 --- a/apps/terminal/api/session/session.py +++ b/apps/terminal/api/session/session.py @@ -18,10 +18,11 @@ from rest_framework.response import Response from audits.const import ActionChoices from common.api import AsyncApiMixin -from common.const.http import GET +from common.const.http import GET, POST from common.drf.filters import BaseFilterSet from common.drf.filters import DatetimeRangeFilterBackend from common.drf.renders import PassthroughRenderer +from common.permissions import IsServiceAccount from common.storage.replay import ReplayStorageHandler from common.utils import data_to_json, is_uuid, i18n_fmt from common.utils import get_logger, get_object_or_none @@ -33,6 +34,7 @@ from terminal import serializers from terminal.const import TerminalType from terminal.models import Session from terminal.permissions import IsSessionAssignee +from terminal.session_lifecycle import lifecycle_events_map, reasons_map from terminal.utils import is_session_approver from users.models import User @@ -79,6 +81,7 @@ class SessionViewSet(RecordViewLogMixin, OrgBulkModelViewSet): serializer_classes = { 'default': serializers.SessionSerializer, 'display': serializers.SessionDisplaySerializer, + 'lifecycle_log': serializers.SessionLifecycleLogSerializer, } search_fields = [ "user", "asset", "account", "remote_addr", @@ -168,6 +171,23 @@ class SessionViewSet(RecordViewLogMixin, OrgBulkModelViewSet): count = queryset.count() return Response({'count': count}) + @action(methods=[POST], detail=True, permission_classes=[IsServiceAccount], url_path='lifecycle_log', + url_name='lifecycle_log') + def lifecycle_log(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + validated_data = serializer.validated_data + event = validated_data.pop('event', None) + event_class = lifecycle_events_map.get(event, None) + if not event_class: + return Response({'msg': f'event_name {event} invalid'}, status=400) + session = self.get_object() + reason = validated_data.pop('reason', None) + reason = reasons_map.get(reason, reason) + event_obj = event_class(session, reason, **validated_data) + activity_log = event_obj.create_activity_log() + return Response({'msg': 'ok', 'id': activity_log.id}) + def get_queryset(self): queryset = super().get_queryset() \ .prefetch_related('terminal') \ diff --git a/apps/terminal/applets/chrome/README_EN.md b/apps/terminal/applets/chrome/README_EN.md new file mode 100644 index 000000000..05240f598 --- /dev/null +++ b/apps/terminal/applets/chrome/README_EN.md @@ -0,0 +1,9 @@ +## Selenium Version + +- Selenium == 4.4.0 +- Chrome and ChromeDriver versions must match +- Driver [download address](https://chromedriver.chromium.org/downloads) + +## ChangeLog + +Refer to [ChangeLog](./ChangeLog) for some important updates. diff --git a/apps/terminal/applets/chrome/README_JA.md b/apps/terminal/applets/chrome/README_JA.md new file mode 100644 index 000000000..26336c9ba --- /dev/null +++ b/apps/terminal/applets/chrome/README_JA.md @@ -0,0 +1,9 @@ +## Selenium バージョン + +- Selenium == 4.4.0 +- Chrome と ChromeDriver のバージョンは一致している必要があります +- ドライバ [ダウンロードアドレス](https://chromedriver.chromium.org/downloads) + +## 変更ログ + +重要な更新については、[変更ログ](./ChangeLog) を参照してください diff --git a/apps/terminal/applets/chrome/README.md b/apps/terminal/applets/chrome/README_ZH.md similarity index 100% rename from apps/terminal/applets/chrome/README.md rename to apps/terminal/applets/chrome/README_ZH.md diff --git a/apps/terminal/applets/dbeaver/README_EN.md b/apps/terminal/applets/dbeaver/README_EN.md new file mode 100644 index 000000000..cc4165853 --- /dev/null +++ b/apps/terminal/applets/dbeaver/README_EN.md @@ -0,0 +1,4 @@ +## DBeaver + +- When connecting to a database application, it is necessary to download the driver. You can either install it offline + in advance or install the corresponding driver as prompted when connecting. diff --git a/apps/terminal/applets/dbeaver/README_JA.md b/apps/terminal/applets/dbeaver/README_JA.md new file mode 100644 index 000000000..5f2cd55ce --- /dev/null +++ b/apps/terminal/applets/dbeaver/README_JA.md @@ -0,0 +1,3 @@ +## DBeaver + +- データベースに接続する際には、ドライバをダウンロードする必要があります。事前にオフラインでインストールするか、接続時に表示される指示に従って該当するドライバをインストールしてください。 diff --git a/apps/terminal/applets/dbeaver/README.md b/apps/terminal/applets/dbeaver/README_ZH.md similarity index 100% rename from apps/terminal/applets/dbeaver/README.md rename to apps/terminal/applets/dbeaver/README_ZH.md diff --git a/apps/terminal/backends/command/db.py b/apps/terminal/backends/command/db.py index 1cdc56bda..207ec70e1 100644 --- a/apps/terminal/backends/command/db.py +++ b/apps/terminal/backends/command/db.py @@ -2,10 +2,10 @@ import datetime from django.db import transaction -from django.utils import timezone from django.db.utils import OperationalError -from common.utils.common import pretty_string +from django.utils import timezone +from common.utils.common import pretty_string from .base import CommandBase @@ -19,9 +19,10 @@ class CommandStore(CommandBase): """ 保存命令到数据库 """ + cmd_input = pretty_string(command['input']) self.model.objects.create( user=command["user"], asset=command["asset"], - account=command["account"], input=command["input"], + account=command["account"], input=cmd_input, output=command["output"], session=command["session"], risk_level=command.get("risk_level", 0), org_id=command["org_id"], timestamp=command["timestamp"] diff --git a/apps/terminal/models/component/endpoint.py b/apps/terminal/models/component/endpoint.py index d9d4cfab8..cdb9b0135 100644 --- a/apps/terminal/models/component/endpoint.py +++ b/apps/terminal/models/component/endpoint.py @@ -75,7 +75,20 @@ class Endpoint(JMSBaseModel): return endpoint @classmethod - def match_by_instance_label(cls, instance, protocol): + def handle_endpoint_host(cls, endpoint, request=None): + if not endpoint.host and request: + # 动态添加 current request host + host_port = request.get_host() + # IPv6 + if host_port.startswith('['): + host = host_port.split(']:')[0].rstrip(']') + ']' + else: + host = host_port.split(':')[0] + endpoint.host = host + return endpoint + + @classmethod + def match_by_instance_label(cls, instance, protocol, request=None): from assets.models import Asset from terminal.models import Session if isinstance(instance, Session): @@ -88,6 +101,7 @@ class Endpoint(JMSBaseModel): endpoints = cls.objects.filter(name__in=list(values)).order_by('-date_updated') for endpoint in endpoints: if endpoint.is_valid_for(instance, protocol): + endpoint = cls.handle_endpoint_host(endpoint, request) return endpoint @@ -130,13 +144,5 @@ class EndpointRule(JMSBaseModel): endpoint = endpoint_rule.endpoint else: endpoint = Endpoint.get_or_create_default(request) - if not endpoint.host and request: - # 动态添加 current request host - host_port = request.get_host() - # IPv6 - if host_port.startswith('['): - host = host_port.split(']:')[0].rstrip(']') + ']' - else: - host = host_port.split(':')[0] - endpoint.host = host + endpoint = Endpoint.handle_endpoint_host(endpoint, request) return endpoint diff --git a/apps/terminal/models/component/terminal.py b/apps/terminal/models/component/terminal.py index a76d67dc6..0337fce69 100644 --- a/apps/terminal/models/component/terminal.py +++ b/apps/terminal/models/component/terminal.py @@ -19,6 +19,7 @@ logger = get_logger(__file__) class TerminalStatusMixin: id: str + type: str ALIVE_KEY = 'TERMINAL_ALIVE_{}' status_set: models.Manager @@ -29,7 +30,7 @@ class TerminalStatusMixin: @lazyproperty def load(self): from ...utils import ComputeLoadUtil - return ComputeLoadUtil.compute_load(self.last_stat) + return ComputeLoadUtil.compute_load(self.last_stat, self.type) @property def is_alive(self): diff --git a/apps/terminal/serializers/command.py b/apps/terminal/serializers/command.py index 11b16f5ad..0c2e9c949 100644 --- a/apps/terminal/serializers/command.py +++ b/apps/terminal/serializers/command.py @@ -15,7 +15,7 @@ class SimpleSessionCommandSerializer(serializers.ModelSerializer): """ 简单Session命令序列类, 用来提取公共字段 """ user = serializers.CharField(label=_("User")) # 限制 64 字符,见 validate_user asset = serializers.CharField(max_length=128, label=_("Asset")) - input = serializers.CharField(max_length=2048, label=_("Command")) + input = serializers.CharField(label=_("Command")) session = serializers.CharField(max_length=36, label=_("Session ID")) risk_level = LabeledChoiceField( choices=RiskLevelChoices.choices, diff --git a/apps/terminal/serializers/session.py b/apps/terminal/serializers/session.py index ba8ecfdf8..74c87dfb0 100644 --- a/apps/terminal/serializers/session.py +++ b/apps/terminal/serializers/session.py @@ -4,6 +4,7 @@ from rest_framework import serializers from common.serializers.fields import LabeledChoiceField from common.utils import pretty_string from orgs.mixins.serializers import BulkOrgResourceModelSerializer +from terminal.session_lifecycle import lifecycle_events_map from .terminal import TerminalSmallSerializer from ..const import SessionType, SessionErrorReason from ..models import Session @@ -11,6 +12,7 @@ from ..models import Session __all__ = [ 'SessionSerializer', 'SessionDisplaySerializer', 'ReplaySerializer', 'SessionJoinValidateSerializer', + 'SessionLifecycleLogSerializer' ] @@ -77,3 +79,9 @@ class ReplaySerializer(serializers.Serializer): class SessionJoinValidateSerializer(serializers.Serializer): user_id = serializers.UUIDField() session_id = serializers.UUIDField() + + +class SessionLifecycleLogSerializer(serializers.Serializer): + event = serializers.ChoiceField(choices=list(lifecycle_events_map.keys())) + reason = serializers.CharField(required=False) + user = serializers.CharField(required=False) diff --git a/apps/terminal/session_lifecycle.py b/apps/terminal/session_lifecycle.py new file mode 100644 index 000000000..3de63d676 --- /dev/null +++ b/apps/terminal/session_lifecycle.py @@ -0,0 +1,176 @@ +from django.utils.translation import gettext_noop + +from audits.const import ActivityChoices +from audits.models import ActivityLog +from common.utils import i18n_fmt +from terminal.models import Session + + +class SessionLifecycleEventBase(object): + + def __init__(self, session: Session, reason, *args, **kwargs): + self.session = session + self.reason = reason + + def detail(self): + raise NotImplementedError + + def create_activity_log(self): + log_obj = ActivityLog.objects.create( + resource_id=self.session.id, + type=ActivityChoices.session_log, + detail=self.detail(), + org_id=self.session.org_id + ) + return log_obj + + +class AssetConnectSuccess(SessionLifecycleEventBase): + name = "asset_connect_success" + i18n_text = gettext_noop("Connect to asset %s success") + + def detail(self): + return i18n_fmt(self.i18n_text, self.session.asset) + + +class AssetConnectFinished(SessionLifecycleEventBase): + name = "asset_connect_finished" + i18n_text = gettext_noop("Connect to asset %s finished: %s") + + def detail(self): + asset = self.session.asset + reason = self.reason + return i18n_fmt(self.i18n_text, asset, reason) + + +class UserCreateShareLink(SessionLifecycleEventBase): + name = "create_share_link" + i18n_text = gettext_noop("User %s create share link") + + def detail(self): + user = self.session.user + return i18n_fmt(self.i18n_text, user) + + +class UserJoinSession(SessionLifecycleEventBase): + name = "user_join_session" + i18n_text = gettext_noop("User %s join session") + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.user = kwargs.get("user") + + def detail(self): + return i18n_fmt(self.i18n_text, self.user) + + +class UserLeaveSession(SessionLifecycleEventBase): + name = "user_leave_session" + i18n_text = gettext_noop("User %s leave session") + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.user = kwargs.get("user") + + def detail(self): + return i18n_fmt(self.i18n_text, self.user) + + +class AdminJoinMonitor(SessionLifecycleEventBase): + name = "admin_join_monitor" + i18n_text = gettext_noop("User %s join to monitor session") + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.user = kwargs.get("user") + + def detail(self): + return i18n_fmt(self.i18n_text, self.user) + + +class AdminExitMonitor(SessionLifecycleEventBase): + name = "admin_exit_monitor" + i18n_text = gettext_noop("User %s exit to monitor session") + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.user = kwargs.get("user") + + def detail(self): + return i18n_fmt(self.i18n_text, self.user) + + +class ReplayConvertStart(SessionLifecycleEventBase): + name = "replay_convert_start" + i18n_text = gettext_noop("Replay start to convert") + + def detail(self): + return self.i18n_text + + +class ReplayConvertSuccess(SessionLifecycleEventBase): + name = "replay_convert_success" + i18n_text = gettext_noop("Replay successfully converted to MP4 format") + + def detail(self): + return self.i18n_text + + +class ReplayConvertFailure(SessionLifecycleEventBase): + name = "replay_convert_failure" + i18n_text = gettext_noop("Replay failed to convert to MP4 format: %s") + + def detail(self): + return i18n_fmt(self.i18n_text, self.reason) + + +class ReplayUploadStart(SessionLifecycleEventBase): + name = "replay_upload_start" + i18n_text = gettext_noop("Replay start to upload") + + def detail(self): + return self.i18n_text + + +class ReplayUploadSuccess(SessionLifecycleEventBase): + name = "replay_upload_success" + i18n_text = gettext_noop("Replay successfully uploaded") + + def detail(self): + return self.i18n_text + + +class ReplayUploadFailure(SessionLifecycleEventBase): + name = "replay_upload_failure" + i18n_text = gettext_noop("Replay failed to upload: %s") + + def detail(self): + return i18n_fmt(self.i18n_text, self.reason) + + +reasons_map = { + 'connect_failed': gettext_noop('connect failed'), + 'connect_disconnect': gettext_noop('connection disconnect'), + 'user_close': gettext_noop('user closed'), + 'idle_disconnect': gettext_noop('idle disconnect'), + 'admin_terminate': gettext_noop('admin terminated'), + 'max_session_timeout': gettext_noop('maximum session time has been reached'), + 'permission_expired': gettext_noop('permission has expired'), + 'null_storage': gettext_noop('storage is null'), +} + +lifecycle_events_map = { + AssetConnectSuccess.name: AssetConnectSuccess, + AssetConnectFinished.name: AssetConnectFinished, + UserCreateShareLink.name: UserCreateShareLink, + UserJoinSession.name: UserJoinSession, + UserLeaveSession.name: UserLeaveSession, + AdminJoinMonitor.name: AdminJoinMonitor, + AdminExitMonitor.name: AdminExitMonitor, + ReplayConvertStart.name: ReplayConvertStart, + ReplayConvertSuccess.name: ReplayConvertSuccess, + ReplayConvertFailure.name: ReplayConvertFailure, + ReplayUploadStart.name: ReplayUploadStart, + ReplayUploadSuccess.name: ReplayUploadSuccess, + ReplayUploadFailure.name: ReplayUploadFailure, +} diff --git a/apps/terminal/signal_handlers/session_sharing.py b/apps/terminal/signal_handlers/session_sharing.py index f20ccf665..6af1f40e8 100644 --- a/apps/terminal/signal_handlers/session_sharing.py +++ b/apps/terminal/signal_handlers/session_sharing.py @@ -3,6 +3,7 @@ from django.dispatch import receiver from terminal.models import SessionSharing from terminal.notifications import SessionSharingMessage +from terminal.session_lifecycle import UserCreateShareLink @receiver(post_save, sender=SessionSharing) @@ -11,3 +12,7 @@ def on_session_sharing_created(sender, instance: SessionSharing, created, **kwar return for user in instance.users_queryset: SessionSharingMessage(user, instance).publish_async() + + # 创建会话分享活动日志 + session = instance.session + UserCreateShareLink(session, None).create_activity_log() diff --git a/apps/terminal/utils/components.py b/apps/terminal/utils/components.py index 2c3786dbf..692fe28fd 100644 --- a/apps/terminal/utils/components.py +++ b/apps/terminal/utils/components.py @@ -3,7 +3,7 @@ from itertools import groupby from common.utils import get_logger -from terminal.const import ComponentLoad +from terminal.const import ComponentLoad, TerminalType logger = get_logger(__name__) @@ -38,9 +38,13 @@ class ComputeLoadUtil: return system_status @classmethod - def compute_load(cls, stat): + def compute_load(cls, stat, terminal_type=None): if not stat: - return ComponentLoad.offline + # TODO The core component and celery component will return true for the time being. + if terminal_type in [TerminalType.core, TerminalType.celery]: + return ComponentLoad.normal + else: + return ComponentLoad.offline system_status_values = cls._compute_system_stat_status(stat).values() if ComponentLoad.critical in system_status_values: return ComponentLoad.critical diff --git a/apps/tickets/api/__init__.py b/apps/tickets/api/__init__.py index 645133d8e..1c66b843b 100644 --- a/apps/tickets/api/__init__.py +++ b/apps/tickets/api/__init__.py @@ -5,3 +5,4 @@ from .ticket import * from .comment import * from .relation import * from .super_ticket import * +from .perms import * diff --git a/apps/tickets/api/perms.py b/apps/tickets/api/perms.py new file mode 100644 index 000000000..fb7d7a138 --- /dev/null +++ b/apps/tickets/api/perms.py @@ -0,0 +1,66 @@ +from django.conf import settings + +from assets.models import Asset, Node +from assets.serializers.asset.common import MiniAssetSerializer +from assets.serializers.node import NodeSerializer +from common.api import SuggestionMixin +from orgs.mixins.api import OrgReadonlyModelViewSet +from perms.utils import AssetPermissionPermAssetUtil +from perms.utils.permission import AssetPermissionUtil +from tickets.const import TicketApplyAssetScope + +__all__ = ['ApplyAssetsViewSet', 'ApplyNodesViewSet'] + + +class ApplyAssetsViewSet(OrgReadonlyModelViewSet, SuggestionMixin): + model = Asset + serializer_class = MiniAssetSerializer + rbac_perms = ( + ("match", "assets.match_asset"), + ) + + search_fields = ("name", "address", "comment") + + def get_queryset(self): + if TicketApplyAssetScope.is_permed(): + queryset = self.get_assets(with_expired=True) + elif TicketApplyAssetScope.is_permed_valid(): + queryset = self.get_assets() + else: + queryset = super().get_queryset() + return queryset + + def get_assets(self, with_expired=False): + perms = AssetPermissionUtil().get_permissions_for_user( + self.request.user, flat=True, with_expired=with_expired + ) + util = AssetPermissionPermAssetUtil(perms) + assets = util.get_all_assets() + return assets + + +class ApplyNodesViewSet(OrgReadonlyModelViewSet, SuggestionMixin): + model = Node + serializer_class = NodeSerializer + rbac_perms = ( + ("match", "assets.match_node"), + ) + + search_fields = ('full_value',) + + def get_queryset(self): + if TicketApplyAssetScope.is_permed(): + queryset = self.get_nodes(with_expired=True) + elif TicketApplyAssetScope.is_permed_valid(): + queryset = self.get_nodes() + else: + queryset = super().get_queryset() + return queryset + + def get_nodes(self, with_expired=False): + perms = AssetPermissionUtil().get_permissions_for_user( + self.request.user, flat=True, with_expired=with_expired + ) + util = AssetPermissionPermAssetUtil(perms) + nodes = util.get_perm_nodes() + return nodes diff --git a/apps/tickets/const.py b/apps/tickets/const.py index a2a5ec981..09c1b39e4 100644 --- a/apps/tickets/const.py +++ b/apps/tickets/const.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.db.models import TextChoices, IntegerChoices from django.utils.translation import gettext_lazy as _ @@ -56,3 +57,21 @@ class TicketApprovalStrategy(TextChoices): custom_user = 'custom_user', _("Custom user") super_admin = 'super_admin', _("Super admin") super_org_admin = 'super_org_admin', _("Super admin and org admin") + + +class TicketApplyAssetScope(TextChoices): + all = 'all', _("All assets") + permed = 'permed', _("Permed assets") + permed_valid = 'permed_valid', _('Permed valid assets') + + @classmethod + def get_scope(cls): + return settings.TICKET_APPLY_ASSET_SCOPE.lower() + + @classmethod + def is_permed(cls): + return cls.get_scope() == cls.permed + + @classmethod + def is_permed_valid(cls): + return cls.get_scope() == cls.permed_valid diff --git a/apps/tickets/models/ticket/general.py b/apps/tickets/models/ticket/general.py index f7c78a4a1..656a8322a 100644 --- a/apps/tickets/models/ticket/general.py +++ b/apps/tickets/models/ticket/general.py @@ -57,7 +57,7 @@ class TicketStep(JMSBaseModel): assignees.update(state=state) self.status = StepStatus.closed self.state = state - self.save(update_fields=['state', 'status']) + self.save(update_fields=['state', 'status', 'date_updated']) def set_active(self): self.status = StepStatus.active diff --git a/apps/tickets/notifications.py b/apps/tickets/notifications.py index b3791b98b..e217acf80 100644 --- a/apps/tickets/notifications.py +++ b/apps/tickets/notifications.py @@ -96,16 +96,10 @@ class BaseTicketMessage(UserMessage): class TicketAppliedToAssigneeMessage(BaseTicketMessage): def __init__(self, user, ticket): - self._token = None + self.token = random_string(32) self.ticket = ticket super().__init__(user) - @property - def token(self): - if self._token is None: - self._token = random_string(32) - return self._token - @property def content_title(self): return _('Your has a new ticket, applicant - {}').format(self.ticket.applicant) @@ -133,10 +127,12 @@ class TicketAppliedToAssigneeMessage(BaseTicketMessage): ticket_approval_url = self.get_ticket_approval_url() context.update({'ticket_approval_url': ticket_approval_url}) message = render_to_string('tickets/_msg_ticket.html', context) - cache.set(self.token, {'ticket_id': self.ticket.id, 'content': self.content}, 3600) + cache.set(self.token, { + 'ticket_id': self.ticket.id, 'approver_id': self.user.id, + 'content': self.content, + }, 3600) return { - 'subject': self.subject, - 'message': message + 'subject': self.subject, 'message': message } @classmethod diff --git a/apps/tickets/urls/api_urls.py b/apps/tickets/urls/api_urls.py index 9cc72d815..88b203d84 100644 --- a/apps/tickets/urls/api_urls.py +++ b/apps/tickets/urls/api_urls.py @@ -16,6 +16,8 @@ router.register('apply-login-tickets', api.ApplyLoginTicketViewSet, 'apply-login router.register('apply-command-tickets', api.ApplyCommandTicketViewSet, 'apply-command-ticket') router.register('apply-login-asset-tickets', api.ApplyLoginAssetTicketViewSet, 'apply-login-asset-ticket') router.register('ticket-session-relation', api.TicketSessionRelationViewSet, 'ticket-session-relation') +router.register('apply-assets', api.ApplyAssetsViewSet, 'ticket-session-relation') +router.register('apply-nodes', api.ApplyNodesViewSet, 'ticket-session-relation') urlpatterns = [ path('tickets//session/', api.TicketSessionApi.as_view(), name='ticket-session'), diff --git a/apps/tickets/views/approve.py b/apps/tickets/views/approve.py index 2f3e715b4..553fcfe69 100644 --- a/apps/tickets/views/approve.py +++ b/apps/tickets/views/approve.py @@ -5,11 +5,14 @@ from __future__ import unicode_literals from django.core.cache import cache from django.http import HttpResponse +from django.conf import settings from django.shortcuts import redirect, reverse from django.utils.translation import gettext as _ from django.views.generic.base import TemplateView from common.utils import get_logger, FlashMessageUtil +from common.exceptions import JMSException +from users.models import User from orgs.utils import tmp_to_root_org from tickets.const import TicketType from tickets.errors import AlreadyClosed @@ -71,7 +74,7 @@ class TicketDirectApproveView(TemplateView): return super().get_context_data(**kwargs) def get(self, request, *args, **kwargs): - if not request.user.is_authenticated: + if not (settings.TICKETS_DIRECT_APPROVE or request.user.is_authenticated): direct_url = reverse('tickets:direct-approve', kwargs={'token': kwargs['token']}) message_data = { 'title': _('Ticket approval'), @@ -87,8 +90,15 @@ class TicketDirectApproveView(TemplateView): return self.redirect_message_response(redirect_url=self.login_url) return super().get(request, ticket_info=ticket_info, *args, **kwargs) - def post(self, request, **kwargs): + @staticmethod + def get_user(request, ticket_info): user = request.user + if not user.is_authenticated and settings.TICKETS_DIRECT_APPROVE: + user_id = ticket_info.get('approver_id') + user = User.objects.filter(id=user_id).first() + return user + + def post(self, request, **kwargs): token = kwargs.get('token') action = request.POST.get('action') if action not in ['approve', 'reject']: @@ -99,13 +109,14 @@ class TicketDirectApproveView(TemplateView): if not ticket_info: return self.redirect_message_response(redirect_url=self.login_url) try: + user = self.get_user(request, ticket_info) ticket_id = ticket_info.get('ticket_id') with tmp_to_root_org(): ticket = Ticket.all().get(id=ticket_id) ticket_sub_model = self.TICKET_SUB_MODEL_MAP[ticket.type] ticket = ticket_sub_model.objects.get(id=ticket_id) if not ticket.has_current_assignee(user): - raise Exception(_("This user is not authorized to approve this ticket")) + raise JMSException(_("This user is not authorized to approve this ticket")) getattr(ticket, action)(user) except AlreadyClosed as e: self.clear(token) diff --git a/apps/users/serializers/user.py b/apps/users/serializers/user.py index d4228b920..aaeda080c 100644 --- a/apps/users/serializers/user.py +++ b/apps/users/serializers/user.py @@ -97,6 +97,8 @@ class UserSerializer(RolesSerializerMixin, CommonBulkSerializerMixin, ResourceLa is_expired = serializers.BooleanField(read_only=True, label=_("Is expired")) is_valid = serializers.BooleanField(read_only=True, label=_("Is valid")) is_otp_secret_key_bound = serializers.BooleanField(read_only=True, label=_("Is OTP bound")) + is_superuser = serializers.BooleanField(read_only=True, label=_("Super Administrator")) + is_org_admin = serializers.BooleanField(read_only=True, label=_("Organization Administrator")) can_public_key_auth = serializers.BooleanField( source="can_use_ssh_key_login", label=_("Can public key authentication"), read_only=True diff --git a/apps/users/templates/users/forgot_password.html b/apps/users/templates/users/forgot_password.html index 64137ea8a..cdb32dca2 100644 --- a/apps/users/templates/users/forgot_password.html +++ b/apps/users/templates/users/forgot_password.html @@ -7,6 +7,7 @@ .margin-bottom { margin-bottom: 15px; } + .input-style { width: 100%; display: inline-block; @@ -22,6 +23,19 @@ height: 100%; vertical-align: top; } + + .scrollable-menu { + height: auto; + max-height: 18rem; + overflow-x: hidden; + } + + .input-group { + .input-group-btn .btn-secondary { + color: #464a4c; + background-color: #eceeef; + } + } {% endblock %} {% block html_title %}{% trans 'Forgot password' %}{% endblock %} @@ -57,9 +71,26 @@ placeholder="{% trans 'Email account' %}" value="{{ email }}">
- - {{ form.sms.help_text }} +
+
+ + +
+ +
diff --git a/apps/users/views/profile/otp.py b/apps/users/views/profile/otp.py index a42a7a513..aca1251fc 100644 --- a/apps/users/views/profile/otp.py +++ b/apps/users/views/profile/otp.py @@ -1,10 +1,14 @@ # ~*~ coding: utf-8 ~*~ +import os +from django.conf import settings from django.contrib.auth import logout as auth_logout from django.http.response import HttpResponseRedirect from django.shortcuts import redirect +from django.templatetags.static import static from django.urls import reverse from django.utils.translation import gettext as _ +from django.utils._os import safe_join from django.views.generic.base import TemplateView from django.views.generic.edit import FormView @@ -45,9 +49,26 @@ class UserOtpEnableStartView(AuthMixin, TemplateView): class UserOtpEnableInstallAppView(TemplateView): template_name = 'users/user_otp_enable_install_app.html' + @staticmethod + def replace_authenticator_png(platform): + media_url = settings.MEDIA_URL + base_path = f'img/authenticator_{platform}.png' + authenticator_media_path = safe_join(settings.MEDIA_ROOT, base_path) + if os.path.exists(authenticator_media_path): + authenticator_url = f'{media_url}{base_path}' + else: + authenticator_url = static(base_path) + return authenticator_url + def get_context_data(self, **kwargs): user = get_user_or_pre_auth_user(self.request) - context = {'user': user} + authenticator_android_url = self.replace_authenticator_png('android') + authenticator_iphone_url = self.replace_authenticator_png('iphone') + context = { + 'user': user, + 'authenticator_android_url': authenticator_android_url, + 'authenticator_iphone_url': authenticator_iphone_url + } kwargs.update(context) return super().get_context_data(**kwargs) diff --git a/apps/users/views/profile/reset.py b/apps/users/views/profile/reset.py index b2eed3cdd..554a2ca88 100644 --- a/apps/users/views/profile/reset.py +++ b/apps/users/views/profile/reset.py @@ -13,6 +13,7 @@ from django.views.generic import FormView, RedirectView from authentication.errors import IntervalTooShort from authentication.utils import check_user_property_is_correct +from common.const.choices import COUNTRY_CALLING_CODES from common.utils import FlashMessageUtil, get_object_or_none, random_string from common.utils.verify_code import SendAndVerifyCodeUtil from users.notifications import ResetPasswordSuccessMsg @@ -108,7 +109,7 @@ class UserForgotPasswordView(FormView): for k, v in cleaned_data.items(): if v: context[k] = v - + context['countries'] = COUNTRY_CALLING_CODES context['form_type'] = 'email' context['XPACK_ENABLED'] = settings.XPACK_ENABLED validate_backends = self.get_validate_backends_context(has_phone) diff --git a/config_example.yml b/config_example.yml index 03cc0aa03..232ac32d8 100644 --- a/config_example.yml +++ b/config_example.yml @@ -85,7 +85,7 @@ REDIS_PORT: 6379 # SECURITY_WATERMARK_ENABLED: False # 浏览器关闭页面后,会话过期 -# SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE: False +# SESSION_EXPIRE_AT_BROWSER_CLOSE: False # 每次api请求,session续期 # SESSION_SAVE_EVERY_REQUEST: True diff --git a/poetry.lock b/poetry.lock index 3271ee6c7..5262e4337 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "adal" @@ -519,13 +519,13 @@ reference = "tsinghua" [[package]] name = "anyio" -version = "4.2.0" +version = "4.3.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, - {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, + {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, + {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, ] [package.dependencies] @@ -544,13 +544,13 @@ reference = "tsinghua" [[package]] name = "appnope" -version = "0.1.3" +version = "0.1.4" description = "Disable App Nap on macOS >= 10.9" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, - {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, + {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, + {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, ] [package.source] @@ -730,17 +730,16 @@ reference = "tsinghua" [[package]] name = "azure-core" -version = "1.29.6" +version = "1.30.0" description = "Microsoft Azure Core Library for Python" optional = false python-versions = ">=3.7" files = [ - {file = "azure-core-1.29.6.tar.gz", hash = "sha256:13b485252ecd9384ae624894fe51cfa6220966207264c360beada239f88b738a"}, - {file = "azure_core-1.29.6-py3-none-any.whl", hash = "sha256:604a005bce6a49ba661bb7b2be84a9b169047e52fcfcd0a4e4770affab4178f7"}, + {file = "azure-core-1.30.0.tar.gz", hash = "sha256:6f3a7883ef184722f6bd997262eddaf80cfe7e5b3e0caaaf8db1695695893d35"}, + {file = "azure_core-1.30.0-py3-none-any.whl", hash = "sha256:3dae7962aad109610e68c9a7abb31d79720e1d982ddf61363038d175a5025e89"}, ] [package.dependencies] -anyio = ">=3.0,<5.0" requests = ">=2.21.0" six = ">=1.11.0" typing-extensions = ">=4.6.0" @@ -961,19 +960,22 @@ reference = "tsinghua" [[package]] name = "beautifulsoup4" -version = "4.12.2" +version = "4.12.3" description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" files = [ - {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, - {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, ] [package.dependencies] soupsieve = ">1.2" [package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] @@ -1080,13 +1082,13 @@ reference = "tsinghua" [[package]] name = "cachetools" -version = "5.3.2" +version = "5.3.3" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" files = [ - {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, - {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, + {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"}, + {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"}, ] [package.source] @@ -1614,12 +1616,13 @@ reference = "tsinghua" [[package]] name = "cron-descriptor" -version = "1.4.0" +version = "1.4.3" description = "A Python library that converts cron expressions into human readable strings." optional = false python-versions = "*" files = [ - {file = "cron_descriptor-1.4.0.tar.gz", hash = "sha256:b6ff4e3a988d7ca04a4ab150248e9f166fb7a5c828a85090e75bcc25aa93b4dd"}, + {file = "cron_descriptor-1.4.3-py3-none-any.whl", hash = "sha256:a67ba21804983b1427ed7f3e1ec27ee77bf24c652b0430239c268c5ddfbf9dc0"}, + {file = "cron_descriptor-1.4.3.tar.gz", hash = "sha256:7b1a00d7d25d6ae6896c0da4457e790b98cba778398a3d48e341e5e0d33f0488"}, ] [package.extras] @@ -1794,13 +1797,13 @@ reference = "tsinghua" [[package]] name = "debtcollector" -version = "2.5.0" +version = "3.0.0" description = "A collection of Python deprecation patterns and strategies that help you collect your technical debt in a non-destructive manner." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "debtcollector-2.5.0-py3-none-any.whl", hash = "sha256:1393a527d2c72f143ffa6a629e9c33face6642634eece475b48cab7b04ba61f3"}, - {file = "debtcollector-2.5.0.tar.gz", hash = "sha256:dc9d1ad3f745c43f4bbedbca30f9ffe8905a8c028c9926e61077847d5ea257ab"}, + {file = "debtcollector-3.0.0-py3-none-any.whl", hash = "sha256:46f9dacbe8ce49c47ebf2bf2ec878d50c9443dfae97cc7b8054be684e54c3e91"}, + {file = "debtcollector-3.0.0.tar.gz", hash = "sha256:2a8917d25b0e1f1d0d365d3c1c6ecfc7a522b1e9716e8a1a4a915126f7ccea6f"}, ] [package.dependencies] @@ -2260,22 +2263,23 @@ reference = "tsinghua" [[package]] name = "dnspython" -version = "2.4.2" +version = "2.6.1" description = "DNS toolkit" optional = false -python-versions = ">=3.8,<4.0" +python-versions = ">=3.8" files = [ - {file = "dnspython-2.4.2-py3-none-any.whl", hash = "sha256:57c6fbaaeaaf39c891292012060beb141791735dbb4004798328fc2c467402d8"}, - {file = "dnspython-2.4.2.tar.gz", hash = "sha256:8dcfae8c7460a2f84b4072e26f1c9f4101ca20c071649cb7c34e8b6a93d58984"}, + {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, + {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, ] [package.extras] -dnssec = ["cryptography (>=2.6,<42.0)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.24.1)"] -doq = ["aioquic (>=0.9.20)"] -idna = ["idna (>=2.1,<4.0)"] -trio = ["trio (>=0.14,<0.23)"] -wmi = ["wmi (>=1.5.1,<2.0.0)"] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] +dnssec = ["cryptography (>=41)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] +doq = ["aioquic (>=0.9.25)"] +idna = ["idna (>=3.6)"] +trio = ["trio (>=0.23)"] +wmi = ["wmi (>=1.5.1)"] [package.source] type = "legacy" @@ -2821,26 +2825,20 @@ reference = "tsinghua" [[package]] name = "google-api-core" -version = "2.15.0" +version = "2.17.1" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.15.0.tar.gz", hash = "sha256:abc978a72658f14a2df1e5e12532effe40f94f868f6e23d95133bd6abcca35ca"}, - {file = "google_api_core-2.15.0-py3-none-any.whl", hash = "sha256:2aa56d2be495551e66bbff7f729b790546f87d5c90e74781aa77233bcb395a8a"}, + {file = "google-api-core-2.17.1.tar.gz", hash = "sha256:9df18a1f87ee0df0bc4eea2770ebc4228392d8cc4066655b320e2cfccb15db95"}, + {file = "google_api_core-2.17.1-py3-none-any.whl", hash = "sha256:610c5b90092c360736baccf17bd3efbcb30dd380e7a6dc28a71059edb8bd0d8e"}, ] [package.dependencies] google-auth = ">=2.14.1,<3.0.dev0" googleapis-common-protos = ">=1.56.2,<2.0.dev0" -grpcio = [ - {version = ">=1.33.2,<2.0dev", optional = true, markers = "extra == \"grpc\""}, - {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, -] -grpcio-status = [ - {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "extra == \"grpc\""}, - {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, -] +grpcio = {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""} +grpcio-status = {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""} protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" requests = ">=2.18.0,<3.0.0.dev0" @@ -2856,13 +2854,13 @@ reference = "tsinghua" [[package]] name = "google-auth" -version = "2.25.2" +version = "2.28.1" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.25.2.tar.gz", hash = "sha256:42f707937feb4f5e5a39e6c4f343a17300a459aaf03141457ba505812841cc40"}, - {file = "google_auth-2.25.2-py2.py3-none-any.whl", hash = "sha256:473a8dfd0135f75bb79d878436e568f2695dce456764bf3a02b6f8c540b1d256"}, + {file = "google-auth-2.28.1.tar.gz", hash = "sha256:34fc3046c257cedcf1622fc4b31fc2be7923d9b4d44973d481125ecc50d83885"}, + {file = "google_auth-2.28.1-py2.py3-none-any.whl", hash = "sha256:25141e2d7a14bfcba945f5e9827f98092716e99482562f15306e5b026e21aa72"}, ] [package.dependencies] @@ -3002,69 +3000,69 @@ reference = "tsinghua" [[package]] name = "grpcio" -version = "1.60.0" +version = "1.62.0" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.7" files = [ - {file = "grpcio-1.60.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:d020cfa595d1f8f5c6b343530cd3ca16ae5aefdd1e832b777f9f0eb105f5b139"}, - {file = "grpcio-1.60.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:b98f43fcdb16172dec5f4b49f2fece4b16a99fd284d81c6bbac1b3b69fcbe0ff"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:20e7a4f7ded59097c84059d28230907cd97130fa74f4a8bfd1d8e5ba18c81491"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452ca5b4afed30e7274445dd9b441a35ece656ec1600b77fff8c216fdf07df43"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43e636dc2ce9ece583b3e2ca41df5c983f4302eabc6d5f9cd04f0562ee8ec1ae"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e306b97966369b889985a562ede9d99180def39ad42c8014628dd3cc343f508"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f897c3b127532e6befdcf961c415c97f320d45614daf84deba0a54e64ea2457b"}, - {file = "grpcio-1.60.0-cp310-cp310-win32.whl", hash = "sha256:b87efe4a380887425bb15f220079aa8336276398dc33fce38c64d278164f963d"}, - {file = "grpcio-1.60.0-cp310-cp310-win_amd64.whl", hash = "sha256:a9c7b71211f066908e518a2ef7a5e211670761651039f0d6a80d8d40054047df"}, - {file = "grpcio-1.60.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:fb464479934778d7cc5baf463d959d361954d6533ad34c3a4f1d267e86ee25fd"}, - {file = "grpcio-1.60.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4b44d7e39964e808b071714666a812049765b26b3ea48c4434a3b317bac82f14"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:90bdd76b3f04bdb21de5398b8a7c629676c81dfac290f5f19883857e9371d28c"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91229d7203f1ef0ab420c9b53fe2ca5c1fbeb34f69b3bc1b5089466237a4a134"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b36a2c6d4920ba88fa98075fdd58ff94ebeb8acc1215ae07d01a418af4c0253"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:297eef542156d6b15174a1231c2493ea9ea54af8d016b8ca7d5d9cc65cfcc444"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:87c9224acba0ad8bacddf427a1c2772e17ce50b3042a789547af27099c5f751d"}, - {file = "grpcio-1.60.0-cp311-cp311-win32.whl", hash = "sha256:95ae3e8e2c1b9bf671817f86f155c5da7d49a2289c5cf27a319458c3e025c320"}, - {file = "grpcio-1.60.0-cp311-cp311-win_amd64.whl", hash = "sha256:467a7d31554892eed2aa6c2d47ded1079fc40ea0b9601d9f79204afa8902274b"}, - {file = "grpcio-1.60.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:a7152fa6e597c20cb97923407cf0934e14224af42c2b8d915f48bc3ad2d9ac18"}, - {file = "grpcio-1.60.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:7db16dd4ea1b05ada504f08d0dca1cd9b926bed3770f50e715d087c6f00ad748"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:b0571a5aef36ba9177e262dc88a9240c866d903a62799e44fd4aae3f9a2ec17e"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fd9584bf1bccdfff1512719316efa77be235469e1e3295dce64538c4773840b"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6a478581b1a1a8fdf3318ecb5f4d0cda41cacdffe2b527c23707c9c1b8fdb55"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:77c8a317f0fd5a0a2be8ed5cbe5341537d5c00bb79b3bb27ba7c5378ba77dbca"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1c30bb23a41df95109db130a6cc1b974844300ae2e5d68dd4947aacba5985aa5"}, - {file = "grpcio-1.60.0-cp312-cp312-win32.whl", hash = "sha256:2aef56e85901c2397bd557c5ba514f84de1f0ae5dd132f5d5fed042858115951"}, - {file = "grpcio-1.60.0-cp312-cp312-win_amd64.whl", hash = "sha256:e381fe0c2aa6c03b056ad8f52f8efca7be29fb4d9ae2f8873520843b6039612a"}, - {file = "grpcio-1.60.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:92f88ca1b956eb8427a11bb8b4a0c0b2b03377235fc5102cb05e533b8693a415"}, - {file = "grpcio-1.60.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:e278eafb406f7e1b1b637c2cf51d3ad45883bb5bd1ca56bc05e4fc135dfdaa65"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:a48edde788b99214613e440fce495bbe2b1e142a7f214cce9e0832146c41e324"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de2ad69c9a094bf37c1102b5744c9aec6cf74d2b635558b779085d0263166454"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:073f959c6f570797272f4ee9464a9997eaf1e98c27cb680225b82b53390d61e6"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c826f93050c73e7769806f92e601e0efdb83ec8d7c76ddf45d514fee54e8e619"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9e30be89a75ee66aec7f9e60086fadb37ff8c0ba49a022887c28c134341f7179"}, - {file = "grpcio-1.60.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b0fb2d4801546598ac5cd18e3ec79c1a9af8b8f2a86283c55a5337c5aeca4b1b"}, - {file = "grpcio-1.60.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:9073513ec380434eb8d21970e1ab3161041de121f4018bbed3146839451a6d8e"}, - {file = "grpcio-1.60.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:74d7d9fa97809c5b892449b28a65ec2bfa458a4735ddad46074f9f7d9550ad13"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:1434ca77d6fed4ea312901122dc8da6c4389738bf5788f43efb19a838ac03ead"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e61e76020e0c332a98290323ecfec721c9544f5b739fab925b6e8cbe1944cf19"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675997222f2e2f22928fbba640824aebd43791116034f62006e19730715166c0"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5208a57eae445ae84a219dfd8b56e04313445d146873117b5fa75f3245bc1390"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:428d699c8553c27e98f4d29fdc0f0edc50e9a8a7590bfd294d2edb0da7be3629"}, - {file = "grpcio-1.60.0-cp38-cp38-win32.whl", hash = "sha256:83f2292ae292ed5a47cdcb9821039ca8e88902923198f2193f13959360c01860"}, - {file = "grpcio-1.60.0-cp38-cp38-win_amd64.whl", hash = "sha256:705a68a973c4c76db5d369ed573fec3367d7d196673fa86614b33d8c8e9ebb08"}, - {file = "grpcio-1.60.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:c193109ca4070cdcaa6eff00fdb5a56233dc7610216d58fb81638f89f02e4968"}, - {file = "grpcio-1.60.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:676e4a44e740deaba0f4d95ba1d8c5c89a2fcc43d02c39f69450b1fa19d39590"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5ff21e000ff2f658430bde5288cb1ac440ff15c0d7d18b5fb222f941b46cb0d2"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c86343cf9ff7b2514dd229bdd88ebba760bd8973dac192ae687ff75e39ebfab"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fd3b3968ffe7643144580f260f04d39d869fcc2cddb745deef078b09fd2b328"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:30943b9530fe3620e3b195c03130396cd0ee3a0d10a66c1bee715d1819001eaf"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b10241250cb77657ab315270b064a6c7f1add58af94befa20687e7c8d8603ae6"}, - {file = "grpcio-1.60.0-cp39-cp39-win32.whl", hash = "sha256:79a050889eb8d57a93ed21d9585bb63fca881666fc709f5d9f7f9372f5e7fd03"}, - {file = "grpcio-1.60.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a97a681e82bc11a42d4372fe57898d270a2707f36c45c6676e49ce0d5c41353"}, - {file = "grpcio-1.60.0.tar.gz", hash = "sha256:2199165a1affb666aa24adf0c97436686d0a61bc5fc113c037701fb7c7fceb96"}, + {file = "grpcio-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271"}, + {file = "grpcio-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0"}, + {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6"}, + {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8"}, + {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c"}, + {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0"}, + {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6"}, + {file = "grpcio-1.62.0-cp310-cp310-win32.whl", hash = "sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc"}, + {file = "grpcio-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa"}, + {file = "grpcio-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f"}, + {file = "grpcio-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb"}, + {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928"}, + {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2"}, + {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021"}, + {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4"}, + {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e"}, + {file = "grpcio-1.62.0-cp311-cp311-win32.whl", hash = "sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd"}, + {file = "grpcio-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334"}, + {file = "grpcio-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8"}, + {file = "grpcio-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6"}, + {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532"}, + {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee"}, + {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c"}, + {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873"}, + {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388"}, + {file = "grpcio-1.62.0-cp312-cp312-win32.whl", hash = "sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701"}, + {file = "grpcio-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842"}, + {file = "grpcio-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9"}, + {file = "grpcio-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2"}, + {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1"}, + {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839"}, + {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4"}, + {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b"}, + {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b"}, + {file = "grpcio-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b"}, + {file = "grpcio-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35"}, + {file = "grpcio-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6"}, + {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c"}, + {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402"}, + {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72"}, + {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f"}, + {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38"}, + {file = "grpcio-1.62.0-cp38-cp38-win32.whl", hash = "sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe"}, + {file = "grpcio-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270"}, + {file = "grpcio-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170"}, + {file = "grpcio-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e"}, + {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829"}, + {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b"}, + {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7"}, + {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c"}, + {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a"}, + {file = "grpcio-1.62.0-cp39-cp39-win32.whl", hash = "sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93"}, + {file = "grpcio-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5"}, + {file = "grpcio-1.62.0.tar.gz", hash = "sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.60.0)"] +protobuf = ["grpcio-tools (>=1.62.0)"] [package.source] type = "legacy" @@ -3073,18 +3071,18 @@ reference = "tsinghua" [[package]] name = "grpcio-status" -version = "1.60.0" +version = "1.62.0" description = "Status proto mapping for gRPC" optional = false python-versions = ">=3.6" files = [ - {file = "grpcio-status-1.60.0.tar.gz", hash = "sha256:f10e0b6db3adc0fdc244b71962814ee982996ef06186446b5695b9fa635aa1ab"}, - {file = "grpcio_status-1.60.0-py3-none-any.whl", hash = "sha256:7d383fa36e59c1e61d380d91350badd4d12ac56e4de2c2b831b050362c3c572e"}, + {file = "grpcio-status-1.62.0.tar.gz", hash = "sha256:0d693e9c09880daeaac060d0c3dba1ae470a43c99e5d20dfeafd62cf7e08a85d"}, + {file = "grpcio_status-1.62.0-py3-none-any.whl", hash = "sha256:3baac03fcd737310e67758c4082a188107f771d32855bce203331cd4c9aa687a"}, ] [package.dependencies] googleapis-common-protos = ">=1.5.5" -grpcio = ">=1.60.0" +grpcio = ">=1.62.0" protobuf = ">=4.21.6" [package.source] @@ -3151,13 +3149,13 @@ reference = "tsinghua" [[package]] name = "httpcore" -version = "1.0.2" +version = "1.0.4" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, - {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, + {file = "httpcore-1.0.4-py3-none-any.whl", hash = "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73"}, + {file = "httpcore-1.0.4.tar.gz", hash = "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022"}, ] [package.dependencies] @@ -3168,7 +3166,7 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.23.0)"] +trio = ["trio (>=0.22.0,<0.25.0)"] [package.source] type = "legacy" @@ -3197,13 +3195,13 @@ reference = "tsinghua" [[package]] name = "httpx" -version = "0.26.0" +version = "0.27.0" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd"}, - {file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf"}, + {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, + {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, ] [package.dependencies] @@ -3582,12 +3580,12 @@ reference = "tsinghua" [[package]] name = "jms-storage" -version = "0.0.53" +version = "0.0.56" description = "Jumpserver storage python sdk tools" optional = false python-versions = "*" files = [ - {file = "jms-storage-0.0.53.tar.gz", hash = "sha256:d197816b3edc6a370892d5a246265ea7ae7267159b1a4ad88a14ae56e92013be"}, + {file = "jms-storage-0.0.56.tar.gz", hash = "sha256:8ee4b121f695b8897da66cb7b3fca842d525479e7fd272db2bbbc133ea796543"}, ] [package.dependencies] @@ -3785,106 +3783,110 @@ reference = "tsinghua" [[package]] name = "lxml" -version = "5.0.0" +version = "4.9.3" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" files = [ - {file = "lxml-5.0.0-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73bfab795d354aaf2f4eb7a5b0db513031734fd371047342d5803834ce19ec18"}, - {file = "lxml-5.0.0-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cb564bbe55ff0897d9cf1225041a44576d7ae87f06fd60163544c91de2623d3f"}, - {file = "lxml-5.0.0-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6a5501438dd521bb7e0dde5008c40c7bfcfaafaf86eccb3f9bd27509abb793da"}, - {file = "lxml-5.0.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7ba26a7dc929a1b3487d51bbcb0099afed2fc06e891b82845c8f37a2d7d7fbbd"}, - {file = "lxml-5.0.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:9b59c429e1a2246da86ae237ffc3565efcdc71c281cd38ca8b44d5fb6a3b993a"}, - {file = "lxml-5.0.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:3ffa066db40b0347e48334bd4465de768e295a3525b9a59831228b5f4f93162d"}, - {file = "lxml-5.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8ce8b468ab50f9e944719d1134709ec11fe0d2840891a6cae369e22141b1094c"}, - {file = "lxml-5.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:583c0e15ae06adc81035346ae2abb2e748f0b5197e7740d8af31222db41bbf7b"}, - {file = "lxml-5.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:904d36165848b59c4e04ae5b969072e602bd987485076fca8ec42c6cd7a7aedc"}, - {file = "lxml-5.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ac21aace6712472e77ea9dfc38329f53830c4259ece54c786107105ebb069053"}, - {file = "lxml-5.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f92d73faa0b1a76d1932429d684b7ce95829e93c3eef3715ec9b98ab192c9d31"}, - {file = "lxml-5.0.0-cp310-cp310-win32.whl", hash = "sha256:03290e2f714f2e7431c8430c08b48167f657da7bc689c6248e828ff3c66d5b1b"}, - {file = "lxml-5.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:3e6cbb68bf70081f036bfc018649cf4b46c4e7eaf7860a277cae92dee2a57f69"}, - {file = "lxml-5.0.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:5382612ba2424cea5d2c89e2c29077023d8de88f8d60d5ceff5f76334516df9e"}, - {file = "lxml-5.0.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:07a900735bad9af7be3085480bf384f68ed5580ba465b39a098e6a882c060d6b"}, - {file = "lxml-5.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:980ba47c8db4b9d870014c7040edb230825b79017a6a27aa54cdb6fcc02d8cc0"}, - {file = "lxml-5.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6507c58431dbd95b50654b3313c5ad54f90e54e5f2cdacf733de61eae478eec5"}, - {file = "lxml-5.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4a45a278518e4308865c1e9dbb2c42ce84fb154efb03adeb16fdae3c1687c7c9"}, - {file = "lxml-5.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:59cea9ba1c675fbd6867ca1078fc717a113e7f5b7644943b74137b7cc55abebf"}, - {file = "lxml-5.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dd39ef87fd1f7bb5c4aa53454936e6135cbfe03fe3744e8218be193f9e4fef16"}, - {file = "lxml-5.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e6bb39d91bf932e7520cb5718ae3c2f498052aca53294d5d59fdd9068fe1a7f2"}, - {file = "lxml-5.0.0-cp311-cp311-win32.whl", hash = "sha256:21af2c3862db6f4f486cddf73ec1157b40d5828876c47cd880edcbad8240ea1b"}, - {file = "lxml-5.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:c1249aa4eaced30b59ecf8b8cae0b1ccede04583c74ca7d10b6f8bbead908b2c"}, - {file = "lxml-5.0.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:f30e697b6215e759d0824768b2c5b0618d2dc19abe6c67eeed2b0460f52470d1"}, - {file = "lxml-5.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d1bb64646480c36a4aa1b6a44a5b6e33d0fcbeab9f53f1b39072cd3bb2c6243a"}, - {file = "lxml-5.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4e69c36c8618707a90ed3fb6f48a6cc9254ffcdbf7b259e439a5ae5fbf9c5206"}, - {file = "lxml-5.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9ca498f8554a09fbc3a2f8fc4b23261e07bc27bef99b3df98e2570688033f6fc"}, - {file = "lxml-5.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0326e9b8176ea77269fb39e7af4010906e73e9496a9f8eaf06d253b1b1231ceb"}, - {file = "lxml-5.0.0-cp312-cp312-win32.whl", hash = "sha256:5fb988e15378d6e905ca8f60813950a0c56da9469d0e8e5d8fe785b282684ec5"}, - {file = "lxml-5.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:bb58e8f4b2cfe012cd312239b8d5139995fe8f5945c7c26d5fbbbb1ddb9acd47"}, - {file = "lxml-5.0.0-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:81509dffd8aba3bdb43e90cbd218c9c068a1f4047d97bc9546b3ac9e3a4ae81d"}, - {file = "lxml-5.0.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e675a4b95208e74c34ac0751cc4bab9170e7728b61601fb0f4746892c2bb7e0b"}, - {file = "lxml-5.0.0-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:405e3760f83a8ba3bdb6e622ec79595cdc20db916ce37377bbcb95b5711fa4ca"}, - {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f15844a1b93dcaa09c2b22e22a73384f3ae4502347c3881cfdd674e14ac04e21"}, - {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88f559f8beb6b90e41a7faae4aca4c8173a4819874a9bf8e74c8d7c1d51f3162"}, - {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e8c63f5c7d87e7044880b01851ac4e863c3349e6f6b6ab456fe218d9346e816d"}, - {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:0d277d4717756fe8816f0beeff229cb72f9dd02a43b70e1d3f07c8efadfb9fe1"}, - {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c8954da15403db1acfc0544b3c3f963a6ef4e428283ab6555e3e298bbbff1cf6"}, - {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:aebd8fd378e074b22e79cad329dcccd243c40ff1cafaa512d19276c5bb9554e1"}, - {file = "lxml-5.0.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:b6d4e148edee59c2ad38af15810dbcb8b5d7b13e5de3509d8cf3edfe74c0adca"}, - {file = "lxml-5.0.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:70ab4e02f7aa5fb4131c8b222a111ce7676f3767e36084fba3a4e7338dc82dcd"}, - {file = "lxml-5.0.0-cp36-cp36m-win32.whl", hash = "sha256:de1a8b54170024cf1c0c2718c82412bca42cd82e390556e3d8031af9541b416f"}, - {file = "lxml-5.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5b39f63edbe7e018c2ac1cf0259ee0dd2355274e8a3003d404699b040782e55e"}, - {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:77b73952534967a4497d9e4f26fbeebfba19950cbc66b7cc3a706214429d8106"}, - {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8cc0a951e5616ac626f7036309c41fb9774adcd4aa7db0886463da1ce5b65edb"}, - {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:4b9d5b01900a760eb3acf6cef50aead4ef2fa79e7ddb927084244e41dfe37b65"}, - {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:173bcead3af5d87c7bca9a030675073ddaad8e0a9f0b04be07cd9390453e7226"}, - {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:44fa9afd632210f1eeda51cf284ed8dbab0c7ec8b008dd39ba02818e0e114e69"}, - {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fef10f27d6318d2d7c88680e113511ddecf09ee4f9559b3623b73ee89fa8f6cc"}, - {file = "lxml-5.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3663542aee845129a981889c19b366beab0b1dadcf5ca164696aabfe1aa51667"}, - {file = "lxml-5.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7188495c1bf71bfda87d78ed50601e72d252119ce11710d6e71ff36e35fea5a0"}, - {file = "lxml-5.0.0-cp37-cp37m-win32.whl", hash = "sha256:6a2de85deabf939b0af89e2e1ea46bfb1239545e2da6f8ac96522755a388025f"}, - {file = "lxml-5.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ea56825c1e23c9c8ea385a191dac75f9160477057285b88c88736d9305e6118f"}, - {file = "lxml-5.0.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:3f908afd0477cace17f941d1b9cfa10b769fe1464770abe4cfb3d9f35378d0f8"}, - {file = "lxml-5.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52a9ab31853d3808e7cf0183b3a5f7e8ffd622ea4aee1deb5252dbeaefd5b40d"}, - {file = "lxml-5.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c7fe19abb3d3c55a9e65d289b12ad73b3a31a3f0bda3c539a890329ae9973bd6"}, - {file = "lxml-5.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:1ef0793e1e2dd221fce7c142177008725680f7b9e4a184ab108d90d5d3ab69b7"}, - {file = "lxml-5.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:581a78f299a9f5448b2c3aea904bfcd17c59bf83016d221d7f93f83633bb2ab2"}, - {file = "lxml-5.0.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:affdd833f82334fdb10fc9a1c7b35cdb5a86d0b672b4e14dd542e1fe7bcea894"}, - {file = "lxml-5.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6bba06d8982be0f0f6432d289a8d104417a0ab9ed04114446c4ceb6d4a40c65d"}, - {file = "lxml-5.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:80209b31dd3908bc5b014f540fd192c97ea52ab179713a730456c5baf7ce80c1"}, - {file = "lxml-5.0.0-cp38-cp38-win32.whl", hash = "sha256:dac2733fe4e159b0aae0439db6813b7b1d23ff96d0b34c0107b87faf79208c4e"}, - {file = "lxml-5.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:ee60f33456ff34b2dd1d048a740a2572798356208e4c494301c931de3a0ab3a2"}, - {file = "lxml-5.0.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:5eff173f0ff408bfa578cbdafd35a7e0ca94d1a9ffe09a8a48e0572d0904d486"}, - {file = "lxml-5.0.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:78d6d8e5b54ed89dc0f0901eaaa579c384ad8d59fa43cc7fb06e9bb89115f8f4"}, - {file = "lxml-5.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:71a7cee869578bc17b18050532bb2f0bc682a7b97dda77041741a1bd2febe6c7"}, - {file = "lxml-5.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7df433d08d4587dc3932f7fcfc3194519a6824824104854e76441fd3bc000d29"}, - {file = "lxml-5.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:793be9b4945c2dfd69828fb5948d7d9569b78e0599e4a2e88d92affeb0ff3aa3"}, - {file = "lxml-5.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c7cfb6af73602c8d288581df8a225989d7e9d5aab0a174be0e19fcfa800b6797"}, - {file = "lxml-5.0.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bfdc4668ac56687a89ca3eca44231144a2e9d02ba3b877558db74ba20e2bd9fa"}, - {file = "lxml-5.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2992591e2294bb07faf7f5f6d5cb60710c046404f4bfce09fb488b85d2a8f58f"}, - {file = "lxml-5.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4786b0af7511ea614fd86407a52a7bc161aa5772d311d97df2591ed2351de768"}, - {file = "lxml-5.0.0-cp39-cp39-win32.whl", hash = "sha256:016de3b29a262655fc3d2075dc1b2611f84f4c3d97a71d579c883d45e201eee4"}, - {file = "lxml-5.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:52c0acc2f29b0a204efc11a5ed911a74f50a25eb7d7d5069c2b1fd3b3346ce11"}, - {file = "lxml-5.0.0-pp310-pypy310_pp73-macosx_11_0_x86_64.whl", hash = "sha256:96095bfc0c02072fc89afa67626013a253596ea5118b8a7f4daaae049dafa096"}, - {file = "lxml-5.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:992029258ed719f130d5a9c443d142c32843046f1263f2c492862b2a853be570"}, - {file = "lxml-5.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:db40e85cffd22f7d65dcce30e85af565a66401a6ed22fc0c56ed342cfa4ffc43"}, - {file = "lxml-5.0.0-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:cfa8a4cdc3765574b7fd0c7cfa5fbd1e2108014c9dfd299c679e5152bea9a55e"}, - {file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:049fef98d02513c34f5babd07569fc1cf1ed14c0f2fbff18fe72597f977ef3c2"}, - {file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a85136d0ee18a41c91cc3e2844c683be0e72e6dda4cb58da9e15fcaef3726af7"}, - {file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:766868f729f3ab84125350f1a0ea2594d8b1628a608a574542a5aff7355b9941"}, - {file = "lxml-5.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:99cad5c912f359e59e921689c04e54662cdd80835d80eeaa931e22612f515df7"}, - {file = "lxml-5.0.0-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:c90c593aa8dd57d5dab0ef6d7d64af894008971d98e6a41b320fdd75258fbc6e"}, - {file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8134d5441d1ed6a682e3de3d7a98717a328dce619ee9c4c8b3b91f0cb0eb3e28"}, - {file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f298ac9149037d6a3d5c74991bded39ac46292520b9c7c182cb102486cc87677"}, - {file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:894c5f71186b410679aaab5774543fcb9cbabe8893f0b31d11cf28a0740e80be"}, - {file = "lxml-5.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9cd3d6c2c67d4fdcd795e4945e2ba5434909c96640b4cc09453bd0dc7e8e1bac"}, - {file = "lxml-5.0.0.zip", hash = "sha256:2219cbf790e701acf9a21a31ead75f983e73daf0eceb9da6990212e4d20ebefe"}, + {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, + {file = "lxml-4.9.3-cp27-cp27m-win32.whl", hash = "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7"}, + {file = "lxml-4.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"}, + {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f"}, + {file = "lxml-4.9.3-cp310-cp310-win32.whl", hash = "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85"}, + {file = "lxml-4.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d"}, + {file = "lxml-4.9.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6"}, + {file = "lxml-4.9.3-cp311-cp311-win32.whl", hash = "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305"}, + {file = "lxml-4.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc"}, + {file = "lxml-4.9.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5"}, + {file = "lxml-4.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2"}, + {file = "lxml-4.9.3-cp35-cp35m-win32.whl", hash = "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d"}, + {file = "lxml-4.9.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833"}, + {file = "lxml-4.9.3-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458"}, + {file = "lxml-4.9.3-cp36-cp36m-win32.whl", hash = "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477"}, + {file = "lxml-4.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02"}, + {file = "lxml-4.9.3-cp37-cp37m-win32.whl", hash = "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f"}, + {file = "lxml-4.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7"}, + {file = "lxml-4.9.3-cp38-cp38-win32.whl", hash = "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574"}, + {file = "lxml-4.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96"}, + {file = "lxml-4.9.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50"}, + {file = "lxml-4.9.3-cp39-cp39-win32.whl", hash = "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2"}, + {file = "lxml-4.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2"}, + {file = "lxml-4.9.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"}, + {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.7)"] +source = ["Cython (>=0.29.35)"] [package.source] type = "legacy" @@ -3976,59 +3978,59 @@ reference = "tsinghua" [[package]] name = "maxminddb" -version = "2.5.1" +version = "2.5.2" description = "Reader for the MaxMind DB format" optional = false python-versions = ">=3.8" files = [ - {file = "maxminddb-2.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:62e93a8e99937bf4307eeece3ca37e1161325ebf9363c4ce195410fb5daf64a0"}, - {file = "maxminddb-2.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea2e27a507b53dfbf2ba2ba85c98682a1ad2dac3f9941a7bffa5cb86150d0c47"}, - {file = "maxminddb-2.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a01b0341bd6bee431bb8c07c7ac0ed221250c7390b125c025b7d57578e78e8a3"}, - {file = "maxminddb-2.5.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:607344b1079ea647629bf962dcea7580ec864faaad3f5aae650e2e8652121d89"}, - {file = "maxminddb-2.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2c2901daebd7c8a702302315e7a58cdc38e626406ad4a05b4d48634897d5f5a3"}, - {file = "maxminddb-2.5.1-cp310-cp310-win32.whl", hash = "sha256:7805ae8c9de433c38939ada2e376706a9f6740239f61fd445927b88f5b42c267"}, - {file = "maxminddb-2.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:f1e5bd58b71f322dc6c16a95a129433b1bc229d4b714f870a61c2367425396ee"}, - {file = "maxminddb-2.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b0bbbd58b300aaddf985f763720bdebba9f7a73168ff9f57168117f630ad1c06"}, - {file = "maxminddb-2.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a6751e2e89d62d53217870bcc2a8c887dc56ae370ba1b74e52e880761916e54"}, - {file = "maxminddb-2.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ecb1be961f1969be047d07743093f0dcf2f6d4ec3a06a4555587f380a96f6e7"}, - {file = "maxminddb-2.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1e091c2b44673c218ee2df23adbc0b6d04fd5c646cfcb6c6fe26fb849434812a"}, - {file = "maxminddb-2.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09b295c401c104ae0e30f66c1a3f3c2aa4ba2cbe12a787576499356a5a4d6c1"}, - {file = "maxminddb-2.5.1-cp311-cp311-win32.whl", hash = "sha256:3d52c693baf07bba897d109b0ecb067f21fd0cc0fb266d67db456e85b80d699e"}, - {file = "maxminddb-2.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:4c67621e842c415ce336ab019a9f087305dfcf24c095b68b8e9d27848f6f6d91"}, - {file = "maxminddb-2.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17ea454f61631b9815d420d48d00663f8718fc7de30be53ffcec0f73989475eb"}, - {file = "maxminddb-2.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef4d508c899ce0f37de731340759c68bfd1102a39a873675c71fae2c8d71ad97"}, - {file = "maxminddb-2.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e5ca423b1e310f0327536f5ed1a2c6e08d83289a7f909e021590b0b477cae2"}, - {file = "maxminddb-2.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:0a21abd85e10e5e0f60244b49c3db17e7e48befd4972e62a62833d91e2acbb49"}, - {file = "maxminddb-2.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:85a302d79577efe5bc308647394ffdc535dd5f062644c41103604ccf24931a05"}, - {file = "maxminddb-2.5.1-cp312-cp312-win32.whl", hash = "sha256:dd28c434fb44f825dde6a75df2c338d44645791b03480af66a4d993f93801e10"}, - {file = "maxminddb-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:b477852cf1741d9187b021e23723e64b063794bbf946a9b5b84cc222f3caf58a"}, - {file = "maxminddb-2.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a1e1a19f9740f586362f47862d0095b54d50b9d465babcaa8a563746132fe5be"}, - {file = "maxminddb-2.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d654895b546a47e85f2e071b98e377a60bb03cd643b9423017fa66fcd5adedce"}, - {file = "maxminddb-2.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0702da59b9670a72761b65cb1a52bc3032d8f6799bdab641cb8350ad5740580b"}, - {file = "maxminddb-2.5.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2e20a70c1545d6626dcd4ce2d7ecf3d566d978ea64cb37e7952f93baff66b812"}, - {file = "maxminddb-2.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0cbd272db3202e948c9088e48dec62add071a47971d84ceb11d2cb2880f83e5a"}, - {file = "maxminddb-2.5.1-cp38-cp38-win32.whl", hash = "sha256:fbd01fc7d7b5b2befe914e8cdb5ed3a1c5476e57b765197cceff8d897f33d012"}, - {file = "maxminddb-2.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:fe0af3ba9e1a78ed5f2ad32fc18d18b78ef233e7d0c627e1a77a525a7eb0c241"}, - {file = "maxminddb-2.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d772be68cce812f7c4b15ae8c68e624c8b88ff83071e3903ca5b5f55e343c25"}, - {file = "maxminddb-2.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e7b3ad87d5352ed3f496bd42bffbf9f896245278b0d8e76afa1382e42a7ae"}, - {file = "maxminddb-2.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:892c11a8694394e97d3ac0f8d5974ea588c732d14e721f22095c58b4f584c144"}, - {file = "maxminddb-2.5.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3ce1f42bdfce7b86cb5a56cba730fed611fb879d867e6024f0d520257bef6891"}, - {file = "maxminddb-2.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6667948e7501a513caef90edda2d367865097239d4c2381eb3998e9905af7209"}, - {file = "maxminddb-2.5.1-cp39-cp39-win32.whl", hash = "sha256:500d321bdefe4dcd351e4390a79b7786aab49b0536bedfa0788e5ffb0e91e421"}, - {file = "maxminddb-2.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:93f7055779caf7753810f1e2c6444af6d727393fd116ffa0767fbd54fb8c9bbf"}, - {file = "maxminddb-2.5.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8cee4315da7cdd3f2a18f1ab1418953a7a9eda65e63095b01f03c7d3645d633e"}, - {file = "maxminddb-2.5.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c97eac5af102cede4b5f57cecb25e8f949fa4e4a8d812bed575539951c60ecaf"}, - {file = "maxminddb-2.5.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:526744b12075051fa20979090c111cc3a42a3b55e2714818270c7b84a41a8cfe"}, - {file = "maxminddb-2.5.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fad45cd2f2e3c5fbebacb8d172a60fb22443222e549bf740a0bc7eeb849e5ce7"}, - {file = "maxminddb-2.5.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8b98ed5c34955c48e72d35daed713ba4a6833a8a6d1204e79d2c85e644049792"}, - {file = "maxminddb-2.5.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:639aee8abd63a95baa12b94b6f3a842d51877d631879c7d08c98c68dc44a84c3"}, - {file = "maxminddb-2.5.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a7a73ab4bbc16b81983531c99fa102a0c7dae459db958c17fea48c981f5e764"}, - {file = "maxminddb-2.5.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:aae262da1940a67c3ba765c49e2308947ce68ff647f87630002c306433a98ca1"}, - {file = "maxminddb-2.5.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b223c53077a736c304b63cf5afceb928975fbd12ddae5afd6b71370bab7b4700"}, - {file = "maxminddb-2.5.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:969d0057ea5472e0b574c5293c4f3ecf49585362351c543e8ea55dc48b60f1eb"}, - {file = "maxminddb-2.5.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4d36cf3d390f02d2bdf53d9efefb92be7bd70e07a5a86cdb79020c48c2d81b7"}, - {file = "maxminddb-2.5.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:188173c07dce0692fd5660a6eb7ea8c126d7b3a4b61496c8a8ee9e8b10186ff5"}, - {file = "maxminddb-2.5.1.tar.gz", hash = "sha256:4807d374e645bd68334e4f487ba85a27189dbc1267a98e644aa686a7927e0559"}, + {file = "maxminddb-2.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f5682963a5817066db50f219c33aaa7eb969888211a289a444c42b5dfa0c0f78"}, + {file = "maxminddb-2.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fe6bb1b5ea132fcd9fd7b16c80247f0ba667018d5f9f98cd645b297e3b02fbf"}, + {file = "maxminddb-2.5.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:955a3ec4b161e872cc615b7a09ae9770049e9794e7b3832e3d78905a65c5049d"}, + {file = "maxminddb-2.5.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:29d63e7711e5f95c7c190010e57dca9e262aee8ac300aaf75c3f7ede0b5a5863"}, + {file = "maxminddb-2.5.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:08a540ec3661f6ca40499c86028e96dca5780e9d471b485dc797859b0b22dd22"}, + {file = "maxminddb-2.5.2-cp310-cp310-win32.whl", hash = "sha256:17fdb691c389a0e956410d5baef9ad082a0aa67dd6aa231d193499e71a104c19"}, + {file = "maxminddb-2.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:d71b48d3dff9150a44e949b28fa5e7251a7a6895a3a77e200ce08410f096f12f"}, + {file = "maxminddb-2.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1409a045eb04cebb297221eab1020c4f05434d02c0961410f6996ef474482998"}, + {file = "maxminddb-2.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d839c480e4b93bb37bb1cc2777d77e6b2127c006e60b56f748f10571d8b0e471"}, + {file = "maxminddb-2.5.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bca70905515fe50684974a9afaa7db4a4e9fbfdebcb0c2cde9db8e048e0d8145"}, + {file = "maxminddb-2.5.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:67f97cd0c6aac39a51294b04a1e922532125285c24b18a58e2a9c92c7691fa9f"}, + {file = "maxminddb-2.5.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1a3fab6bea6cc59444e6bad2a4fbf91228f6f51dcb29d09ed091930a475bd8cb"}, + {file = "maxminddb-2.5.2-cp311-cp311-win32.whl", hash = "sha256:a99e3125528ea31e807f80e8c5b65118dc5cc122d0a435f1691a3cc1df55840c"}, + {file = "maxminddb-2.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:b6adf63695fa5e3d2549f7c2c9d82c6d252edd5c6ba67074637d2cb944143673"}, + {file = "maxminddb-2.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ed504ca9f3c42e8e71bdbe21f5b818139a1448ac15d7bb6ce12cf41e3b7e2067"}, + {file = "maxminddb-2.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a5053231228d7cbf57d98a741b3cbee9efa9e689348dbb56c414e5a4c7f6f1c"}, + {file = "maxminddb-2.5.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7e8688342bab592647313cd2054779bcd35ad85933424ceae9f07e3a9779986"}, + {file = "maxminddb-2.5.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:335ee3140b41d4e751c14f8fae297aa064c7d3f184c9fbb2790336123187c440"}, + {file = "maxminddb-2.5.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b0203fa2731da45e5461f6e8a0768e85bba8e02137a1598b3fcadf7cbfe8e6f2"}, + {file = "maxminddb-2.5.2-cp312-cp312-win32.whl", hash = "sha256:8b89129de70e1629f200df9dfda4e4f477c26b05c29e0836604a00209c9466d5"}, + {file = "maxminddb-2.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:099f4e27feec4bb9658034a3eb853e746721fc15709030bee4f2f889f4a34185"}, + {file = "maxminddb-2.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:19d8d1e9bbc5281fb4c8112d541d2bd350fd8b5ddfbb43a6951e46df7cd27b9d"}, + {file = "maxminddb-2.5.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94183a78628cad257183a88ce12a3bb9ffbfe0544bd0c1aafc1f9dc55629dd1b"}, + {file = "maxminddb-2.5.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17de49660372dcccaa23958eccdd1c2464f92f594d027045ad76788db14a5da4"}, + {file = "maxminddb-2.5.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae05c4f87b1dd9a21d430c52451eef5f3bd5af609d093408db91fe0dc4d8d7d1"}, + {file = "maxminddb-2.5.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cb718908b9dffa10e02361094158ae68ded5a82c750de89737437999a81bafe"}, + {file = "maxminddb-2.5.2-cp38-cp38-win32.whl", hash = "sha256:e0faa0c4c458eb0eb2f267daa7b106baef72c3c7ebcbece00b9e974fc8321412"}, + {file = "maxminddb-2.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:bac5a29fdc5df9222f7baecbcc4a88b309a66a7d147b34160940c0850ee4b9c5"}, + {file = "maxminddb-2.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c204f53ef7c1d77e9fb0dba415dbb56419f2b08ccaca66cd772e29b3a793c3e7"}, + {file = "maxminddb-2.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae98508a200db6f7ae5985a53039aba8eef7ed71d34b0a0e9c9145c3e6139fc3"}, + {file = "maxminddb-2.5.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e9198d25e252b27d4e9526d5fcd4b78341c23153363a94f1246de5afcd39f6d"}, + {file = "maxminddb-2.5.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b85b008f8e2cf3abfabdc24041549c51c97ea9a8bc46eeeadac8cec7acf9fbf0"}, + {file = "maxminddb-2.5.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6f50210506e9818162ef6706d3127efb0575dfe2cc98a7236ca2011f1cc3effe"}, + {file = "maxminddb-2.5.2-cp39-cp39-win32.whl", hash = "sha256:2bba43d370a57785f5ef61c10d0b4bf8de58d431da3c4c2ed78bb2ff3d07edbf"}, + {file = "maxminddb-2.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:2e01b09480b97d2ebe6765618fb12a0f52caa17368d6cf1f42481d6740428de7"}, + {file = "maxminddb-2.5.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dd47d13376eaee2e8d1a1fb55d3d6ccdcc995bc931699967f7d5670ec6a454a3"}, + {file = "maxminddb-2.5.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abd626efaba4f0bc867462337f846796da0bb97b82125dbdbc63067947e353b0"}, + {file = "maxminddb-2.5.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ddbe547d83a2e28e81d9f59fd9708d3044ffb2398ee0f8df2e2a2e9cdea6646"}, + {file = "maxminddb-2.5.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:22184fa2514c15f5b39e4e2522f4f73d00afcf5eb7102c473f9376f3c3a03b81"}, + {file = "maxminddb-2.5.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5cb6702fbcc5b209ac3cffacd9cf0a5155feabbeb6fdcf497038be7cb6e52da6"}, + {file = "maxminddb-2.5.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0c3ebfc0af00445089629faffa4c5a1fcc42a1ca5d7dffc42bba314fde20c6d"}, + {file = "maxminddb-2.5.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:461dcf0a4f67aa1c9faea6d52c4060d39559bf68e99a514cf8c1e01af383f90b"}, + {file = "maxminddb-2.5.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e012e889639aab411f5483990188da51c968377f665dcb90584971dbf314d50a"}, + {file = "maxminddb-2.5.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:20596e452d03071db37a72c8ef9236126c04ed342864f68db0adf0d1bc9f642e"}, + {file = "maxminddb-2.5.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ec51b66774b102824c9a3dd4916356283f6a61db1868d4ebcb98bf26486718e"}, + {file = "maxminddb-2.5.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fda0dd512f345cc92492f96c61a0df47efc2e2064c15e8053ab2114b362d64d"}, + {file = "maxminddb-2.5.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:862fcfe226ebda29a537cdce678dc8dc71ca6540ad2483099f80c6a1ee4cdbdd"}, + {file = "maxminddb-2.5.2.tar.gz", hash = "sha256:b3c33e4fc7821ee6c9f40837116e16ab6175863d4a64eee024c5bec686690a87"}, ] [package.dependencies] @@ -4057,22 +4059,22 @@ reference = "tsinghua" [[package]] name = "msal" -version = "1.26.0" +version = "1.27.0" description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." optional = false python-versions = ">=2.7" files = [ - {file = "msal-1.26.0-py2.py3-none-any.whl", hash = "sha256:be77ba6a8f49c9ff598bbcdc5dfcf1c9842f3044300109af738e8c3e371065b5"}, - {file = "msal-1.26.0.tar.gz", hash = "sha256:224756079fe338be838737682b49f8ebc20a87c1c5eeaf590daae4532b83de15"}, + {file = "msal-1.27.0-py2.py3-none-any.whl", hash = "sha256:572d07149b83e7343a85a3bcef8e581167b4ac76befcbbb6eef0c0e19643cdc0"}, + {file = "msal-1.27.0.tar.gz", hash = "sha256:3109503c038ba6b307152b0e8d34f98113f2e7a78986e28d0baf5b5303afda52"}, ] [package.dependencies] -cryptography = ">=0.6,<44" +cryptography = ">=0.6,<45" PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} requests = ">=2.0.0,<3" [package.extras] -broker = ["pymsalruntime (>=0.13.2,<0.14)"] +broker = ["pymsalruntime (>=0.13.2,<0.15)"] [package.source] type = "legacy" @@ -4222,85 +4224,101 @@ reference = "tsinghua" [[package]] name = "multidict" -version = "6.0.4" +version = "6.0.5" description = "multidict implementation" optional = false python-versions = ">=3.7" files = [ - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, - {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, - {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, - {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, - {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, - {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, - {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, - {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, - {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, - {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, - {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, - {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, - {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, + {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, + {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, + {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, + {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, + {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, + {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, + {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, + {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, + {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, + {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, + {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, + {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, + {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, + {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, + {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, ] [package.source] @@ -4331,15 +4349,18 @@ reference = "tsinghua" [[package]] name = "netaddr" -version = "0.10.0" +version = "1.2.1" description = "A network address manipulation library for Python" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "netaddr-0.10.0-py2.py3-none-any.whl", hash = "sha256:8752f96c8fc24162edbf5b73d3e464b5d88e62869917582daa37b2695b65afb4"}, - {file = "netaddr-0.10.0.tar.gz", hash = "sha256:4c30c54adf4ea4318b3c055ea3d8c7f6554a50aa2cd8aea4605a23caa0b0229e"}, + {file = "netaddr-1.2.1-py3-none-any.whl", hash = "sha256:bd9e9534b0d46af328cf64f0e5a23a5a43fca292df221c85580b27394793496e"}, + {file = "netaddr-1.2.1.tar.gz", hash = "sha256:6eb8fedf0412c6d294d06885c110de945cf4d22d2b510d0404f4e06950857987"}, ] +[package.extras] +nicer-shell = ["ipython"] + [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" @@ -4427,13 +4448,13 @@ reference = "tsinghua" [[package]] name = "openai" -version = "1.6.1" +version = "1.12.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.6.1-py3-none-any.whl", hash = "sha256:bc9f774838d67ac29fb24cdeb2d58faf57de8b311085dcd1348f7aa02a96c7ee"}, - {file = "openai-1.6.1.tar.gz", hash = "sha256:d553ca9dbf9486b08e75b09e8671e4f638462aaadccfced632bf490fc3d75fa2"}, + {file = "openai-1.12.0-py3-none-any.whl", hash = "sha256:a54002c814e05222e413664f651b5916714e4700d041d5cf5724d3ae1a3e3481"}, + {file = "openai-1.12.0.tar.gz", hash = "sha256:99c5d257d09ea6533d689d1cc77caa0ac679fa21efef8893d8b0832a86877f1b"}, ] [package.dependencies] @@ -4556,13 +4577,13 @@ reference = "tsinghua" [[package]] name = "oslo-config" -version = "9.2.0" +version = "9.4.0" description = "Oslo Configuration API" optional = false python-versions = ">=3.8" files = [ - {file = "oslo.config-9.2.0-py3-none-any.whl", hash = "sha256:b98e50b19161fc76f25905ff74043e239258a3ebe799a5f9070d285e3c039dee"}, - {file = "oslo.config-9.2.0.tar.gz", hash = "sha256:ffeb01ca65a603d5525905f1a88a3319be09ce2c6ac376c4312aaec283095878"}, + {file = "oslo.config-9.4.0-py3-none-any.whl", hash = "sha256:8c2049c14cade7adeeda18638531b3b3a40d3c6bcc690535939f64a3c1ec8d63"}, + {file = "oslo.config-9.4.0.tar.gz", hash = "sha256:35b11a661b608edb50305dad91e4e30819d90ef794b7d7dba5bd8b2ef2eb8c0d"}, ] [package.dependencies] @@ -4576,7 +4597,7 @@ stevedore = ">=1.20.0" [package.extras] rst-generator = ["rst2txt (>=1.1.0)", "sphinx (>=1.8.0,!=2.1.0)"] -test = ["bandit (>=1.7.0,<1.8.0)", "coverage (>=4.0,!=4.4)", "fixtures (>=3.0.0)", "hacking (>=3.0.1,<3.1.0)", "mypy (>=0.720)", "oslo.log (>=3.36.0)", "oslotest (>=3.2.0)", "pre-commit (>=2.6.0)", "requests-mock (>=1.5.0)", "stestr (>=2.1.0)", "testscenarios (>=0.4)", "testtools (>=2.2.0)"] +test = ["bandit (>=1.7.0,<1.8.0)", "coverage (>=4.0,!=4.4)", "fixtures (>=3.0.0)", "hacking (>=6.1.0,<6.2.0)", "mypy (>=0.720)", "oslo.log (>=3.36.0)", "oslotest (>=3.2.0)", "pre-commit (>=2.6.0)", "requests-mock (>=1.5.0)", "stestr (>=2.1.0)", "testscenarios (>=0.4)", "testtools (>=2.2.0)"] [package.source] type = "legacy" @@ -4585,13 +4606,13 @@ reference = "tsinghua" [[package]] name = "oslo-i18n" -version = "6.2.0" +version = "6.3.0" description = "Oslo i18n library" optional = false python-versions = ">=3.8" files = [ - {file = "oslo.i18n-6.2.0-py3-none-any.whl", hash = "sha256:5cd6d0659bec2013107d235a8cf5e61475cc9dd33ef9ffc7aa2776bc1c6b56c9"}, - {file = "oslo.i18n-6.2.0.tar.gz", hash = "sha256:70f8a4ce9871291bc609d07e31e6e5032666556992ff1ae53e78f2ed2a5abe82"}, + {file = "oslo.i18n-6.3.0-py3-none-any.whl", hash = "sha256:698eb5c63a01359ed6d91031d6331098190d38be0bdda7d270264d6f86bc79e7"}, + {file = "oslo.i18n-6.3.0.tar.gz", hash = "sha256:64a251edef8bf1bb1d4e6f78d377e149d4f15c1a9245de77f172016da6267444"}, ] [package.dependencies] @@ -4604,21 +4625,20 @@ reference = "tsinghua" [[package]] name = "oslo-serialization" -version = "5.2.0" +version = "5.4.0" description = "Oslo Serialization library" optional = false python-versions = ">=3.8" files = [ - {file = "oslo.serialization-5.2.0-py3-none-any.whl", hash = "sha256:c7ec759192a787c7e1a5e765920bb594752c75e6e0cd5a9a82c385a9088125e5"}, - {file = "oslo.serialization-5.2.0.tar.gz", hash = "sha256:9cf030d61a6cce1f47a62d4050f5e83e1bd1a1018ac671bb193aee07d15bdbc2"}, + {file = "oslo.serialization-5.4.0-py3-none-any.whl", hash = "sha256:f999b75f2c2904c2f6aae5efbb67ab668cc0e79470510b721937626b36427220"}, + {file = "oslo.serialization-5.4.0.tar.gz", hash = "sha256:315cb3465e99c685cb091b90365cb701bee7140e204ba3e5fc2d8a20b4ec6e76"}, ] [package.dependencies] msgpack = ">=0.5.2" "oslo.utils" = ">=3.33.0" pbr = ">=2.0.0,<2.1.0 || >2.1.0" -pytz = ">=2013.6" -tzdata = ">=2022.4" +tzdata = {version = ">=2022.4", markers = "python_version >= \"3.9\""} [package.source] type = "legacy" @@ -4627,13 +4647,13 @@ reference = "tsinghua" [[package]] name = "oslo-utils" -version = "6.3.0" +version = "7.1.0" description = "Oslo Utility library" optional = false python-versions = ">=3.8" files = [ - {file = "oslo.utils-6.3.0-py3-none-any.whl", hash = "sha256:6bac2e56650f502caae6c0e8ba6e5eda3d7a16743d115f8836cad54538dd667f"}, - {file = "oslo.utils-6.3.0.tar.gz", hash = "sha256:758d945b2bad5bea81abed80ad33ffea1d1d793348ac5eb5b3866ba745b11d55"}, + {file = "oslo.utils-7.1.0-py3-none-any.whl", hash = "sha256:1d6504526c33cc10ae2c72565d0446a82d2acd43eaa5e6f3fd901d78400a2da0"}, + {file = "oslo.utils-7.1.0.tar.gz", hash = "sha256:5e42f3394d1f1f976e8994ac4a0918966d2f7eaf7c77380dd612c4a4148dd98e"}, ] [package.dependencies] @@ -4644,9 +4664,8 @@ netifaces = ">=0.10.4" "oslo.i18n" = ">=3.15.3" packaging = ">=20.4" pyparsing = ">=2.1.0" -pytz = ">=2013.6" PyYAML = ">=3.13" -tzdata = ">=2022.4" +tzdata = {version = ">=2022.4", markers = "python_version >= \"3.9\""} [package.source] type = "legacy" @@ -4925,20 +4944,20 @@ reference = "tsinghua" [[package]] name = "prettytable" -version = "3.9.0" +version = "3.10.0" description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" optional = false python-versions = ">=3.8" files = [ - {file = "prettytable-3.9.0-py3-none-any.whl", hash = "sha256:a71292ab7769a5de274b146b276ce938786f56c31cf7cea88b6f3775d82fe8c8"}, - {file = "prettytable-3.9.0.tar.gz", hash = "sha256:f4ed94803c23073a90620b201965e5dc0bccf1760b7a7eaf3158cab8aaffdf34"}, + {file = "prettytable-3.10.0-py3-none-any.whl", hash = "sha256:6536efaf0757fdaa7d22e78b3aac3b69ea1b7200538c2c6995d649365bddab92"}, + {file = "prettytable-3.10.0.tar.gz", hash = "sha256:9665594d137fb08a1117518c25551e0ede1687197cf353a4fdc78d27e1073568"}, ] [package.dependencies] wcwidth = "*" [package.extras] -tests = ["pytest", "pytest-cov", "pytest-lazy-fixture"] +tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"] [package.source] type = "legacy" @@ -4947,13 +4966,13 @@ reference = "tsinghua" [[package]] name = "prometheus-client" -version = "0.19.0" +version = "0.20.0" description = "Python client for the Prometheus monitoring system." optional = false python-versions = ">=3.8" files = [ - {file = "prometheus_client-0.19.0-py3-none-any.whl", hash = "sha256:c88b1e6ecf6b41cd8fb5731c7ae919bf66df6ec6fafa555cd6c0e16ca169ae92"}, - {file = "prometheus_client-0.19.0.tar.gz", hash = "sha256:4585b0d1223148c27a225b10dbec5ae9bc4c81a99a3fa80774fa6209935324e1"}, + {file = "prometheus_client-0.20.0-py3-none-any.whl", hash = "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7"}, + {file = "prometheus_client-0.20.0.tar.gz", hash = "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89"}, ] [package.extras] @@ -5007,22 +5026,22 @@ reference = "tsinghua" [[package]] name = "protobuf" -version = "4.25.1" +version = "4.25.3" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.1-cp310-abi3-win32.whl", hash = "sha256:193f50a6ab78a970c9b4f148e7c750cfde64f59815e86f686c22e26b4fe01ce7"}, - {file = "protobuf-4.25.1-cp310-abi3-win_amd64.whl", hash = "sha256:3497c1af9f2526962f09329fd61a36566305e6c72da2590ae0d7d1322818843b"}, - {file = "protobuf-4.25.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:0bf384e75b92c42830c0a679b0cd4d6e2b36ae0cf3dbb1e1dfdda48a244f4bcd"}, - {file = "protobuf-4.25.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:0f881b589ff449bf0b931a711926e9ddaad3b35089cc039ce1af50b21a4ae8cb"}, - {file = "protobuf-4.25.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:ca37bf6a6d0046272c152eea90d2e4ef34593aaa32e8873fc14c16440f22d4b7"}, - {file = "protobuf-4.25.1-cp38-cp38-win32.whl", hash = "sha256:abc0525ae2689a8000837729eef7883b9391cd6aa7950249dcf5a4ede230d5dd"}, - {file = "protobuf-4.25.1-cp38-cp38-win_amd64.whl", hash = "sha256:1484f9e692091450e7edf418c939e15bfc8fc68856e36ce399aed6889dae8bb0"}, - {file = "protobuf-4.25.1-cp39-cp39-win32.whl", hash = "sha256:8bdbeaddaac52d15c6dce38c71b03038ef7772b977847eb6d374fc86636fa510"}, - {file = "protobuf-4.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:becc576b7e6b553d22cbdf418686ee4daa443d7217999125c045ad56322dda10"}, - {file = "protobuf-4.25.1-py3-none-any.whl", hash = "sha256:a19731d5e83ae4737bb2a089605e636077ac001d18781b3cf489b9546c7c80d6"}, - {file = "protobuf-4.25.1.tar.gz", hash = "sha256:57d65074b4f5baa4ab5da1605c02be90ac20c8b40fb137d6a8df9f416b0d0ce2"}, + {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, + {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, + {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, + {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, + {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, + {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, + {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, + {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, + {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, ] [package.source] @@ -5344,18 +5363,18 @@ reference = "tsinghua" [[package]] name = "pydantic" -version = "2.5.3" +version = "2.6.3" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4"}, - {file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a"}, + {file = "pydantic-2.6.3-py3-none-any.whl", hash = "sha256:72c6034df47f46ccdf81869fddb81aade68056003900a8724a4f160700016a2a"}, + {file = "pydantic-2.6.3.tar.gz", hash = "sha256:e07805c4c7f5c6826e33a1d4c9d47950d7eaf34868e2690f8594d2e30241f11f"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.14.6" +pydantic-core = "2.16.3" typing-extensions = ">=4.6.1" [package.extras] @@ -5368,116 +5387,90 @@ reference = "tsinghua" [[package]] name = "pydantic-core" -version = "2.14.6" +version = "2.16.3" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9"}, - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590"}, - {file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7"}, - {file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2"}, - {file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2"}, - {file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23"}, - {file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c"}, - {file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786"}, - {file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40"}, - {file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e"}, - {file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6"}, - {file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60"}, - {file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe"}, - {file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411"}, - {file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975"}, - {file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e"}, - {file = "pydantic_core-2.14.6.tar.gz", hash = "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, + {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, + {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, + {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, + {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, + {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, + {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, + {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, + {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, + {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, + {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, + {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, + {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, + {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, ] [package.dependencies] @@ -6622,13 +6615,13 @@ reference = "tsinghua" [[package]] name = "service-identity" -version = "23.1.0" +version = "24.1.0" description = "Service identity verification for pyOpenSSL & cryptography." optional = false python-versions = ">=3.8" files = [ - {file = "service_identity-23.1.0-py3-none-any.whl", hash = "sha256:87415a691d52fcad954a500cb81f424d0273f8e7e3ee7d766128f4575080f383"}, - {file = "service_identity-23.1.0.tar.gz", hash = "sha256:ecb33cd96307755041e978ab14f8b14e13b40f1fbd525a4dc78f46d2b986431d"}, + {file = "service_identity-24.1.0-py3-none-any.whl", hash = "sha256:a28caf8130c8a5c1c7a6f5293faaf239bbfb7751e4862436920ee6f2616f568a"}, + {file = "service_identity-24.1.0.tar.gz", hash = "sha256:6829c9d62fb832c2e1c435629b0a8c476e1929881f28bee4d20bc24161009221"}, ] [package.dependencies] @@ -6638,7 +6631,7 @@ pyasn1 = "*" pyasn1-modules = "*" [package.extras] -dev = ["pyopenssl", "service-identity[docs,idna,mypy,tests]"] +dev = ["pyopenssl", "service-identity[idna,mypy,tests]"] docs = ["furo", "myst-parser", "pyopenssl", "sphinx", "sphinx-notfound-page"] idna = ["idna"] mypy = ["idna", "mypy", "types-pyopenssl"] @@ -6651,19 +6644,19 @@ reference = "tsinghua" [[package]] name = "setuptools" -version = "69.0.3" +version = "69.1.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"}, + {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [package.source] type = "legacy" @@ -6787,13 +6780,13 @@ reference = "tsinghua" [[package]] name = "sniffio" -version = "1.3.0" +version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] [package.source] @@ -6955,13 +6948,13 @@ reference = "tsinghua" [[package]] name = "stevedore" -version = "5.1.0" +version = "5.2.0" description = "Manage dynamic plugins for Python applications" optional = false python-versions = ">=3.8" files = [ - {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, - {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, + {file = "stevedore-5.2.0-py3-none-any.whl", hash = "sha256:1c15d95766ca0569cad14cb6272d4d31dae66b011a929d7c18219c176ea1b5c9"}, + {file = "stevedore-5.2.0.tar.gz", hash = "sha256:46b93ca40e1114cea93d738a6c1e365396981bb6bb78c27045b7587c9473544d"}, ] [package.dependencies] @@ -7053,13 +7046,13 @@ reference = "tsinghua" [[package]] name = "tqdm" -version = "4.66.1" +version = "4.66.2" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, - {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, + {file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9"}, + {file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531"}, ] [package.dependencies] @@ -7078,13 +7071,13 @@ reference = "tsinghua" [[package]] name = "traitlets" -version = "5.14.0" +version = "5.14.1" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.14.0-py3-none-any.whl", hash = "sha256:f14949d23829023013c47df20b4a76ccd1a85effb786dc060f34de7948361b33"}, - {file = "traitlets-5.14.0.tar.gz", hash = "sha256:fcdaa8ac49c04dfa0ed3ee3384ef6dfdb5d6f3741502be247279407679296772"}, + {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, + {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, ] [package.extras] @@ -7215,13 +7208,13 @@ reference = "tsinghua" [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.10.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, + {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, ] [package.source] @@ -7231,13 +7224,13 @@ reference = "tsinghua" [[package]] name = "tzdata" -version = "2023.4" +version = "2024.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, - {file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [package.source] @@ -7420,13 +7413,13 @@ reference = "tsinghua" [[package]] name = "wcwidth" -version = "0.2.12" +version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, - {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] [package.source] @@ -7647,13 +7640,13 @@ reference = "tsinghua" [[package]] name = "xlsxwriter" -version = "3.1.9" +version = "3.2.0" description = "A Python module for creating Excel XLSX files." optional = false python-versions = ">=3.6" files = [ - {file = "XlsxWriter-3.1.9-py3-none-any.whl", hash = "sha256:b61c1a0c786f82644936c0936ec96ee96cd3afb9440094232f7faef9b38689f0"}, - {file = "XlsxWriter-3.1.9.tar.gz", hash = "sha256:de810bf328c6a4550f4ffd6b0b34972aeb7ffcf40f3d285a0413734f9b63a929"}, + {file = "XlsxWriter-3.2.0-py3-none-any.whl", hash = "sha256:ecfd5405b3e0e228219bcaf24c2ca0915e012ca9464a14048021d21a995d490e"}, + {file = "XlsxWriter-3.2.0.tar.gz", hash = "sha256:9977d0c661a72866a61f9f7a809e25ebbb0fb7036baa3b9fe74afcfca6b3cb8c"}, ] [package.source] @@ -7817,47 +7810,47 @@ reference = "tsinghua" [[package]] name = "zope-interface" -version = "6.1" +version = "6.2" description = "Interfaces for Python" optional = false python-versions = ">=3.7" files = [ - {file = "zope.interface-6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:43b576c34ef0c1f5a4981163b551a8781896f2a37f71b8655fd20b5af0386abb"}, - {file = "zope.interface-6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:67be3ca75012c6e9b109860820a8b6c9a84bfb036fbd1076246b98e56951ca92"}, - {file = "zope.interface-6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b9bc671626281f6045ad61d93a60f52fd5e8209b1610972cf0ef1bbe6d808e3"}, - {file = "zope.interface-6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbe81def9cf3e46f16ce01d9bfd8bea595e06505e51b7baf45115c77352675fd"}, - {file = "zope.interface-6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dc998f6de015723196a904045e5a2217f3590b62ea31990672e31fbc5370b41"}, - {file = "zope.interface-6.1-cp310-cp310-win_amd64.whl", hash = "sha256:239a4a08525c080ff833560171d23b249f7f4d17fcbf9316ef4159f44997616f"}, - {file = "zope.interface-6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9ffdaa5290422ac0f1688cb8adb1b94ca56cee3ad11f29f2ae301df8aecba7d1"}, - {file = "zope.interface-6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34c15ca9248f2e095ef2e93af2d633358c5f048c49fbfddf5fdfc47d5e263736"}, - {file = "zope.interface-6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b012d023b4fb59183909b45d7f97fb493ef7a46d2838a5e716e3155081894605"}, - {file = "zope.interface-6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97806e9ca3651588c1baaebb8d0c5ee3db95430b612db354c199b57378312ee8"}, - {file = "zope.interface-6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fddbab55a2473f1d3b8833ec6b7ac31e8211b0aa608df5ab09ce07f3727326de"}, - {file = "zope.interface-6.1-cp311-cp311-win_amd64.whl", hash = "sha256:a0da79117952a9a41253696ed3e8b560a425197d4e41634a23b1507efe3273f1"}, - {file = "zope.interface-6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8bb9c990ca9027b4214fa543fd4025818dc95f8b7abce79d61dc8a2112b561a"}, - {file = "zope.interface-6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b51b64432eed4c0744241e9ce5c70dcfecac866dff720e746d0a9c82f371dfa7"}, - {file = "zope.interface-6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa6fd016e9644406d0a61313e50348c706e911dca29736a3266fc9e28ec4ca6d"}, - {file = "zope.interface-6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c8cf55261e15590065039696607f6c9c1aeda700ceee40c70478552d323b3ff"}, - {file = "zope.interface-6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e30506bcb03de8983f78884807e4fd95d8db6e65b69257eea05d13d519b83ac0"}, - {file = "zope.interface-6.1-cp312-cp312-win_amd64.whl", hash = "sha256:e33e86fd65f369f10608b08729c8f1c92ec7e0e485964670b4d2633a4812d36b"}, - {file = "zope.interface-6.1-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:2f8d89721834524a813f37fa174bac074ec3d179858e4ad1b7efd4401f8ac45d"}, - {file = "zope.interface-6.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13b7d0f2a67eb83c385880489dbb80145e9d344427b4262c49fbf2581677c11c"}, - {file = "zope.interface-6.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef43ee91c193f827e49599e824385ec7c7f3cd152d74cb1dfe02cb135f264d83"}, - {file = "zope.interface-6.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e441e8b7d587af0414d25e8d05e27040d78581388eed4c54c30c0c91aad3a379"}, - {file = "zope.interface-6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f89b28772fc2562ed9ad871c865f5320ef761a7fcc188a935e21fe8b31a38ca9"}, - {file = "zope.interface-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:70d2cef1bf529bff41559be2de9d44d47b002f65e17f43c73ddefc92f32bf00f"}, - {file = "zope.interface-6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ad54ed57bdfa3254d23ae04a4b1ce405954969c1b0550cc2d1d2990e8b439de1"}, - {file = "zope.interface-6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef467d86d3cfde8b39ea1b35090208b0447caaabd38405420830f7fd85fbdd56"}, - {file = "zope.interface-6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6af47f10cfc54c2ba2d825220f180cc1e2d4914d783d6fc0cd93d43d7bc1c78b"}, - {file = "zope.interface-6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9559138690e1bd4ea6cd0954d22d1e9251e8025ce9ede5d0af0ceae4a401e43"}, - {file = "zope.interface-6.1-cp38-cp38-win_amd64.whl", hash = "sha256:964a7af27379ff4357dad1256d9f215047e70e93009e532d36dcb8909036033d"}, - {file = "zope.interface-6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:387545206c56b0315fbadb0431d5129c797f92dc59e276b3ce82db07ac1c6179"}, - {file = "zope.interface-6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:57d0a8ce40ce440f96a2c77824ee94bf0d0925e6089df7366c2272ccefcb7941"}, - {file = "zope.interface-6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ebc4d34e7620c4f0da7bf162c81978fce0ea820e4fa1e8fc40ee763839805f3"}, - {file = "zope.interface-6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a804abc126b33824a44a7aa94f06cd211a18bbf31898ba04bd0924fbe9d282d"}, - {file = "zope.interface-6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f294a15f7723fc0d3b40701ca9b446133ec713eafc1cc6afa7b3d98666ee1ac"}, - {file = "zope.interface-6.1-cp39-cp39-win_amd64.whl", hash = "sha256:a41f87bb93b8048fe866fa9e3d0c51e27fe55149035dcf5f43da4b56732c0a40"}, - {file = "zope.interface-6.1.tar.gz", hash = "sha256:2fdc7ccbd6eb6b7df5353012fbed6c3c5d04ceaca0038f75e601060e95345309"}, + {file = "zope.interface-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:506f5410b36e5ba494136d9fa04c548eaf1a0d9c442b0b0e7a0944db7620e0ab"}, + {file = "zope.interface-6.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b386b8b9d2b6a5e1e4eadd4e62335571244cb9193b7328c2b6e38b64cfda4f0e"}, + {file = "zope.interface-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb0b3f2cb606981c7432f690db23506b1db5899620ad274e29dbbbdd740e797"}, + {file = "zope.interface-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7916380abaef4bb4891740879b1afcba2045aee51799dfd6d6ca9bdc71f35f"}, + {file = "zope.interface-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b240883fb43160574f8f738e6d09ddbdbf8fa3e8cea051603d9edfd947d9328"}, + {file = "zope.interface-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:8af82afc5998e1f307d5e72712526dba07403c73a9e287d906a8aa2b1f2e33dd"}, + {file = "zope.interface-6.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d45d2ba8195850e3e829f1f0016066a122bfa362cc9dc212527fc3d51369037"}, + {file = "zope.interface-6.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:76e0531d86523be7a46e15d379b0e975a9db84316617c0efe4af8338dc45b80c"}, + {file = "zope.interface-6.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59f7374769b326a217d0b2366f1c176a45a4ff21e8f7cebb3b4a3537077eff85"}, + {file = "zope.interface-6.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25e0af9663eeac6b61b231b43c52293c2cb7f0c232d914bdcbfd3e3bd5c182ad"}, + {file = "zope.interface-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e02a6fc1772b458ebb6be1c276528b362041217b9ca37e52ecea2cbdce9fac"}, + {file = "zope.interface-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:02adbab560683c4eca3789cc0ac487dcc5f5a81cc48695ec247f00803cafe2fe"}, + {file = "zope.interface-6.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8f5d2c39f3283e461de3655e03faf10e4742bb87387113f787a7724f32db1e48"}, + {file = "zope.interface-6.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:75d2ec3d9b401df759b87bc9e19d1b24db73083147089b43ae748aefa63067ef"}, + {file = "zope.interface-6.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa994e8937e8ccc7e87395b7b35092818905cf27c651e3ff3e7f29729f5ce3ce"}, + {file = "zope.interface-6.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ede888382882f07b9e4cd942255921ffd9f2901684198b88e247c7eabd27a000"}, + {file = "zope.interface-6.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2606955a06c6852a6cff4abeca38346ed01e83f11e960caa9a821b3626a4467b"}, + {file = "zope.interface-6.2-cp312-cp312-win_amd64.whl", hash = "sha256:ac7c2046d907e3b4e2605a130d162b1b783c170292a11216479bb1deb7cadebe"}, + {file = "zope.interface-6.2-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:febceb04ee7dd2aef08c2ff3d6f8a07de3052fc90137c507b0ede3ea80c21440"}, + {file = "zope.interface-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fc711acc4a1c702ca931fdbf7bf7c86f2a27d564c85c4964772dadf0e3c52f5"}, + {file = "zope.interface-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:396f5c94654301819a7f3a702c5830f0ea7468d7b154d124ceac823e2419d000"}, + {file = "zope.interface-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd374927c00764fcd6fe1046bea243ebdf403fba97a937493ae4be2c8912c2b"}, + {file = "zope.interface-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a3046e8ab29b590d723821d0785598e0b2e32b636a0272a38409be43e3ae0550"}, + {file = "zope.interface-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:de125151a53ecdb39df3cb3deb9951ed834dd6a110a9e795d985b10bb6db4532"}, + {file = "zope.interface-6.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f444de0565db46d26c9fa931ca14f497900a295bd5eba480fc3fad25af8c763e"}, + {file = "zope.interface-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2fefad268ff5c5b314794e27e359e48aeb9c8bb2cbb5748a071757a56f6bb8f"}, + {file = "zope.interface-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97785604824981ec8c81850dd25c8071d5ce04717a34296eeac771231fbdd5cd"}, + {file = "zope.interface-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7b2bed4eea047a949296e618552d3fed00632dc1b795ee430289bdd0e3717f3"}, + {file = "zope.interface-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:d54f66c511ea01b9ef1d1a57420a93fbb9d48a08ec239f7d9c581092033156d0"}, + {file = "zope.interface-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5ee9789a20b0081dc469f65ff6c5007e67a940d5541419ca03ef20c6213dd099"}, + {file = "zope.interface-6.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af27b3fe5b6bf9cd01b8e1c5ddea0a0d0a1b8c37dc1c7452f1e90bf817539c6d"}, + {file = "zope.interface-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bce517b85f5debe07b186fc7102b332676760f2e0c92b7185dd49c138734b70"}, + {file = "zope.interface-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ae9793f114cee5c464cc0b821ae4d36e1eba961542c6086f391a61aee167b6f"}, + {file = "zope.interface-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e87698e2fea5ca2f0a99dff0a64ce8110ea857b640de536c76d92aaa2a91ff3a"}, + {file = "zope.interface-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:b66335bbdbb4c004c25ae01cc4a54fd199afbc1fd164233813c6d3c2293bb7e1"}, + {file = "zope.interface-6.2.tar.gz", hash = "sha256:3b6c62813c63c543a06394a636978b22dffa8c5410affc9331ce6cdb5bfa8565"}, ] [package.dependencies] @@ -7876,4 +7869,4 @@ reference = "tsinghua" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "3d6e2ccd4d1c1943d9bda901601872db7eb0564858a258372ad7ccf02c978378" +content-hash = "9f9294b5efb21a24625429dddb084c8d7f53b4d9d7d41c534d249bc9ed512905" diff --git a/pyproject.toml b/pyproject.toml index c25951966..e0d084724 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ pynacl = "1.5.0" python-dateutil = "2.8.2" pyyaml = "6.0.1" requests = "2.31.0" -jms-storage = "0.0.53" +jms-storage = "0.0.56" simplejson = "3.19.1" six = "1.16.0" sshtunnel = "0.4.0" @@ -147,6 +147,8 @@ mistune = "2.0.3" openai = "^1.3.7" xlsxwriter = "^3.1.9" exchangelib = "^5.1.0" +xmlsec = "^1.3.13" +lxml = "4.9.3" [tool.poetry.group.xpack.dependencies] diff --git a/utils/start_celery_beat.py b/utils/start_celery_beat.py index 2f089a4af..d2e0d4753 100644 --- a/utils/start_celery_beat.py +++ b/utils/start_celery_beat.py @@ -19,9 +19,7 @@ os.environ.setdefault('PYTHONOPTIMIZE', '1') if os.getuid() == 0: os.environ.setdefault('C_FORCE_ROOT', '1') -connection_params = { - 'password': settings.REDIS_PASSWORD, -} +connection_params = {} if settings.REDIS_USE_SSL: connection_params['ssl'] = settings.REDIS_USE_SSL @@ -36,6 +34,7 @@ REDIS_SENTINEL_PASSWORD = settings.REDIS_SENTINEL_PASSWORD REDIS_SENTINEL_SOCKET_TIMEOUT = settings.REDIS_SENTINEL_SOCKET_TIMEOUT if REDIS_SENTINEL_SERVICE_NAME and REDIS_SENTINELS: connection_params['sentinels'] = REDIS_SENTINELS + connection_params['password'] = settings.REDIS_PASSWORD sentinel_client = Sentinel( **connection_params, sentinel_kwargs={ 'ssl': settings.REDIS_USE_SSL, @@ -52,7 +51,7 @@ else: REDIS_PROTOCOL = 'rediss' if settings.REDIS_USE_SSL else 'redis' REDIS_LOCATION_NO_DB = '%(protocol)s://:%(password)s@%(host)s:%(port)s' % { 'protocol': REDIS_PROTOCOL, - 'password': settings.REDIS_PASSWORD, + 'password': settings.REDIS_PASSWORD_QUOTE, 'host': settings.REDIS_HOST, 'port': settings.REDIS_PORT, }