From e509568fe50502ec2f57d6f1003c6dab1583655d Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Thu, 18 Jan 2024 18:05:21 +0800 Subject: [PATCH 01/69] =?UTF-8?q?fix:=20redis=20=E5=AF=86=E7=A0=81?= =?UTF-8?q?=E6=9C=89=E7=89=B9=E6=AE=8A=E5=AD=97=E7=AC=A6celery=20beat?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/start_celery_beat.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/utils/start_celery_beat.py b/utils/start_celery_beat.py index 19d578e70..2f089a4af 100644 --- a/utils/start_celery_beat.py +++ b/utils/start_celery_beat.py @@ -1,13 +1,12 @@ #!/usr/bin/env python # import os -import sys import signal import subprocess +import sys import redis_lock - -from redis import Redis, Sentinel +from redis import Redis, Sentinel, ConnectionPool BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) APPS_DIR = os.path.join(BASE_DIR, 'apps') @@ -50,9 +49,15 @@ if REDIS_SENTINEL_SERVICE_NAME and REDIS_SENTINELS: ) redis_client = sentinel_client.master_for(REDIS_SENTINEL_SERVICE_NAME) else: - connection_params['host'] = settings.REDIS_HOST - connection_params['port'] = settings.REDIS_PORT - redis_client = Redis(**connection_params) + 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, + 'host': settings.REDIS_HOST, + 'port': settings.REDIS_PORT, + } + pool = ConnectionPool.from_url(REDIS_LOCATION_NO_DB, **connection_params) + redis_client = Redis(connection_pool=pool) scheduler = "ops.celery.beat.schedulers:DatabaseScheduler" processes = [] From 37a0d831da44892d42f156ea4b7f7132f96bf83c Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Thu, 18 Jan 2024 10:55:02 +0800 Subject: [PATCH 02/69] perf:ldap sync add no user msg --- apps/locale/ja/LC_MESSAGES/django.mo | 4 ++-- apps/locale/ja/LC_MESSAGES/django.po | 10 +++++++--- apps/locale/zh/LC_MESSAGES/django.mo | 4 ++-- apps/locale/zh/LC_MESSAGES/django.po | 10 +++++++--- .../settings/templates/ldap/_msg_import_ldap_user.html | 10 +++++++--- 5 files changed, 25 insertions(+), 13 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 0f74a7c63..5636acce0 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:762a632de4e679462b64cc5baee5e0851fd0e075b63895f2da7ee89de3a11cd3 +size 171043 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index c6a6dfe37..48be25a42 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-01-18 10:45+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -495,7 +495,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 "間違い" @@ -6112,6 +6112,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:// プロトコルが使用されます。" @@ -8511,7 +8515,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..0dd3e1e12 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:77bcfafe99a5e93c5710639e88a0648bce49c666eeb3b4b02185a9f490413bcf +size 140193 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 73f1032a6..8aabf6615 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-01-18 10:44+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -494,7 +494,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 "错误" @@ -6028,6 +6028,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:// 协议" @@ -8387,7 +8391,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/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' %}: From dc79346bdcae3315dcabec106d966aa88b197c20 Mon Sep 17 00:00:00 2001 From: Bai Date: Thu, 18 Jan 2024 19:43:55 +0800 Subject: [PATCH 03/69] =?UTF-8?q?perf:=20=E4=BF=AE=E5=A4=8D=20Count=20?= =?UTF-8?q?=E6=97=B6=E6=B2=A1=E6=9C=89=E5=8E=BB=E9=87=8D=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/accounts/tasks/remove_account.py | 2 +- apps/assets/serializers/domain.py | 2 +- apps/common/drf/filters.py | 2 +- apps/jumpserver/api.py | 4 ++-- apps/labels/serializers.py | 2 +- apps/ops/api/job.py | 2 +- apps/perms/serializers/permission.py | 8 ++++---- apps/rbac/api/role.py | 6 ++++-- apps/users/models/user.py | 2 +- apps/users/serializers/group.py | 2 +- 10 files changed, 17 insertions(+), 15 deletions(-) diff --git a/apps/accounts/tasks/remove_account.py b/apps/accounts/tasks/remove_account.py index 44bb9a840..6b637ed96 100644 --- a/apps/accounts/tasks/remove_account.py +++ b/apps/accounts/tasks/remove_account.py @@ -55,7 +55,7 @@ def clean_historical_accounts(): history_model = Account.history.model history_id_mapper = defaultdict(list) - ids = history_model.objects.values('id').annotate(count=Count('id')) \ + ids = history_model.objects.values('id').annotate(count=Count('id', distinct=True)) \ .filter(count__gte=limit).values_list('id', flat=True) if not ids: diff --git a/apps/assets/serializers/domain.py b/apps/assets/serializers/domain.py index 9ea603ac3..4ada8fc2f 100644 --- a/apps/assets/serializers/domain.py +++ b/apps/assets/serializers/domain.py @@ -58,7 +58,7 @@ class DomainListSerializer(DomainSerializer): @classmethod def setup_eager_loading(cls, queryset): queryset = queryset.annotate( - assets_amount=Count('assets'), + assets_amount=Count('assets', distinct=True), ) return queryset diff --git a/apps/common/drf/filters.py b/apps/common/drf/filters.py index d84692dfe..85475f479 100644 --- a/apps/common/drf/filters.py +++ b/apps/common/drf/filters.py @@ -206,7 +206,7 @@ class LabelFilterBackend(filters.BaseFilterBackend): resources = resources.filter(q) \ .values('res_id') \ .order_by('res_id') \ - .annotate(count=Count('res_id')) \ + .annotate(count=Count('res_id', distinct=True)) \ .values('res_id', 'count') \ .filter(count=len(args)) return resources diff --git a/apps/jumpserver/api.py b/apps/jumpserver/api.py index cfa6b771d..5b672d5f9 100644 --- a/apps/jumpserver/api.py +++ b/apps/jumpserver/api.py @@ -182,14 +182,14 @@ class DatesLoginMetricMixin: def get_dates_login_times_assets(self): assets = self.sessions_queryset.values("asset") \ - .annotate(total=Count("asset")) \ + .annotate(total=Count("asset", distinct=True)) \ .annotate(last=Cast(Max("date_start"), output_field=CharField())) \ .order_by("-total") return list(assets[:10]) def get_dates_login_times_users(self): users = self.sessions_queryset.values("user_id") \ - .annotate(total=Count("user_id")) \ + .annotate(total=Count("user_id", distinct=True)) \ .annotate(user=Max('user')) \ .annotate(last=Cast(Max("date_start"), output_field=CharField())) \ .order_by("-total") diff --git a/apps/labels/serializers.py b/apps/labels/serializers.py index 803843ad8..62abc1bc8 100644 --- a/apps/labels/serializers.py +++ b/apps/labels/serializers.py @@ -34,7 +34,7 @@ class LabelSerializer(BulkOrgResourceModelSerializer): @classmethod def setup_eager_loading(cls, queryset): """ Perform necessary eager loading of data. """ - queryset = queryset.annotate(res_count=Count('labeled_resources')) + queryset = queryset.annotate(res_count=Count('labeled_resources', distinct=True)) return queryset diff --git a/apps/ops/api/job.py b/apps/ops/api/job.py index 61768f5d9..eb908d04c 100644 --- a/apps/ops/api/job.py +++ b/apps/ops/api/job.py @@ -246,6 +246,6 @@ class UsernameHintsAPI(APIView): .filter(username__icontains=query) \ .filter(asset__in=assets) \ .values('username') \ - .annotate(total=Count('username')) \ + .annotate(total=Count('username', distinct=True)) \ .order_by('total', '-username')[:10] return Response(data=top_accounts) diff --git a/apps/perms/serializers/permission.py b/apps/perms/serializers/permission.py index 3e32b40e1..35d6ecacd 100644 --- a/apps/perms/serializers/permission.py +++ b/apps/perms/serializers/permission.py @@ -198,9 +198,9 @@ class AssetPermissionListSerializer(AssetPermissionSerializer): """Perform necessary eager loading of data.""" queryset = queryset \ .prefetch_related('labels', 'labels__label') \ - .annotate(users_amount=Count("users"), - user_groups_amount=Count("user_groups"), - assets_amount=Count("assets"), - nodes_amount=Count("nodes"), + .annotate(users_amount=Count("users", distinct=True), + user_groups_amount=Count("user_groups", distinct=True), + assets_amount=Count("assets", distinct=True), + nodes_amount=Count("nodes", distinct=True), ) return queryset diff --git a/apps/rbac/api/role.py b/apps/rbac/api/role.py index b9133c5c5..022a2ac05 100644 --- a/apps/rbac/api/role.py +++ b/apps/rbac/api/role.py @@ -80,9 +80,11 @@ class RoleViewSet(JMSModelViewSet): queryset = Role.objects.filter(id__in=ids).order_by(*self.ordering) org_id = current_org.id q = Q(role__scope=Role.Scope.system) | Q(role__scope=Role.Scope.org, org_id=org_id) - role_bindings = RoleBinding.objects.filter(q).values_list('role_id').annotate(user_count=Count('user_id')) + role_bindings = RoleBinding.objects.filter(q).values_list('role_id').annotate( + user_count=Count('user_id', distinct=True) + ) role_user_amount_mapper = {role_id: user_count for role_id, user_count in role_bindings} - queryset = queryset.annotate(permissions_amount=Count('permissions')) + queryset = queryset.annotate(permissions_amount=Count('permissions', distinct=True)) queryset = list(queryset) for role in queryset: role.users_amount = role_user_amount_mapper.get(role.id, 0) diff --git a/apps/users/models/user.py b/apps/users/models/user.py index 290c0c1f1..f31ec6690 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -729,7 +729,7 @@ class JSONFilterMixin: bindings = RoleBinding.objects.filter(**kwargs, role__in=value) if match == 'm2m_all': - user_id = bindings.values('user_id').annotate(count=Count('user_id')) \ + user_id = bindings.values('user_id').annotate(count=Count('user_id', distinct=True)) \ .filter(count=len(value)).values_list('user_id', flat=True) else: user_id = bindings.values_list('user_id', flat=True) diff --git a/apps/users/serializers/group.py b/apps/users/serializers/group.py index 4c0de20f6..bbfc04918 100644 --- a/apps/users/serializers/group.py +++ b/apps/users/serializers/group.py @@ -46,7 +46,7 @@ class UserGroupSerializer(ResourceLabelsMixin, BulkOrgResourceModelSerializer): def setup_eager_loading(cls, queryset): """ Perform necessary eager loading of data. """ queryset = queryset.prefetch_related('labels', 'labels__label') \ - .annotate(users_amount=Count('users', filter=Q(users__is_service_account=False))) + .annotate(users_amount=Count('users', distinct=True, filter=Q(users__is_service_account=False))) return queryset From f74f8b7d8c468e4abe72f2c5aa02e26e844b6906 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 17 Jan 2024 19:31:01 +0800 Subject: [PATCH 04/69] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20delay=5Frun?= =?UTF-8?q?=20=E6=89=A7=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/backends/drf.py | 16 +++++++++------- apps/common/decorators.py | 11 ++++++++--- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/apps/authentication/backends/drf.py b/apps/authentication/backends/drf.py index 86999037d..29d586e27 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,20 +20,21 @@ 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(users=(user.id,)) if token: update_token_last_used(tokens=(token,)) diff --git a/apps/common/decorators.py b/apps/common/decorators.py index 7269c9e0d..0034a41df 100644 --- a/apps/common/decorators.py +++ b/apps/common/decorators.py @@ -101,7 +101,10 @@ 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('executor submit run {}'.format(func.__name__,)) return loop = _loop_thread.get_loop() @@ -136,10 +139,12 @@ class Debouncer(object): 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) + logger.error('thread {} delay run {} error: {}'.format( + threading.current_thread(), func.__name__, e)) _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) From ce94348d456a83c1378bd50dc8aca72cbf70b0aa Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 19 Jan 2024 11:11:50 +0800 Subject: [PATCH 05/69] perf: ignore some err --- apps/common/decorators.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/common/decorators.py b/apps/common/decorators.py index 0034a41df..12a72ce28 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 @@ -104,7 +105,8 @@ def run_debouncer_func(cache_key, org, ttl, func, *args, **kwargs): _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('executor submit run {}'.format(func.__name__,)) + logger.debug('pid {} executor submit run {}'.format( + os.getpid(), func.__name__, )) return loop = _loop_thread.get_loop() @@ -136,6 +138,11 @@ 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: @@ -143,8 +150,14 @@ def _run_func_with_org(key, org, func, *args, **kwargs): set_current_org(org) func(*args, **kwargs) except Exception as e: - logger.error('thread {} delay run {} error: {}'.format( - threading.current_thread(), func.__name__, 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) From cd0348cca16a4dcfc01bec7650a8eaf80d478eb2 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Thu, 18 Jan 2024 15:28:13 +0800 Subject: [PATCH 06/69] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=88=97=E8=A1=A8=E6=89=A7=E8=A1=8C=E6=97=B6=E9=97=B4?= =?UTF-8?q?=20=E6=80=A7=E8=83=BD=E5=BF=AB=E4=BA=8610=E5=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ops/api/celery.py | 43 +++++++++++++++++++++++++++++++++++++++ apps/ops/models/celery.py | 41 +++++++++++++++++++++++++++++-------- 2 files changed, 75 insertions(+), 9 deletions(-) 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/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") From 3853d0bcc6f3c4a5297d57250d1e545b70ea3533 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Thu, 18 Jan 2024 18:35:32 +0800 Subject: [PATCH 07/69] =?UTF-8?q?fix:=E7=BB=91=E5=AE=9A=E7=9A=84=E7=AB=AF?= =?UTF-8?q?=E7=82=B9Default=E4=B8=8B=E8=BD=BDRDP=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=9C=B0=E5=9D=80=E6=98=AF=E7=A9=BA=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/api/connection_token.py | 2 +- apps/terminal/api/component/endpoint.py | 2 +- apps/terminal/models/component/endpoint.py | 26 +++++++++++++-------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/authentication/api/connection_token.py b/apps/authentication/api/connection_token.py index 076767946..b5bafac32 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( 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/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 From 0c74e92bfb6b28b8de7476fd35c755e152a2435e Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:36:18 +0800 Subject: [PATCH 08/69] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20labels=20?= =?UTF-8?q?=E5=9C=A8=20json=20field=20=E4=B8=AD=E7=9A=84=E7=AD=9B=E9=80=89?= =?UTF-8?q?=20(#12577)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: 优化 labels 在 json field 中的筛选 * perf: 修改 labels 搜索 --------- Co-authored-by: ibuler --- apps/common/db/fields.py | 27 ++++++++++++++++---------- apps/common/drf/filters.py | 39 +++++++++++++++++--------------------- apps/labels/mixins.py | 36 ++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 33 deletions(-) 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/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/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) From 503034299e4dc106f9f7b20deea2681e04308c84 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Tue, 23 Jan 2024 11:07:56 +0800 Subject: [PATCH 09/69] =?UTF-8?q?fix:=20windows=20=E6=94=B6=E9=9B=86?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7=20=E6=94=B6=E9=9B=86=E5=A4=B1=E8=B4=A5=20(#1?= =?UTF-8?q?2583)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- .../accounts/automations/gather_accounts/host/windows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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: From 7aa6613e69b72b5d83484affadfb54b05be867e5 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Tue, 23 Jan 2024 11:39:44 +0800 Subject: [PATCH 10/69] =?UTF-8?q?perf:=20=E6=9B=B4=E6=96=B0jms-storage?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c25951966..a1a06b39f 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.54" simplejson = "3.19.1" six = "1.16.0" sshtunnel = "0.4.0" From 34aa48d18c5c0cfa1473c1fe7169025cb6e961e4 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 23 Jan 2024 17:15:34 +0800 Subject: [PATCH 11/69] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E6=A3=80=E6=B5=8B=E7=94=A8=E6=88=B7=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E6=B4=BB=E8=B7=83=E4=BB=BB=E5=8A=A1=E6=97=A0=E6=B3=95=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/users/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/users/tasks.py b/apps/users/tasks.py index 638e3bdec..7fd707ac7 100644 --- a/apps/users/tasks.py +++ b/apps/users/tasks.py @@ -86,7 +86,7 @@ def check_user_expired_periodic(): @tmp_to_root_org() def check_unused_users(): uncommon_users_ttl = settings.SECURITY_UNCOMMON_USERS_TTL - if not uncommon_users_ttl or not uncommon_users_ttl.isdigit(): + if not uncommon_users_ttl: return uncommon_users_ttl = int(uncommon_users_ttl) From e8bbc446476db61e949b9d743206b55cb7365e5c Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 24 Jan 2024 15:41:03 +0800 Subject: [PATCH 12/69] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E7=9A=84=E8=B5=84=E4=BA=A7=EF=BC=8C=E9=80=9F=E5=BA=A6?= =?UTF-8?q?=E5=BF=AB=2010=20=E5=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/models/node.py | 7 ++++-- apps/common/signal_handlers.py | 2 +- apps/perms/api/user_permission/assets.py | 2 +- apps/perms/serializers/user_permission.py | 4 +-- apps/perms/utils/user_perm.py | 30 +++++++++-------------- 5 files changed, 21 insertions(+), 24 deletions(-) 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/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/perms/api/user_permission/assets.py b/apps/perms/api/user_permission/assets.py index 6db934c3b..b21604d5a 100644 --- a/apps/perms/api/user_permission/assets.py +++ b/apps/perms/api/user_permission/assets.py @@ -38,7 +38,7 @@ class UserPermedAssetRetrieveApi(SelfOrPKUserMixin, RetrieveAPIView): class BaseUserPermedAssetsApi(SelfOrPKUserMixin, ListAPIView): - ordering = ('name',) + ordering = [] search_fields = ('name', 'address', 'comment') ordering_fields = ("name", "address") filterset_class = AssetFilterSet 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/user_perm.py b/apps/perms/utils/user_perm.py index d06f18a83..cbcecc99d 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,32 @@ 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): + def get_perm_nodes_assets(self): """ 获取所有授权节点下的资产 """ - from assets.models import Node - from ..models import AssetPermission 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)) + 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 From 8bde45d9dcc36d16b712cec4f46e3929850b1f13 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:20:44 +0800 Subject: [PATCH 13/69] =?UTF-8?q?perf:=20=E6=94=B9=E5=AF=86=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=9C=80=E5=90=8E=E6=B1=87=E6=80=BB=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=20(#12595)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- .../automations/change_secret/manager.py | 27 +++++-- apps/accounts/notifications.py | 15 ++-- apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/ja/LC_MESSAGES/django.po | 81 ++++++++++--------- apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 81 ++++++++++--------- 6 files changed, 121 insertions(+), 91 deletions(-) diff --git a/apps/accounts/automations/change_secret/manager.py b/apps/accounts/automations/change_secret/manager.py index 8381419ad..ee6aa436f 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 @@ -183,17 +184,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 @@ -213,7 +230,7 @@ class ChangeSecretManager(AccountBasePlaybookManager): attachment = os.path.join(path, f'{name}-{local_now_filename()}-{time.time()}.zip') encrypt_and_compress_zip_file(attachment, password, [filename]) attachments = [attachment] - ChangeSecretExecutionTaskMsg(name, user).publish(attachments) + ChangeSecretExecutionTaskMsg(name, user, summary).publish(attachments) os.remove(filename) @staticmethod diff --git a/apps/accounts/notifications.py b/apps/accounts/notifications.py index 404125fd3..30e952b98 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 -> " + "file encryption password to set the encryption password").format(name) + return self.summary + '\n' + default_message def publish(self, attachments=None): send_mail_attachment_async( diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 5636acce0..a6be67bca 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:762a632de4e679462b64cc5baee5e0851fd0e075b63895f2da7ee89de3a11cd3 -size 171043 +oid sha256:048704af814780b5ac924173460ccc8f7105530c469160093e8516c2ef0ae745 +size 171131 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 48be25a42..ea77eb2ec 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-18 10:45+0800\n" +"POT-Creation-Date: 2024-01-24 14:55+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:197 +#, 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 @@ -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:235 #: ops/templates/ops/celery_task_log.html:75 #: perms/models/asset_permission.py:78 #: settings/templates/ldap/_msg_import_ldap_user.html:5 @@ -471,7 +476,7 @@ 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:236 #: terminal/models/applet/host.py:142 msgid "Date finished" msgstr "終了日" @@ -604,12 +609,12 @@ 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:136 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/virtualapp/provider.py:10 @@ -630,7 +635,7 @@ 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/component/endpoint.py:120 #: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:167 msgid "Is active" msgstr "アクティブです。" @@ -714,13 +719,13 @@ 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 " @@ -729,7 +734,7 @@ msgstr "" "{} -暗号化変更タスクが完了しました: 暗号化パスワードが設定されていません-個人" "情報にアクセスしてください-> ファイル暗号化パスワードを設定してください" -#: accounts/notifications.py:79 +#: accounts/notifications.py:82 msgid "Gather account change information" msgstr "アカウント変更情報" @@ -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 @@ -930,7 +935,7 @@ msgstr "关联平台,可以配置推送参数,如果不关联,则使用默 #: 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 @@ -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、低い値は最初に一致します" @@ -2734,21 +2739,21 @@ msgstr "認証" 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 "無効なトークンまたはキャッシュの更新。" @@ -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 グループ" @@ -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,15 +4065,15 @@ 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 "タスク実行パラメータエラー" @@ -4241,7 +4246,7 @@ msgstr "パターン" 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:138 #: terminal/models/component/task.py:14 msgid "Args" msgstr "アルグ" @@ -4273,28 +4278,28 @@ 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 +#: ops/models/celery.py:84 terminal/models/session/sharing.py:128 #: tickets/const.py:25 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 タスク実行" @@ -4666,7 +4671,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 "内部ロール、更新できません" @@ -6729,14 +6734,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 "エンドポイントルール" @@ -8515,7 +8520,7 @@ msgstr "そして" msgid "Or" msgstr "または" -#: xpack/plugins/cloud/manager.py:57 +#: xpack/plugins/cloud/manager.py:56 msgid "Account unavailable" msgstr "利用できないアカウント" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 0dd3e1e12..fd213b554 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:77bcfafe99a5e93c5710639e88a0648bce49c666eeb3b4b02185a9f490413bcf -size 140193 +oid sha256:29124b882dd0a8fc73bc0c5669c20c3224823df45a8aef580cbecd73339edc30 +size 140335 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 8aabf6615..f59eb5fe0 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-18 10:44+0800\n" +"POT-Creation-Date: 2024-01-24 14:55+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:197 +#, 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 @@ -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:235 #: ops/templates/ops/celery_task_log.html:75 #: perms/models/asset_permission.py:78 #: settings/templates/ldap/_msg_import_ldap_user.html:5 @@ -470,7 +475,7 @@ 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:236 #: terminal/models/applet/host.py:142 msgid "Date finished" msgstr "结束日期" @@ -603,12 +608,12 @@ 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:136 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/virtualapp/provider.py:10 @@ -629,7 +634,7 @@ 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/component/endpoint.py:120 #: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:167 msgid "Is active" msgstr "激活" @@ -712,13 +717,13 @@ 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 " @@ -727,7 +732,7 @@ msgstr "" "{} - 改密任务已完成: 未设置加密密码 - 请前往个人信息 -> 文件加密密码中设置加" "密密码" -#: accounts/notifications.py:79 +#: accounts/notifications.py:82 msgid "Gather account change information" msgstr "账号变更信息" @@ -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 @@ -928,7 +933,7 @@ msgstr "关联平台,可配置推送参数,如果不关联,将使用默认 #: 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 @@ -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 (数值越小越优先)" @@ -2713,20 +2718,20 @@ msgstr "认证" 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 "刷新的令牌或缓存无效。" @@ -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グループ" @@ -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,15 +4016,15 @@ 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 "任务 {} 执行参数错误" @@ -4190,7 +4195,7 @@ msgstr "模式" 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:138 #: terminal/models/component/task.py:14 msgid "Args" msgstr "参数" @@ -4222,28 +4227,28 @@ 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 +#: ops/models/celery.py:84 terminal/models/session/sharing.py:128 #: tickets/const.py:25 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 任务执行" @@ -4614,7 +4619,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 "内部角色,不能更新" @@ -6635,14 +6640,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 "端点规则" @@ -8391,7 +8396,7 @@ msgstr "与" msgid "Or" msgstr "或" -#: xpack/plugins/cloud/manager.py:57 +#: xpack/plugins/cloud/manager.py:56 msgid "Account unavailable" msgstr "账号无效" From f5802ace025a57448d6f2b2366829b8e1b55943e Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:39:43 +0800 Subject: [PATCH 14/69] =?UTF-8?q?fix:=20oracle=20=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=98=AFsysdba=E7=B1=BB=E5=9E=8B=E7=9A=84=20=E6=94=B9=E5=AF=86?= =?UTF-8?q?=E6=8E=A8=E9=80=81=20=E9=AA=8C=E8=AF=81=E8=B4=A6=E5=8F=B7?= =?UTF-8?q?=E5=8F=AF=E8=BF=9E=E6=8E=A5=E6=80=A7=E5=A4=B1=E8=B4=A5=20(#1259?= =?UTF-8?q?6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/accounts/automations/change_secret/database/oracle/main.yml | 1 + apps/accounts/automations/push_account/database/oracle/main.yml | 1 + 2 files changed, 2 insertions(+) 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/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 }}" From 0303408be80a871727925e66fd95b627c7a0d317 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 23 Jan 2024 16:45:59 +0800 Subject: [PATCH 15/69] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E6=A0=91=E7=9A=84=E5=88=B7=E6=96=B0=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E8=A7=A3=E5=86=B3=E5=90=8C=E6=AD=A5=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/accounts/signal_handlers.py | 2 +- apps/assets/signal_handlers/asset.py | 4 +- .../signal_handlers/node_assets_amount.py | 21 ++++++++- .../signal_handlers/node_assets_mapping.py | 6 +-- apps/authentication/backends/drf.py | 4 +- apps/common/decorators.py | 47 ++++++++++++------- apps/jumpserver/settings/custom.py | 3 ++ apps/orgs/signal_handlers/cache.py | 2 +- apps/perms/utils/user_perm_tree.py | 17 +++++-- 9 files changed, 72 insertions(+), 34 deletions(-) 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/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/authentication/backends/drf.py b/apps/authentication/backends/drf.py index 29d586e27..4cf2577c1 100644 --- a/apps/authentication/backends/drf.py +++ b/apps/authentication/backends/drf.py @@ -34,9 +34,9 @@ def update_user_last_used(users=()): def after_authenticate_update_date(user, token=None): - update_user_last_used(users=(user.id,)) + 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/common/decorators.py b/apps/common/decorators.py index 12a72ce28..171a4ff33 100644 --- a/apps/common/decorators.py +++ b/apps/common/decorators.py @@ -199,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: @@ -206,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/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index 311e54aa8..2457b28b1 100644 --- a/apps/jumpserver/settings/custom.py +++ b/apps/jumpserver/settings/custom.py @@ -214,6 +214,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 diff --git a/apps/orgs/signal_handlers/cache.py b/apps/orgs/signal_handlers/cache.py index 4dc3c796e..975392ad9 100644 --- a/apps/orgs/signal_handlers/cache.py +++ b/apps/orgs/signal_handlers/cache.py @@ -87,7 +87,7 @@ class OrgResourceStatisticsRefreshUtil: if not cache_field_name: return org = getattr(instance, 'org', None) - cls.refresh_org_fields(((org, cache_field_name),)) + cls.refresh_org_fields.delay(org_fields=((org, cache_field_name),)) @receiver(post_save) diff --git a/apps/perms/utils/user_perm_tree.py b/apps/perms/utils/user_perm_tree.py index 13577a9b1..4514c78ca 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) From 1f5554d9450a90250994887540246bc2174b1a71 Mon Sep 17 00:00:00 2001 From: Bai Date: Wed, 24 Jan 2024 16:20:08 +0800 Subject: [PATCH 16/69] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20OAuth2=20?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E6=97=B6=20POST=20=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=20access=5Ftoken=20API=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=20json=20=E4=BC=A0=E9=80=92=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/backends/oauth2/backends.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/authentication/backends/oauth2/backends.py b/apps/authentication/backends/oauth2/backends.py index 0c40d09bd..9f3b04ac3 100644 --- a/apps/authentication/backends/oauth2/backends.py +++ b/apps/authentication/backends/oauth2/backends.py @@ -105,7 +105,7 @@ class OAuth2Backend(JMSModelBackend): 'Accept': 'application/json' } if token_method == 'post': - access_token_response = requests_func(access_token_url, headers=headers, data=query_dict) + access_token_response = requests_func(access_token_url, headers=headers, json=query_dict) else: access_token_response = requests_func(access_token_url, headers=headers) try: From 1dea424104a29f9fe1894fcd48abf210a2a02a53 Mon Sep 17 00:00:00 2001 From: Bryan Date: Wed, 24 Jan 2024 18:22:33 +0800 Subject: [PATCH 17/69] =?UTF-8?q?Revert=20"fix:=20=E4=BF=AE=E5=A4=8D=20OAu?= =?UTF-8?q?th2=20=E8=AE=A4=E8=AF=81=E6=97=B6=20POST=20=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=20access=5Ftoken=20API=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=20json=20=E4=BC=A0=E9=80=92=E6=95=B0=E6=8D=AE"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/backends/oauth2/backends.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/authentication/backends/oauth2/backends.py b/apps/authentication/backends/oauth2/backends.py index 9f3b04ac3..0c40d09bd 100644 --- a/apps/authentication/backends/oauth2/backends.py +++ b/apps/authentication/backends/oauth2/backends.py @@ -105,7 +105,7 @@ class OAuth2Backend(JMSModelBackend): 'Accept': 'application/json' } if token_method == 'post': - access_token_response = requests_func(access_token_url, headers=headers, json=query_dict) + access_token_response = requests_func(access_token_url, headers=headers, data=query_dict) else: access_token_response = requests_func(access_token_url, headers=headers) try: From a6bf592046c5baadf1c86a2cc18b6ae7030d8276 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Wed, 24 Jan 2024 19:50:05 +0800 Subject: [PATCH 18/69] =?UTF-8?q?perf:=20=E7=BF=BB=E8=AF=91=20(#12600)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/accounts/notifications.py | 2 +- apps/locale/ja/LC_MESSAGES/django.mo | 4 ++-- apps/locale/ja/LC_MESSAGES/django.po | 22 +++++++++++----------- apps/locale/zh/LC_MESSAGES/django.mo | 4 ++-- apps/locale/zh/LC_MESSAGES/django.po | 24 ++++++++++++------------ 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/apps/accounts/notifications.py b/apps/accounts/notifications.py index 30e952b98..0082f8b80 100644 --- a/apps/accounts/notifications.py +++ b/apps/accounts/notifications.py @@ -69,7 +69,7 @@ class ChangeSecretExecutionTaskMsg(object): else: default_message = _("{} - 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) + "set encryption password in preferences").format(name) return self.summary + '\n' + default_message def publish(self, attachments=None): diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index a6be67bca..155ab1500 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:048704af814780b5ac924173460ccc8f7105530c469160093e8516c2ef0ae745 -size 171131 +oid sha256:84c1ff8fcd2a035e5c0919aa1337ac85d22f0e4676eca33dddfdcf7896717f99 +size 171105 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index ea77eb2ec..968eab5bb 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-24 14:55+0800\n" +"POT-Creation-Date: 2024-01-24 19:44+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -728,11 +728,11 @@ msgstr "{} -暗号化変更タスクが完了しました。詳細は添付フ #: 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:82 msgid "Gather account change information" @@ -1749,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" @@ -1889,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 @@ -1912,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 "ノードを一致させることができます" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index fd213b554..b1ddceb46 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:29124b882dd0a8fc73bc0c5669c20c3224823df45a8aef580cbecd73339edc30 -size 140335 +oid sha256:2d6388bc60eeeb67f9bc5deaf8aec65a6027bfebad2fb994104841775cdb912d +size 140312 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index f59eb5fe0..15809ca09 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-24 14:55+0800\n" +"POT-Creation-Date: 2024-01-24 19:44+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -726,11 +726,11 @@ msgstr "{} - 改密任务已完成, 详情见附件" #: 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:82 msgid "Gather account change information" @@ -1741,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" @@ -1881,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 @@ -1904,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 "可以匹配节点" From aee11827c404ca84a6743e580fc46e8d5ce483b1 Mon Sep 17 00:00:00 2001 From: Bai Date: Thu, 25 Jan 2024 11:46:04 +0800 Subject: [PATCH 19/69] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=20jms-storage?= =?UTF-8?q?=200.0.55?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- poetry.lock | 6 +++--- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3271ee6c7..c7edaeee5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3582,12 +3582,12 @@ reference = "tsinghua" [[package]] name = "jms-storage" -version = "0.0.53" +version = "0.0.55" 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.55.tar.gz", hash = "sha256:cab3ac01b9733dd30101b59dd21de104543355c010ca0024cfaed3069e392cfa"}, ] [package.dependencies] @@ -7876,4 +7876,4 @@ reference = "tsinghua" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "3d6e2ccd4d1c1943d9bda901601872db7eb0564858a258372ad7ccf02c978378" +content-hash = "ae542c3660a6fc5fde022a23cc23b0f7be1229a0e4249f924f07d1bd8d4efc95" diff --git a/pyproject.toml b/pyproject.toml index a1a06b39f..ecc2d8c9b 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.54" +jms-storage = "0.0.55" simplejson = "3.19.1" six = "1.16.0" sshtunnel = "0.4.0" From 7897462e324dc7b484bab49fcae9cd3d1bf3dbc0 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Thu, 25 Jan 2024 11:53:06 +0800 Subject: [PATCH 20/69] perf: jms_storage==0.0.55 --- poetry.lock | 399 +++++++++++++++++++++++++--------------------------- 1 file changed, 193 insertions(+), 206 deletions(-) diff --git a/poetry.lock b/poetry.lock index c7edaeee5..bb0ab022b 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.6.1 and should not be changed by hand. [[package]] name = "adal" @@ -730,17 +730,16 @@ reference = "tsinghua" [[package]] name = "azure-core" -version = "1.29.6" +version = "1.29.7" 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.29.7.tar.gz", hash = "sha256:2944faf1a7ff1558b1f457cabf60f279869cabaeef86b353bed8eb032c7d8c5e"}, + {file = "azure_core-1.29.7-py3-none-any.whl", hash = "sha256:95a7b41b4af102e5fcdfac9500fcc82ff86e936c7145a099b7848b9ac0501250"}, ] [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"] @@ -1927,7 +1929,7 @@ reference = "tsinghua" [[package]] name = "django-cas-ng" version = "4.3.0" -description = "Django CAS 1.0/2.0/3.0 client authentication library, support Django 2.2, 3.0, 3.1, 3.2, 4.0 and Python 3.7+" +description = "" optional = false python-versions = ">=3.7" files = [ @@ -2260,22 +2262,23 @@ reference = "tsinghua" [[package]] name = "dnspython" -version = "2.4.2" +version = "2.5.0" 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.5.0-py3-none-any.whl", hash = "sha256:6facdf76b73c742ccf2d07add296f178e629da60be23ce4b0a9c927b1e02c3a6"}, + {file = "dnspython-2.5.0.tar.gz", hash = "sha256:a0034815a59ba9ae888946be7ccca8f7c157b286f8455b379c692efb51022a15"}, ] [package.extras] -dnssec = ["cryptography (>=2.6,<42.0)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.24.1)"] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=5.0.3)", "mypy (>=1.0.1)", "pylint (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0.0)", "sphinx (>=7.0.0)", "twine (>=4.0.0)", "wheel (>=0.41.0)"] +dnssec = ["cryptography (>=41)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.25.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)"] +idna = ["idna (>=2.1)"] +trio = ["trio (>=0.14)"] +wmi = ["wmi (>=1.5.1)"] [package.source] type = "legacy" @@ -2833,14 +2836,8 @@ files = [ [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 +2853,13 @@ reference = "tsinghua" [[package]] name = "google-auth" -version = "2.25.2" +version = "2.27.0" 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.27.0.tar.gz", hash = "sha256:e863a56ccc2d8efa83df7a80272601e43487fa9a728a376205c86c26aaefa821"}, + {file = "google_auth-2.27.0-py2.py3-none-any.whl", hash = "sha256:8e4bad367015430ff253fe49d500fdc3396c1a434db5740828c728e45bcce245"}, ] [package.dependencies] @@ -3785,106 +3782,96 @@ reference = "tsinghua" [[package]] name = "lxml" -version = "5.0.0" +version = "5.1.0" 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.*" +python-versions = ">=3.6" 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-5.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e"}, + {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da"}, + {file = "lxml-5.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c"}, + {file = "lxml-5.1.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb"}, + {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2befa20a13f1a75c751f47e00929fb3433d67eb9923c2c0b364de449121f447c"}, + {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22b7ee4c35f374e2c20337a95502057964d7e35b996b1c667b5c65c567d2252a"}, + {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bf8443781533b8d37b295016a4b53c1494fa9a03573c09ca5104550c138d5c05"}, + {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147"}, + {file = "lxml-5.1.0-cp310-cp310-win32.whl", hash = "sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93"}, + {file = "lxml-5.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d"}, + {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f"}, + {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4"}, + {file = "lxml-5.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a"}, + {file = "lxml-5.1.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa"}, + {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af8920ce4a55ff41167ddbc20077f5698c2e710ad3353d32a07d3264f3a2021e"}, + {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cfced4a069003d8913408e10ca8ed092c49a7f6cefee9bb74b6b3e860683b45"}, + {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9e5ac3437746189a9b4121db2a7b86056ac8786b12e88838696899328fc44bb2"}, + {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204"}, + {file = "lxml-5.1.0-cp311-cp311-win32.whl", hash = "sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b"}, + {file = "lxml-5.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda"}, + {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114"}, + {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8"}, + {file = "lxml-5.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e"}, + {file = "lxml-5.1.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a"}, + {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16dd953fb719f0ffc5bc067428fc9e88f599e15723a85618c45847c96f11f431"}, + {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16018f7099245157564d7148165132c70adb272fb5a17c048ba70d9cc542a1a1"}, + {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:82cd34f1081ae4ea2ede3d52f71b7be313756e99b4b5f829f89b12da552d3aa3"}, + {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:19a1bc898ae9f06bccb7c3e1dfd73897ecbbd2c96afe9095a6026016e5ca97b8"}, + {file = "lxml-5.1.0-cp312-cp312-win32.whl", hash = "sha256:13521a321a25c641b9ea127ef478b580b5ec82aa2e9fc076c86169d161798b01"}, + {file = "lxml-5.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:1ad17c20e3666c035db502c78b86e58ff6b5991906e55bdbef94977700c72623"}, + {file = "lxml-5.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:24ef5a4631c0b6cceaf2dbca21687e29725b7c4e171f33a8f8ce23c12558ded1"}, + {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d2900b7f5318bc7ad8631d3d40190b95ef2aa8cc59473b73b294e4a55e9f30f"}, + {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:601f4a75797d7a770daed8b42b97cd1bb1ba18bd51a9382077a6a247a12aa38d"}, + {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4b68c961b5cc402cbd99cca5eb2547e46ce77260eb705f4d117fd9c3f932b95"}, + {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:afd825e30f8d1f521713a5669b63657bcfe5980a916c95855060048b88e1adb7"}, + {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:262bc5f512a66b527d026518507e78c2f9c2bd9eb5c8aeeb9f0eb43fcb69dc67"}, + {file = "lxml-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:e856c1c7255c739434489ec9c8aa9cdf5179785d10ff20add308b5d673bed5cd"}, + {file = "lxml-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c7257171bb8d4432fe9d6fdde4d55fdbe663a63636a17f7f9aaba9bcb3153ad7"}, + {file = "lxml-5.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b9e240ae0ba96477682aa87899d94ddec1cc7926f9df29b1dd57b39e797d5ab5"}, + {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a96f02ba1bcd330807fc060ed91d1f7a20853da6dd449e5da4b09bfcc08fdcf5"}, + {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3898ae2b58eeafedfe99e542a17859017d72d7f6a63de0f04f99c2cb125936"}, + {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61c5a7edbd7c695e54fca029ceb351fc45cd8860119a0f83e48be44e1c464862"}, + {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3aeca824b38ca78d9ee2ab82bd9883083d0492d9d17df065ba3b94e88e4d7ee6"}, + {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764"}, + {file = "lxml-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8"}, + {file = "lxml-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b"}, + {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1"}, + {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5"}, + {file = "lxml-5.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84"}, + {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa"}, + {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45"}, + {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:98f3f020a2b736566c707c8e034945c02aa94e124c24f77ca097c446f81b01f1"}, + {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e"}, + {file = "lxml-5.1.0-cp38-cp38-win32.whl", hash = "sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a"}, + {file = "lxml-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1"}, + {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354"}, + {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969"}, + {file = "lxml-5.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3"}, + {file = "lxml-5.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581"}, + {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f8b0c78e7aac24979ef09b7f50da871c2de2def043d468c4b41f512d831e912"}, + {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bcf86dfc8ff3e992fed847c077bd875d9e0ba2fa25d859c3a0f0f76f07f0c8d"}, + {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:49a9b4af45e8b925e1cd6f3b15bbba2c81e7dba6dce170c677c9cda547411e14"}, + {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:280f3edf15c2a967d923bcfb1f8f15337ad36f93525828b40a0f9d6c2ad24890"}, + {file = "lxml-5.1.0-cp39-cp39-win32.whl", hash = "sha256:ed7326563024b6e91fef6b6c7a1a2ff0a71b97793ac33dbbcf38f6005e51ff6e"}, + {file = "lxml-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:8d7b4beebb178e9183138f552238f7e6613162a42164233e2bda00cb3afac58f"}, + {file = "lxml-5.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9bd0ae7cc2b85320abd5e0abad5ccee5564ed5f0cc90245d2f9a8ef330a8deae"}, + {file = "lxml-5.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8c1d679df4361408b628f42b26a5d62bd3e9ba7f0c0e7969f925021554755aa"}, + {file = "lxml-5.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2ad3a8ce9e8a767131061a22cd28fdffa3cd2dc193f399ff7b81777f3520e372"}, + {file = "lxml-5.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:304128394c9c22b6569eba2a6d98392b56fbdfbad58f83ea702530be80d0f9df"}, + {file = "lxml-5.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d74fcaf87132ffc0447b3c685a9f862ffb5b43e70ea6beec2fb8057d5d2a1fea"}, + {file = "lxml-5.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8cf5877f7ed384dabfdcc37922c3191bf27e55b498fecece9fd5c2c7aaa34c33"}, + {file = "lxml-5.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:877efb968c3d7eb2dad540b6cabf2f1d3c0fbf4b2d309a3c141f79c7e0061324"}, + {file = "lxml-5.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f14a4fb1c1c402a22e6a341a24c1341b4a3def81b41cd354386dcb795f83897"}, + {file = "lxml-5.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:25663d6e99659544ee8fe1b89b1a8c0aaa5e34b103fab124b17fa958c4a324a6"}, + {file = "lxml-5.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8b9f19df998761babaa7f09e6bc169294eefafd6149aaa272081cbddc7ba4ca3"}, + {file = "lxml-5.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e53d7e6a98b64fe54775d23a7c669763451340c3d44ad5e3a3b48a1efbdc96f"}, + {file = "lxml-5.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c3cd1fc1dc7c376c54440aeaaa0dcc803d2126732ff5c6b68ccd619f2e64be4f"}, + {file = "lxml-5.1.0.tar.gz", hash = "sha256:3eea6ed6e6c918e468e693c41ef07f3c3acc310b70ddd9cc72d9ef84bc9564ca"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.7)"] +source = ["Cython (>=3.0.8)"] [package.source] type = "legacy" @@ -3976,59 +3963,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] @@ -4331,13 +4318,13 @@ reference = "tsinghua" [[package]] name = "netaddr" -version = "0.10.0" +version = "0.10.1" description = "A network address manipulation library for Python" optional = false python-versions = "*" 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-0.10.1-py2.py3-none-any.whl", hash = "sha256:9822305b42ea1020d54fee322d43cee5622b044c07a1f0130b459bb467efcf88"}, + {file = "netaddr-0.10.1.tar.gz", hash = "sha256:f4da4222ca8c3f43c8e18a8263e5426c750a3a837fdfeccf74c68d0408eaa3bf"}, ] [package.source] @@ -4427,13 +4414,13 @@ reference = "tsinghua" [[package]] name = "openai" -version = "1.6.1" +version = "1.9.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.9.0-py3-none-any.whl", hash = "sha256:5774a0582ed82f6de92200ed5024e03e272b93e04e9d31caeda5fb80f63df50d"}, + {file = "openai-1.9.0.tar.gz", hash = "sha256:3e9947a544556c051fa138a4def5bd8b468364ec52803c6628532ab949ddce55"}, ] [package.dependencies] @@ -4556,13 +4543,13 @@ reference = "tsinghua" [[package]] name = "oslo-config" -version = "9.2.0" +version = "9.3.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.3.0-py3-none-any.whl", hash = "sha256:5642e75ab8070aee96563670b1c1ee3b6f3cac3c0302fe7fc78973cd4b4e3d29"}, + {file = "oslo.config-9.3.0.tar.gz", hash = "sha256:a4b1e526135d67c0e9b14d3ed299c6ec8a3887f92afcb26f4f3ea918504a3554"}, ] [package.dependencies] @@ -4604,13 +4591,13 @@ reference = "tsinghua" [[package]] name = "oslo-serialization" -version = "5.2.0" +version = "5.3.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.3.0-py3-none-any.whl", hash = "sha256:0da7248d0e515b875ef9883e3631ff51f9a8d11e8576247f0ded890f3276c0bf"}, + {file = "oslo.serialization-5.3.0.tar.gz", hash = "sha256:228898f4f33b7deabc74289b32bbd302a659c39cf6dda9048510f930fc4f76ed"}, ] [package.dependencies] @@ -4627,13 +4614,13 @@ reference = "tsinghua" [[package]] name = "oslo-utils" -version = "6.3.0" +version = "7.0.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.0.0-py3-none-any.whl", hash = "sha256:dbb724041a2ea0c342d524c4d7c7f07c8bc5016f4762d38c6a41b2ef805b3a8e"}, + {file = "oslo.utils-7.0.0.tar.gz", hash = "sha256:5263c00980cfab74f6635ef61d0fc91e6bd4a8dd0e78a77897ed6e447c8c6731"}, ] [package.dependencies] @@ -5007,22 +4994,22 @@ reference = "tsinghua" [[package]] name = "protobuf" -version = "4.25.1" +version = "4.25.2" 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.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"}, + {file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"}, + {file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"}, + {file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"}, + {file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"}, + {file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"}, + {file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"}, + {file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"}, + {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, ] [package.source] @@ -6622,13 +6609,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 +6625,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"] @@ -7078,13 +7065,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] @@ -7420,13 +7407,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] From 77569c554b8f08c6e14d008b6ad040913066bf28 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 25 Jan 2024 10:59:09 +0800 Subject: [PATCH 21/69] =?UTF-8?q?perf:=20=E5=8E=BB=E6=8E=89=E8=B5=84?= =?UTF-8?q?=E4=BA=A7=E6=9F=A5=E8=AF=A2=E7=9A=84=E9=BB=98=E8=AE=A4=E6=8E=92?= =?UTF-8?q?=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/asset/asset.py | 1 + apps/assets/migrations/0109_alter_asset_options.py | 2 +- apps/assets/models/asset/common.py | 2 +- apps/perms/api/user_permission/assets.py | 3 +++ 4 files changed, 6 insertions(+), 2 deletions(-) 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/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/perms/api/user_permission/assets.py b/apps/perms/api/user_permission/assets.py index b21604d5a..5456af1e3 100644 --- a/apps/perms/api/user_permission/assets.py +++ b/apps/perms/api/user_permission/assets.py @@ -1,5 +1,6 @@ import abc +from django.conf import settings from rest_framework.generics import ListAPIView, RetrieveAPIView from assets.api.asset.asset import AssetFilterSet @@ -47,6 +48,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 From 00256f86df2b6542dd7f5345589a58374bfa5833 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:00:13 +0800 Subject: [PATCH 22/69] =?UTF-8?q?perf:=20OAuth2=E5=8D=8F=E8=AE=AE=E8=8E=B7?= =?UTF-8?q?=E5=8F=96token=E6=94=AF=E6=8C=81=E9=85=8D=E7=BD=AEjson=E6=88=96?= =?UTF-8?q?=E8=80=85data=20(#12602)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: OAuth2协议获取token支持配置json或者data * perf: 优化注释 --------- Co-authored-by: jiangweidong --- apps/authentication/backends/oauth2/backends.py | 11 +++++++---- apps/settings/serializers/auth/oauth2.py | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) 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/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') From ef8db68db15f548b37f079c4f022af653b2966bc Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 25 Jan 2024 14:40:11 +0800 Subject: [PATCH 23/69] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=BB=84?= =?UTF-8?q?=E7=BB=87=E5=88=B7=E6=96=B0=E8=B5=84=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/orgs/signal_handlers/cache.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/orgs/signal_handlers/cache.py b/apps/orgs/signal_handlers/cache.py index 975392ad9..aec38527a 100644 --- a/apps/orgs/signal_handlers/cache.py +++ b/apps/orgs/signal_handlers/cache.py @@ -87,6 +87,7 @@ class OrgResourceStatisticsRefreshUtil: if not cache_field_name: return org = getattr(instance, 'org', None) + cache_field_name = tuple(cache_field_name) cls.refresh_org_fields.delay(org_fields=((org, cache_field_name),)) From 8aefacd7edf38129729cda29525b4f28ef4c7421 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Wed, 24 Jan 2024 15:19:03 +0800 Subject: [PATCH 24/69] =?UTF-8?q?perf:=20=E5=AE=89=E5=85=A8=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E8=BF=94=E5=9B=9E=E6=8E=88=E6=9D=83=E7=9A=84=E8=B5=84?= =?UTF-8?q?=E4=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/jumpserver/conf.py | 4 +- apps/jumpserver/settings/custom.py | 2 + apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/ja/LC_MESSAGES/django.po | 70 ++++++++++++++++------------ apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 70 ++++++++++++++++------------ apps/perms/utils/permission.py | 12 +++-- apps/perms/utils/user_perm.py | 11 +++-- apps/tickets/api/__init__.py | 1 + apps/tickets/api/perms.py | 66 ++++++++++++++++++++++++++ apps/tickets/const.py | 19 ++++++++ apps/tickets/urls/api_urls.py | 2 + 12 files changed, 194 insertions(+), 71 deletions(-) create mode 100644 apps/tickets/api/perms.py diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 741a0e5db..d2f99e85f 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -606,7 +606,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 = { diff --git a/apps/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index 2457b28b1..ed5cc61a9 100644 --- a/apps/jumpserver/settings/custom.py +++ b/apps/jumpserver/settings/custom.py @@ -227,3 +227,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/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 155ab1500..fcb22bbe4 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:84c1ff8fcd2a035e5c0919aa1337ac85d22f0e4676eca33dddfdcf7896717f99 -size 171105 +oid sha256:6a7f3882356366531dca8e6459bc4bc50dcbd1e0cf0c379ac93ee3bd1b679d3c +size 171329 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 968eab5bb..534a78731 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-24 19:44+0800\n" +"POT-Creation-Date: 2024-01-25 15:38+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -365,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:86 ops/models/job.py:235 +#: ops/models/base.py:55 ops/models/celery.py:86 ops/models/job.py:237 #: ops/templates/ops/celery_task_log.html:75 #: perms/models/asset_permission.py:78 #: settings/templates/ldap/_msg_import_ldap_user.html:5 @@ -476,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:87 ops/models/job.py:236 +#: ops/models/celery.py:87 ops/models/job.py:238 #: 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:229 #: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:140 #: terminal/models/component/status.py:30 #: terminal/models/virtualapp/virtualapp.py:99 @@ -609,7 +609,7 @@ 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:80 ops/models/job.py:136 ops/models/playbook.py:28 +#: ops/models/celery.py:80 ops/models/job.py:138 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 @@ -763,7 +763,7 @@ 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:146 #: 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 @@ -800,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:148 ops/serializers/job.py:19 #: terminal/templates/terminal/_msg_command_execute_alert.html:16 msgid "Assets" msgstr "資産" @@ -931,7 +931,7 @@ 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:154 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 @@ -1330,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 "" "資産を直接作成することはできません。ホストまたはその他を作成する必要がありま" @@ -1635,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:236 users/models/user.py:1042 msgid "Date created" msgstr "作成された日付" @@ -1804,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:232 #: settings/serializers/auth/sms.py:103 msgid "Parameters" msgstr "パラメータ" @@ -2566,7 +2566,7 @@ 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:147 ops/models/job.py:235 #: ops/models/playbook.py:30 terminal/models/session/sharing.py:25 msgid "Creator" msgstr "作成者" @@ -2735,7 +2735,7 @@ 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 "ユーザーが無効、無効、または期限切れです" @@ -4157,7 +4157,7 @@ msgstr "VCS" msgid "Adhoc" msgstr "コマンド#コマンド#" -#: ops/const.py:39 ops/models/job.py:143 +#: ops/const.py:39 ops/models/job.py:145 msgid "Playbook" msgstr "Playbook" @@ -4242,11 +4242,11 @@ msgstr "定期的または定期的に設定を行う必要があります" msgid "Pattern" msgstr "パターン" -#: ops/models/adhoc.py:23 ops/models/job.py:140 +#: ops/models/adhoc.py:23 ops/models/job.py:142 msgid "Module" msgstr "モジュール" -#: ops/models/adhoc.py:24 ops/models/celery.py:81 ops/models/job.py:138 +#: ops/models/adhoc.py:24 ops/models/celery.py:81 ops/models/job.py:140 #: terminal/models/component/task.py:14 msgid "Args" msgstr "アルグ" @@ -4265,12 +4265,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:233 #: 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:234 msgid "Summary" msgstr "概要" @@ -4303,43 +4303,43 @@ msgstr "発売日" msgid "Celery Task Execution" msgstr "Celery タスク実行" -#: ops/models/job.py:141 +#: ops/models/job.py:143 msgid "Chdir" msgstr "実行ディレクトリ" -#: ops/models/job.py:142 +#: ops/models/job.py:144 msgid "Timeout (Seconds)" msgstr "タイムアウト(秒)" -#: ops/models/job.py:147 +#: ops/models/job.py:149 msgid "Use Parameter Define" msgstr "パラメータ定義を使用する" -#: ops/models/job.py:148 +#: ops/models/job.py:150 msgid "Parameters define" msgstr "パラメータ定義" -#: ops/models/job.py:149 +#: ops/models/job.py:151 msgid "Runas" msgstr "ユーザーとして実行" -#: ops/models/job.py:151 +#: ops/models/job.py:153 msgid "Runas policy" msgstr "ユーザー ポリシー" -#: ops/models/job.py:215 +#: ops/models/job.py:217 msgid "Job" msgstr "ジョブ#ジョブ#" -#: ops/models/job.py:238 +#: ops/models/job.py:240 msgid "Material" msgstr "Material" -#: ops/models/job.py:240 +#: ops/models/job.py:242 msgid "Material Type" msgstr "Material を選択してオプションを設定します。" -#: ops/models/job.py:557 +#: ops/models/job.py:559 msgid "Job Execution" msgstr "ジョブ実行" @@ -7391,6 +7391,18 @@ msgstr "スーパー管理者" msgid "Super admin and org admin" msgstr "スーパーadminとorg admin" +#: tickets/const.py:62 +msgid "All assets" +msgstr "すべての資産" + +#: tickets/const.py:63 +msgid "Permed assets" +msgstr "許可された資産" + +#: tickets/const.py:64 +msgid "Permed valid assets" +msgstr "有効な許可を受けた資産" + #: tickets/errors.py:9 msgid "Ticket already closed" msgstr "チケットはすでに閉じています" @@ -8520,7 +8532,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 b1ddceb46..d860b75f5 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:2d6388bc60eeeb67f9bc5deaf8aec65a6027bfebad2fb994104841775cdb912d -size 140312 +oid sha256:82a37a09d6142219f93f871746f9bc036bff1df07d10f273f8ea8b26c5dbd63b +size 140456 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 15809ca09..93e984fb7 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-24 19:44+0800\n" +"POT-Creation-Date: 2024-01-25 15:38+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -364,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:86 ops/models/job.py:235 +#: ops/models/base.py:55 ops/models/celery.py:86 ops/models/job.py:237 #: ops/templates/ops/celery_task_log.html:75 #: perms/models/asset_permission.py:78 #: settings/templates/ldap/_msg_import_ldap_user.html:5 @@ -475,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:87 ops/models/job.py:236 +#: ops/models/celery.py:87 ops/models/job.py:238 #: 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:229 #: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:140 #: terminal/models/component/status.py:30 #: terminal/models/virtualapp/virtualapp.py:99 @@ -608,7 +608,7 @@ 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:80 ops/models/job.py:136 ops/models/playbook.py:28 +#: ops/models/celery.py:80 ops/models/job.py:138 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 @@ -761,7 +761,7 @@ 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:146 #: 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 @@ -798,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:148 ops/serializers/job.py:19 #: terminal/templates/terminal/_msg_command_execute_alert.html:16 msgid "Assets" msgstr "资产" @@ -929,7 +929,7 @@ 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:154 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 @@ -1324,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 "不能直接创建资产, 你应该创建主机或其他资产" @@ -1627,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:236 users/models/user.py:1042 msgid "Date created" msgstr "创建日期" @@ -1796,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:232 #: settings/serializers/auth/sms.py:103 msgid "Parameters" msgstr "参数" @@ -2549,7 +2549,7 @@ 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:147 ops/models/job.py:235 #: ops/models/playbook.py:30 terminal/models/session/sharing.py:25 msgid "Creator" msgstr "创建者" @@ -2714,7 +2714,7 @@ 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 "用户无效,已禁用或已过期" @@ -4106,7 +4106,7 @@ msgstr "VCS" msgid "Adhoc" msgstr "命令" -#: ops/const.py:39 ops/models/job.py:143 +#: ops/const.py:39 ops/models/job.py:145 msgid "Playbook" msgstr "Playbook" @@ -4191,11 +4191,11 @@ msgstr "需要周期或定期设置" msgid "Pattern" msgstr "模式" -#: ops/models/adhoc.py:23 ops/models/job.py:140 +#: ops/models/adhoc.py:23 ops/models/job.py:142 msgid "Module" msgstr "模块" -#: ops/models/adhoc.py:24 ops/models/celery.py:81 ops/models/job.py:138 +#: ops/models/adhoc.py:24 ops/models/celery.py:81 ops/models/job.py:140 #: terminal/models/component/task.py:14 msgid "Args" msgstr "参数" @@ -4214,12 +4214,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:233 #: 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:234 msgid "Summary" msgstr "汇总" @@ -4252,43 +4252,43 @@ msgstr "发布日期" msgid "Celery Task Execution" msgstr "Celery 任务执行" -#: ops/models/job.py:141 +#: ops/models/job.py:143 msgid "Chdir" msgstr "运行目录" -#: ops/models/job.py:142 +#: ops/models/job.py:144 msgid "Timeout (Seconds)" msgstr "超时时间 (秒)" -#: ops/models/job.py:147 +#: ops/models/job.py:149 msgid "Use Parameter Define" msgstr "使用参数定义" -#: ops/models/job.py:148 +#: ops/models/job.py:150 msgid "Parameters define" msgstr "参数定义" -#: ops/models/job.py:149 +#: ops/models/job.py:151 msgid "Runas" msgstr "运行用户" -#: ops/models/job.py:151 +#: ops/models/job.py:153 msgid "Runas policy" msgstr "用户策略" -#: ops/models/job.py:215 +#: ops/models/job.py:217 msgid "Job" msgstr "作业" -#: ops/models/job.py:238 +#: ops/models/job.py:240 msgid "Material" msgstr "Material" -#: ops/models/job.py:240 +#: ops/models/job.py:242 msgid "Material Type" msgstr "Material 类型" -#: ops/models/job.py:557 +#: ops/models/job.py:559 msgid "Job Execution" msgstr "作业执行" @@ -7287,6 +7287,18 @@ msgstr "超级管理员" msgid "Super admin and org admin" msgstr "组织管理员或超级管理员" +#: tickets/const.py:62 +msgid "All assets" +msgstr "所有资产" + +#: tickets/const.py:63 +msgid "Permed assets" +msgstr "授权的资产" + +#: tickets/const.py:64 +msgid "Permed valid assets" +msgstr "有效授权的资产" + #: tickets/errors.py:9 msgid "Ticket already closed" msgstr "工单已经关闭" @@ -8396,7 +8408,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/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 cbcecc99d..1fc4e86bf 100644 --- a/apps/perms/utils/user_perm.py +++ b/apps/perms/utils/user_perm.py @@ -29,14 +29,19 @@ class AssetPermissionPermAssetUtil: # 比原来的查到所有 asset id 再搜索块很多,因为当资产量大的时候,搜索会很慢 return (node_assets | direct_assets).order_by().distinct() - @timeit - def get_perm_nodes_assets(self): - """ 获取所有授权节点下的资产 """ + 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') + 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 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/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'), From 78d0e3f485e80607943cbab66cff35c0f68842f1 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Mon, 29 Jan 2024 11:12:45 +0800 Subject: [PATCH 25/69] =?UTF-8?q?perf:=20=E4=BD=BF=E7=94=A8winrm=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E6=89=A7=E8=A1=8C=E5=BF=AB=E6=8D=B7=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ops/models/job.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/ops/models/job.py b/apps/ops/models/job.py index 9fcc079ca..3ce83c5cd 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'], } if self.module not in protocol_supported_modules_mapping.get(protocol.name, []): From 9cc048267b4dd0c9d9582bfd392ac55ca9a08a90 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Mon, 29 Jan 2024 14:40:09 +0800 Subject: [PATCH 26/69] =?UTF-8?q?feat:=20=E6=89=B9=E9=87=8F=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E8=B4=A6=E5=8F=B7=E5=8F=AF=E8=BF=9E=E6=8E=A5=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/accounts/api/account/task.py | 45 ++++++++++++-------- apps/accounts/serializers/account/account.py | 4 +- 2 files changed, 31 insertions(+), 18 deletions(-) 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/serializers/account/account.py b/apps/accounts/serializers/account/account.py index 197c64c7d..ec3f8f87b 100644 --- a/apps/accounts/serializers/account/account.py +++ b/apps/accounts/serializers/account/account.py @@ -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 ) From 8c7ba4a4976b6e9affc06a922305f0d8adde002c Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Mon, 29 Jan 2024 13:51:46 +0800 Subject: [PATCH 27/69] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=B7=A5?= =?UTF-8?q?=E5=8D=95=E5=AE=A1=E6=89=B9=E6=97=B6=E9=97=B4=E4=B8=8D=E5=87=86?= =?UTF-8?q?=E7=A1=AE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/tickets/models/ticket/general.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 279109c9a6a1d021115563e478bea9bbfc17a051 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Tue, 30 Jan 2024 11:09:38 +0800 Subject: [PATCH 28/69] =?UTF-8?q?perf:=20=E4=BD=BF=E7=94=A8winrm=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E6=89=B9=E9=87=8F=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ops/models/job.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ops/models/job.py b/apps/ops/models/job.py index 3ce83c5cd..04c7fa519 100644 --- a/apps/ops/models/job.py +++ b/apps/ops/models/job.py @@ -67,7 +67,7 @@ class JMSPermedInventory(JMSInventory): 'postgresql': ['postgresql'], 'sqlserver': ['sqlserver'], 'ssh': ['shell', 'python', 'win_shell', 'raw'], - 'winrm': ['win_shell'], + 'winrm': ['win_shell', 'shell'], } if self.module not in protocol_supported_modules_mapping.get(protocol.name, []): From 8cb74976e191264a2d9bd97680ba065436b1b86b Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Wed, 31 Jan 2024 17:17:34 +0800 Subject: [PATCH 29/69] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=94=A8?= =?UTF-8?q?=E6=88=B7session=20=E4=BC=9A=E8=AF=9D=E8=BF=87=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/audits/api.py | 4 +- apps/audits/filters.py | 11 ++--- apps/audits/models.py | 7 ++-- apps/authentication/forms.py | 2 +- apps/authentication/middleware.py | 16 -------- apps/authentication/signal_handlers.py | 3 -- apps/common/sessions/__init__.py | 0 apps/common/sessions/cache.py | 56 ++++++++++++++++++++++++++ apps/jumpserver/conf.py | 1 - apps/jumpserver/middleware.py | 5 --- apps/jumpserver/settings/base.py | 6 +-- apps/notifications/ws.py | 46 +++++++++++++++++---- config_example.yml | 2 +- 13 files changed, 107 insertions(+), 52 deletions(-) create mode 100644 apps/common/sessions/__init__.py create mode 100644 apps/common/sessions/cache.py diff --git a/apps/audits/api.py b/apps/audits/api.py index 209bc30fd..5a665777b 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 @@ -289,8 +290,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..078e68c2c 100644 --- a/apps/audits/filters.py +++ b/apps/audits/filters.py @@ -1,10 +1,9 @@ -from django.core.cache import cache 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 @@ -41,13 +40,11 @@ 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: 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/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/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/jumpserver/conf.py b/apps/jumpserver/conf.py index d2f99e85f..9f869ace6 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, 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/settings/base.py b/apps/jumpserver/settings/base.py index 10188a1a7..f05293155 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 diff --git a/apps/notifications/ws.py b/apps/notifications/ws.py index 019b0b409..b172c4ed4 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 = 3 + 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/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 From f9f1d9667412b194da4498b23732adcc95bf4b60 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Fri, 2 Feb 2024 14:54:19 +0800 Subject: [PATCH 30/69] =?UTF-8?q?fix:=20=E8=B5=84=E4=BA=A7=E8=BF=87?= =?UTF-8?q?=E6=9C=9F=E6=B6=88=E6=81=AF=E6=8F=90=E7=A4=BA=E5=8F=91=E9=80=81?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/perms/notifications.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/perms/notifications.py b/apps/perms/notifications.py index 5c82c2589..f168a0517 100644 --- a/apps/perms/notifications.py +++ b/apps/perms/notifications.py @@ -9,7 +9,7 @@ class PermedAssetsWillExpireUserMsg(UserMessage): def __init__(self, user, assets, day_count=0): super().__init__(user) self.assets = assets - self.day_count = _('today') if day_count == 0 else day_count + _('day') + self.day_count = _('today') if day_count == 0 else str(day_count) + _('day') def get_html_msg(self) -> dict: subject = _("You permed assets is about to expire") @@ -41,7 +41,7 @@ class AssetPermsWillExpireForOrgAdminMsg(UserMessage): super().__init__(user) self.perms = perms self.org = org - self.day_count = _('today') if day_count == 0 else day_count + _('day') + self.day_count = _('today') if day_count == 0 else str(day_count) + _('day') def get_items_with_url(self): items_with_url = [] From 973df0360c53b942c8e51dca78079411e3ee4dd6 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Fri, 2 Feb 2024 10:40:42 +0800 Subject: [PATCH 31/69] =?UTF-8?q?fix:=20=E6=8E=A7=E5=88=B6=E5=8F=B0-?= =?UTF-8?q?=E4=BB=AA=E8=A1=A8=E7=9B=98=E4=BC=9A=E8=AF=9D=E7=94=A8=E6=88=B7?= =?UTF-8?q?=EF=BC=8C=E8=B5=84=E4=BA=A7=E6=8E=92=E5=90=8D=E4=B8=8D=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/jumpserver/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/jumpserver/api.py b/apps/jumpserver/api.py index 5b672d5f9..cfa6b771d 100644 --- a/apps/jumpserver/api.py +++ b/apps/jumpserver/api.py @@ -182,14 +182,14 @@ class DatesLoginMetricMixin: def get_dates_login_times_assets(self): assets = self.sessions_queryset.values("asset") \ - .annotate(total=Count("asset", distinct=True)) \ + .annotate(total=Count("asset")) \ .annotate(last=Cast(Max("date_start"), output_field=CharField())) \ .order_by("-total") return list(assets[:10]) def get_dates_login_times_users(self): users = self.sessions_queryset.values("user_id") \ - .annotate(total=Count("user_id", distinct=True)) \ + .annotate(total=Count("user_id")) \ .annotate(user=Max('user')) \ .annotate(last=Cast(Max("date_start"), output_field=CharField())) \ .order_by("-total") From f606dd8920b6247111281c08d99008608b30fea6 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Fri, 2 Feb 2024 16:52:57 +0800 Subject: [PATCH 32/69] =?UTF-8?q?perf:=20=E5=A2=9E=E5=8A=A0=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E7=94=B5=E8=AF=9D=E5=8C=BA=E5=8F=B7=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/const/choices.py | 14 +++++ apps/settings/api/public.py | 4 +- apps/settings/serializers/public.py | 1 + .../templates/users/forgot_password.html | 60 ++++++++++++++++--- apps/users/views/profile/reset.py | 3 +- 5 files changed, 72 insertions(+), 10 deletions(-) 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/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/public.py b/apps/settings/serializers/public.py index 6e5a74c8e..278764c65 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): 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) From be80663436dae6fd54b4f797ec68918495c1551c Mon Sep 17 00:00:00 2001 From: ibuler Date: Sun, 4 Feb 2024 17:21:09 +0800 Subject: [PATCH 36/69] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=98=BE=E7=A4=BA=E9=81=BF=E5=85=8D=E5=A4=AA=E9=95=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/perms/utils/user_perm_tree.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/perms/utils/user_perm_tree.py b/apps/perms/utils/user_perm_tree.py index 4514c78ca..17248adc0 100644 --- a/apps/perms/utils/user_perm_tree.py +++ b/apps/perms/utils/user_perm_tree.py @@ -200,7 +200,13 @@ class UserPermTreeExpireUtil(_UserPermTreeCacheMixin): 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) From d1f31f078b9edb5e6be487e2761af78b198ec5b8 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Wed, 31 Jan 2024 13:48:52 +0800 Subject: [PATCH 37/69] =?UTF-8?q?perf:=20=E8=B4=A6=E5=8F=B7=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=89=B9=E9=87=8F=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/accounts/serializers/account/account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/accounts/serializers/account/account.py b/apps/accounts/serializers/account/account.py index ec3f8f87b..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) From aa69353474856a9428f8356c88f70cb2980e97b3 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Wed, 31 Jan 2024 15:06:40 +0800 Subject: [PATCH 38/69] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81=E8=BF=9C?= =?UTF-8?q?=E7=A8=8B=E5=BA=94=E7=94=A8=E6=8F=8F=E8=BF=B0=E6=96=87=E6=A1=88?= =?UTF-8?q?=E7=9A=84=E5=9B=BD=E9=99=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api/applet/applet.py | 51 ++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/apps/terminal/api/applet/applet.py b/apps/terminal/api/applet/applet.py index 7f68d67d3..f85e5f572 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,52 @@ 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 = get_language() + with open(os.path.join(obj.path, 'manifest.yml'), encoding='utf8') as f: + manifest = yaml_load_with_i18n(f, lang) + return manifest + + def trans_queryset(self, queryset): + for obj in queryset: + self.trans_object(obj) + return queryset + + def trans_object(self, obj): + manifest = self.read_manifest_with_i18n(obj) + obj.display_name = manifest.get('display_name', obj.display_name) + obj.comment = manifest.get('comment', obj.comment) + 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: From 1051c6af04e0876314a9e3a03494f9cb25560496 Mon Sep 17 00:00:00 2001 From: Bai Date: Mon, 5 Feb 2024 16:04:48 +0800 Subject: [PATCH 39/69] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=99=BB=E5=BD=95=E5=90=8E=E4=BB=AA=E8=A1=A8=E7=9B=98?= =?UTF-8?q?=E6=98=BE=E7=A4=BA403=E7=9A=84=E9=97=AE=E9=A2=98(=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=9C=A8=E9=9D=9EDefault=E7=BB=84=E7=BB=87=E4=B8=8B?= =?UTF-8?q?=E6=98=AF=E7=BB=84=E7=BB=87=E7=AE=A1=E7=90=86=E5=91=98=E6=9D=83?= =?UTF-8?q?=E9=99=90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/orgs/models.py | 3 +++ apps/orgs/utils.py | 35 +++++++++++++++++++++++++++-------- 2 files changed, 30 insertions(+), 8 deletions(-) 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/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 From eaca296bd0cc1c220ad42c4a6615f0b10cdc1182 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Mon, 5 Feb 2024 16:36:03 +0800 Subject: [PATCH 40/69] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81=E6=94=B9?= =?UTF-8?q?=E5=AF=86=E6=97=A5=E5=BF=97=E8=AE=B0=E5=BD=95=E4=BF=9D=E7=95=99?= =?UTF-8?q?=E5=A4=A9=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/audits/tasks.py | 10 +- apps/jumpserver/conf.py | 1 + apps/jumpserver/settings/custom.py | 2 +- apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/ja/LC_MESSAGES/django.po | 220 +++++++++++++------------- apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 220 +++++++++++++------------- apps/settings/serializers/cleaning.py | 4 + 8 files changed, 243 insertions(+), 222 deletions(-) diff --git a/apps/audits/tasks.py b/apps/audits/tasks.py index 65243a966..667fc5c5f 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,13 @@ 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() + + def clean_activity_log_period(): now = timezone.now() days = get_log_keep_day('ACTIVITY_LOG_KEEP_DAYS') @@ -109,6 +116,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/jumpserver/conf.py b/apps/jumpserver/conf.py index 9f869ace6..06e306209 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -563,6 +563,7 @@ 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, diff --git a/apps/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index ed5cc61a9..38ee1d33d 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 diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index fcb22bbe4..7c5720ca9 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:6a7f3882356366531dca8e6459bc4bc50dcbd1e0cf0c379ac93ee3bd1b679d3c -size 171329 +oid sha256:2fd8cc044dd42750cc1c96a051cdd767172d2e1c6026c65a6db44f4eac21426a +size 171418 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 534a78731..23f62fd72 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-25 15:38+0800\n" +"POT-Creation-Date: 2024-02-05 16:29+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -208,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 "メール" @@ -365,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:86 ops/models/job.py:237 +#: 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 @@ -476,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:87 ops/models/job.py:238 +#: 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:229 +#: 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 @@ -609,7 +609,7 @@ 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:80 ops/models/job.py:138 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 @@ -763,7 +763,7 @@ 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:146 +#: 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 @@ -800,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:148 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 "資産" @@ -931,7 +931,7 @@ 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:154 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 @@ -1076,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 "拒否" @@ -1118,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 "アクティブ" @@ -1176,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 "コマンドの確認" @@ -1197,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 "ログイン確認" @@ -1205,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 "ログイン資産の確認" @@ -1470,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 "一般" @@ -1635,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:236 users/models/user.py:1042 +#: ops/models/job.py:235 users/models/user.py:1042 msgid "Date created" msgstr "作成された日付" @@ -1804,7 +1804,7 @@ msgstr "証明書チェックを無視" msgid "Proxy" msgstr "プロキシー" -#: assets/models/automations/base.py:22 ops/models/job.py:232 +#: assets/models/automations/base.py:22 ops/models/job.py:231 #: settings/serializers/auth/sms.py:103 msgid "Parameters" msgstr "パラメータ" @@ -2405,14 +2405,14 @@ 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 "閉じる" @@ -2557,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:147 ops/models/job.py:235 +#: 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 "作成者" @@ -2636,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 @@ -2653,11 +2653,11 @@ msgstr "仮パスワード" msgid "Passkey" msgstr "Passkey" -#: audits/tasks.py:101 +#: audits/tasks.py:108 msgid "Clean audits session task log" msgstr "資産監査セッションタスクログのクリーンアップ" -#: audits/tasks.py:114 +#: audits/tasks.py:122 msgid "Upload FTP file to external storage" msgstr "外部ストレージへのFTPファイルのアップロード" @@ -2705,11 +2705,11 @@ 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 +#: 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 "ユーザーにマッチしなかった" @@ -2723,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" @@ -2928,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はバインドされていません" @@ -3040,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 "メッセージ" @@ -3239,7 +3239,7 @@ 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 "{} 空にしてはならない" @@ -3379,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 "コードの確認" @@ -3427,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 "キャンセル" @@ -3454,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 "次へ" @@ -3520,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エラー" @@ -3534,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をバインドしてください" @@ -3654,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 "未定" @@ -4157,7 +4157,7 @@ msgstr "VCS" msgid "Adhoc" msgstr "コマンド#コマンド#" -#: ops/const.py:39 ops/models/job.py:145 +#: ops/const.py:39 ops/models/job.py:144 msgid "Playbook" msgstr "Playbook" @@ -4242,11 +4242,11 @@ msgstr "定期的または定期的に設定を行う必要があります" msgid "Pattern" msgstr "パターン" -#: ops/models/adhoc.py:23 ops/models/job.py:142 +#: ops/models/adhoc.py:23 ops/models/job.py:141 msgid "Module" msgstr "モジュール" -#: ops/models/adhoc.py:24 ops/models/celery.py:81 ops/models/job.py:140 +#: ops/models/adhoc.py:24 ops/models/celery.py:81 ops/models/job.py:139 #: terminal/models/component/task.py:14 msgid "Args" msgstr "アルグ" @@ -4265,12 +4265,12 @@ msgstr "最後の実行" msgid "Date last run" msgstr "最終実行日" -#: ops/models/base.py:51 ops/models/job.py:233 +#: 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:234 +#: ops/models/base.py:52 ops/models/job.py:233 msgid "Summary" msgstr "概要" @@ -4291,7 +4291,7 @@ msgid "Kwargs" msgstr "クワーグ" #: ops/models/celery.py:84 terminal/models/session/sharing.py:128 -#: tickets/const.py:25 +#: tickets/const.py:26 msgid "Finished" msgstr "終了" @@ -4303,43 +4303,43 @@ msgstr "発売日" msgid "Celery Task Execution" msgstr "Celery タスク実行" -#: ops/models/job.py:143 +#: ops/models/job.py:142 msgid "Chdir" msgstr "実行ディレクトリ" -#: ops/models/job.py:144 +#: ops/models/job.py:143 msgid "Timeout (Seconds)" msgstr "タイムアウト(秒)" -#: ops/models/job.py:149 +#: ops/models/job.py:148 msgid "Use Parameter Define" msgstr "パラメータ定義を使用する" -#: ops/models/job.py:150 +#: ops/models/job.py:149 msgid "Parameters define" msgstr "パラメータ定義" -#: ops/models/job.py:151 +#: ops/models/job.py:150 msgid "Runas" msgstr "ユーザーとして実行" -#: ops/models/job.py:153 +#: ops/models/job.py:152 msgid "Runas policy" msgstr "ユーザー ポリシー" -#: ops/models/job.py:217 +#: ops/models/job.py:216 msgid "Job" msgstr "ジョブ#ジョブ#" -#: ops/models/job.py:240 +#: ops/models/job.py:239 msgid "Material" msgstr "Material" -#: ops/models/job.py:242 +#: ops/models/job.py:241 msgid "Material Type" msgstr "Material を選択してオプションを設定します。" -#: ops/models/job.py:559 +#: ops/models/job.py:558 msgid "Job Execution" msgstr "ジョブ実行" @@ -5509,26 +5509,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." @@ -6365,12 +6369,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 "確認コードが送信されました" @@ -6424,13 +6428,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 "これはエンタープライズ版アプレットです" @@ -7343,63 +7347,63 @@ 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:62 +#: tickets/const.py:63 msgid "All assets" msgstr "すべての資産" -#: tickets/const.py:63 +#: tickets/const.py:64 msgid "Permed assets" msgstr "許可された資産" -#: tickets/const.py:64 +#: tickets/const.py:65 msgid "Permed valid assets" msgstr "有効な許可を受けた資産" @@ -7913,7 +7917,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 "パスワードのリセット成功" @@ -8179,28 +8183,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 "送信" @@ -8294,7 +8298,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)." @@ -8322,32 +8326,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無効化成功、ログインページを返す" @@ -8355,7 +8359,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: {}" @@ -8363,23 +8367,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 "パスワードの成功をリセットし、ログインページに戻る" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index d860b75f5..fc8da2aa5 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:82a37a09d6142219f93f871746f9bc036bff1df07d10f273f8ea8b26c5dbd63b -size 140456 +oid sha256:68cbef2326c0b3abe8d8358eba96400ead043348c80ab9ece490c18610bf6b6c +size 140527 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 93e984fb7..4d4fa5ca9 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-25 15:38+0800\n" +"POT-Creation-Date: 2024-02-05 16:29+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -207,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 "邮箱" @@ -364,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:86 ops/models/job.py:237 +#: 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 @@ -475,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:87 ops/models/job.py:238 +#: 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:229 +#: 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 @@ -608,7 +608,7 @@ 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:80 ops/models/job.py:138 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 @@ -761,7 +761,7 @@ 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:146 +#: 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 @@ -798,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:148 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 "资产" @@ -929,7 +929,7 @@ 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:154 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 @@ -1072,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 "拒绝" @@ -1114,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 "激活中" @@ -1172,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 "命令复核" @@ -1193,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 "登录复核" @@ -1201,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 "登录资产复核" @@ -1462,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 "一般" @@ -1627,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:236 users/models/user.py:1042 +#: ops/models/job.py:235 users/models/user.py:1042 msgid "Date created" msgstr "创建日期" @@ -1796,7 +1796,7 @@ msgstr "忽略证书校验" msgid "Proxy" msgstr "代理" -#: assets/models/automations/base.py:22 ops/models/job.py:232 +#: assets/models/automations/base.py:22 ops/models/job.py:231 #: settings/serializers/auth/sms.py:103 msgid "Parameters" msgstr "参数" @@ -2388,14 +2388,14 @@ 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 "关闭" @@ -2540,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:147 ops/models/job.py:235 +#: 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 "创建者" @@ -2619,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 @@ -2636,11 +2636,11 @@ msgstr "临时密码" msgid "Passkey" msgstr "Passkey" -#: audits/tasks.py:101 +#: audits/tasks.py:108 msgid "Clean audits session task log" msgstr "清理资产审计会话任务日志" -#: audits/tasks.py:114 +#: audits/tasks.py:122 msgid "Upload FTP file to external storage" msgstr "上传 FTP 文件到外部存储" @@ -2686,11 +2686,11 @@ 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 +#: 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 "没有匹配到用户" @@ -2702,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" @@ -2900,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 "钉钉没有绑定" @@ -3010,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 "短信" @@ -3207,7 +3207,7 @@ 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 "{} 不能为空" @@ -3343,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 "验证码" @@ -3387,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 "取消" @@ -3412,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 "下一步" @@ -3476,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 "钉钉错误" @@ -3490,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 "请使用密码登录,然后绑定钉钉" @@ -3610,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 "待定的" @@ -4106,7 +4106,7 @@ msgstr "VCS" msgid "Adhoc" msgstr "命令" -#: ops/const.py:39 ops/models/job.py:145 +#: ops/const.py:39 ops/models/job.py:144 msgid "Playbook" msgstr "Playbook" @@ -4191,11 +4191,11 @@ msgstr "需要周期或定期设置" msgid "Pattern" msgstr "模式" -#: ops/models/adhoc.py:23 ops/models/job.py:142 +#: ops/models/adhoc.py:23 ops/models/job.py:141 msgid "Module" msgstr "模块" -#: ops/models/adhoc.py:24 ops/models/celery.py:81 ops/models/job.py:140 +#: ops/models/adhoc.py:24 ops/models/celery.py:81 ops/models/job.py:139 #: terminal/models/component/task.py:14 msgid "Args" msgstr "参数" @@ -4214,12 +4214,12 @@ msgstr "最后执行" msgid "Date last run" msgstr "最后运行日期" -#: ops/models/base.py:51 ops/models/job.py:233 +#: 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:234 +#: ops/models/base.py:52 ops/models/job.py:233 msgid "Summary" msgstr "汇总" @@ -4240,7 +4240,7 @@ msgid "Kwargs" msgstr "其它参数" #: ops/models/celery.py:84 terminal/models/session/sharing.py:128 -#: tickets/const.py:25 +#: tickets/const.py:26 msgid "Finished" msgstr "结束" @@ -4252,43 +4252,43 @@ msgstr "发布日期" msgid "Celery Task Execution" msgstr "Celery 任务执行" -#: ops/models/job.py:143 +#: ops/models/job.py:142 msgid "Chdir" msgstr "运行目录" -#: ops/models/job.py:144 +#: ops/models/job.py:143 msgid "Timeout (Seconds)" msgstr "超时时间 (秒)" -#: ops/models/job.py:149 +#: ops/models/job.py:148 msgid "Use Parameter Define" msgstr "使用参数定义" -#: ops/models/job.py:150 +#: ops/models/job.py:149 msgid "Parameters define" msgstr "参数定义" -#: ops/models/job.py:151 +#: ops/models/job.py:150 msgid "Runas" msgstr "运行用户" -#: ops/models/job.py:153 +#: ops/models/job.py:152 msgid "Runas policy" msgstr "用户策略" -#: ops/models/job.py:217 +#: ops/models/job.py:216 msgid "Job" msgstr "作业" -#: ops/models/job.py:240 +#: ops/models/job.py:239 msgid "Material" msgstr "Material" -#: ops/models/job.py:242 +#: ops/models/job.py:241 msgid "Material Type" msgstr "Material 类型" -#: ops/models/job.py:559 +#: ops/models/job.py:558 msgid "Job Execution" msgstr "作业执行" @@ -5451,26 +5451,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." @@ -6276,12 +6280,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 "验证码已发送" @@ -6330,13 +6334,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 "企业版远程应用,在社区版中不能使用" @@ -7239,63 +7243,63 @@ 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:62 +#: tickets/const.py:63 msgid "All assets" msgstr "所有资产" -#: tickets/const.py:63 +#: tickets/const.py:64 msgid "Permed assets" msgstr "授权的资产" -#: tickets/const.py:64 +#: tickets/const.py:65 msgid "Permed valid assets" msgstr "有效授权的资产" @@ -7806,7 +7810,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 "重置密码成功" @@ -8065,28 +8069,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 "提交" @@ -8176,7 +8180,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)." @@ -8201,31 +8205,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) 禁用成功,返回登录页面" @@ -8233,29 +8237,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 "重置密码成功,返回到登录页面" 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)"), From 2062778ab8bb7d9feeed040e77f5952195a295aa Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Tue, 6 Feb 2024 11:33:04 +0800 Subject: [PATCH 41/69] =?UTF-8?q?fix:=20=E8=B5=84=E4=BA=A7=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E6=9C=AA=E5=8F=91=E9=80=81=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/notifications.py | 10 +++++----- apps/authentication/api/connection_token.py | 2 +- apps/perms/utils/user_perm_tree.py | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) 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/authentication/api/connection_token.py b/apps/authentication/api/connection_token.py index b5bafac32..f76b6e037 100644 --- a/apps/authentication/api/connection_token.py +++ b/apps/authentication/api/connection_token.py @@ -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/perms/utils/user_perm_tree.py b/apps/perms/utils/user_perm_tree.py index 17248adc0..01090176e 100644 --- a/apps/perms/utils/user_perm_tree.py +++ b/apps/perms/utils/user_perm_tree.py @@ -194,6 +194,7 @@ 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: From 58d30e7f85ad09711dc6cca0b5ed8b202f9a7929 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Tue, 6 Feb 2024 18:28:31 +0800 Subject: [PATCH 42/69] =?UTF-8?q?perf:=20=E8=AE=B0=E5=BD=95=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E6=B4=BB=E5=8A=A8=E6=97=A5=E5=BF=97=20(#12523)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: 更新会话生命周期日志 * perf: 优化错误原因 * perf: 增加错误类型 --------- Co-authored-by: Eric --- apps/terminal/api/session/session.py | 22 ++- apps/terminal/serializers/session.py | 8 + apps/terminal/session_lifecycle.py | 176 ++++++++++++++++++ .../signal_handlers/session_sharing.py | 5 + 4 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 apps/terminal/session_lifecycle.py 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/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() From 6e506e3146df9eb695a48f0abac9edef7c185930 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Wed, 7 Feb 2024 15:57:36 +0800 Subject: [PATCH 43/69] =?UTF-8?q?fix:=20=E3=80=90=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E8=B6=85=E6=97=B6=E3=80=91=E4=BF=AE=E5=A4=8D=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=8F=90=E7=A4=BA=20<=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E8=B6=85=E6=97=B6=EF=BC=8C=E8=AF=B7=E9=87=8D=E6=96=B0=E7=99=BB?= =?UTF-8?q?=E5=BD=95>=20=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/templates/authentication/login.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/authentication/templates/authentication/login.html b/apps/authentication/templates/authentication/login.html index 4d7489034..22ec4f5fc 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, 10 * 1000); From d7b1903fb7c3968f4852e6e17bb5cc38d76bc9bb Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Mon, 19 Feb 2024 10:57:40 +0800 Subject: [PATCH 44/69] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E9=A1=B5=E9=9D=A2=E5=AE=9A=E6=9C=9F=20check=20?= =?UTF-8?q?=E7=9A=84=E6=97=B6=E9=97=B4=20(#12660)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/authentication/templates/authentication/login.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/authentication/templates/authentication/login.html b/apps/authentication/templates/authentication/login.html index 22ec4f5fc..ed70b30f7 100644 --- a/apps/authentication/templates/authentication/login.html +++ b/apps/authentication/templates/authentication/login.html @@ -415,7 +415,7 @@ flash_message: false, }) } - setInterval(checkHealth, 10 * 1000); + setInterval(checkHealth, 30 * 1000); From dce68cd011bcb74aab216a42c2f6081dbcd65bb3 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:48:31 +0800 Subject: [PATCH 45/69] =?UTF-8?q?perf:=20=E6=8E=88=E6=9D=83=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E4=B8=8D=E6=98=BE=E7=A4=BA=E7=BB=84=E4=BB=B6=E7=94=A8?= =?UTF-8?q?=E6=88=B7=20(#12664)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/assets/api/asset/permission.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From f592f19b087d99ce9729e220e99ec23ad096f71e Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Mon, 19 Feb 2024 17:32:32 +0800 Subject: [PATCH 46/69] =?UTF-8?q?perf:=20=E8=87=AA=E5=8A=A8=E5=8C=96?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=8C=89=E4=BC=98=E5=85=88=E7=BA=A7=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../automations/change_secret/custom/ssh/manifest.yml | 1 + .../change_secret/host/windows_rdp_verify/manifest.yml | 1 + .../push_account/host/windows_rdp_verify/manifest.yml | 1 + .../automations/verify_account/custom/rdp/manifest.yml | 1 + .../automations/verify_account/custom/ssh/manifest.yml | 1 + apps/assets/automations/__init__.py | 2 +- apps/assets/automations/methods.py | 4 ++++ apps/assets/automations/ping/custom/rdp/manifest.yml | 1 + apps/assets/automations/ping/custom/ssh/manifest.yml | 1 + apps/assets/const/types.py | 3 ++- 10 files changed, 14 insertions(+), 2 deletions(-) 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/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/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/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) From 135fb7c6f9c08add35cb03032fbb2a2f55a31d55 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Mon, 19 Feb 2024 14:47:32 +0800 Subject: [PATCH 47/69] =?UTF-8?q?perf:=20=E7=BB=88=E6=96=AD=E6=89=B9?= =?UTF-8?q?=E9=87=8F=E5=BF=AB=E6=8D=B7=E5=91=BD=E4=BB=A4=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E7=9A=84=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ops/ansible/callback.py | 14 ++++++++++++++ apps/ops/api/job.py | 13 ++++++++++++- apps/ops/models/job.py | 9 +++++++++ apps/ops/serializers/job.py | 7 +++++++ 4 files changed, 42 insertions(+), 1 deletion(-) 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/job.py b/apps/ops/api/job.py index eb908d04c..4c60956fd 100644 --- a/apps/ops/api/job.py +++ b/apps/ops/api/job.py @@ -16,7 +16,7 @@ from common.const.http import POST from common.permissions import IsValidUser 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 +187,17 @@ 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'] + instance = get_object_or_404(JobExecution, task_id=task_id, creator=request.user) + instance.stop() + return Response({'task_id': task_id}, status=200) + class JobAssetDetail(APIView): rbac_perms = { diff --git a/apps/ops/models/job.py b/apps/ops/models/job.py index 04c7fa519..f7831251b 100644 --- a/apps/ops/models/job.py +++ b/apps/ops/models/job.py @@ -554,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")) From c21ca70158c4c63c4b442a5259ba033713867a08 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Tue, 20 Feb 2024 18:42:11 +0800 Subject: [PATCH 48/69] =?UTF-8?q?perf:=20=E8=B4=A6=E5=8F=B7=E6=94=B6?= =?UTF-8?q?=E9=9B=86=E6=B7=BB=E5=8A=A0=E8=B5=84=E4=BA=A7=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E6=A8=A1=E7=B3=8A=E6=90=9C=E7=B4=A2=20(#12673)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/accounts/filters.py | 1 + 1 file changed, 1 insertion(+) 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): From ba127c506d69d5ee0e2ceb527535db4cc2dd56b9 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Mon, 19 Feb 2024 11:18:01 +0800 Subject: [PATCH 49/69] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=B7=A5?= =?UTF-8?q?=E5=8D=95=E9=93=BE=E6=8E=A5=E7=9B=B4=E6=8E=A5=E5=85=8D=E5=AF=86?= =?UTF-8?q?=E5=AE=A1=E6=89=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/jumpserver/conf.py | 1 + apps/jumpserver/settings/custom.py | 1 + apps/locale/ja/LC_MESSAGES/django.po | 100 ++++++++++++++------------- apps/locale/zh/LC_MESSAGES/django.po | 100 ++++++++++++++------------- apps/settings/serializers/feature.py | 1 + apps/settings/serializers/public.py | 1 + apps/tickets/notifications.py | 16 ++--- apps/tickets/views/approve.py | 17 ++++- 8 files changed, 128 insertions(+), 109 deletions(-) diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 06e306209..719bc3ae9 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -566,6 +566,7 @@ class Config(dict): 'PASSWORD_CHANGE_LOG_KEEP_DAYS': 999, 'TICKETS_ENABLED': True, + 'TICKETS_DIRECT_APPROVE': False, # 废弃的 'DEFAULT_ORG_SHOW_ALL_USERS': True, diff --git a/apps/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index 38ee1d33d..b564cba25 100644 --- a/apps/jumpserver/settings/custom.py +++ b/apps/jumpserver/settings/custom.py @@ -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 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 23f62fd72..e209dc2c6 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-02-05 16:29+0800\n" +"POT-Creation-Date: 2024-02-19 11:14+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -258,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 @@ -402,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:64 terminal/serializers/session.py:51 msgid "Is success" msgstr "成功は" @@ -767,7 +767,7 @@ msgstr "カテゴリ" #: 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 @@ -990,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 "成功" @@ -1675,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 "プロトコル" @@ -2371,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 "ダウンロード" @@ -2379,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" @@ -2418,8 +2418,8 @@ 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/virtualapp/provider.py:14 terminal/serializers/session.py:54 +#: terminal/serializers/session.py:68 msgid "Terminal" msgstr "ターミナル" @@ -2704,7 +2704,7 @@ msgstr "ACL アクションはレビューです" msgid "Current user not support mfa type: {}" msgstr "現在のユーザーはmfaタイプをサポートしていません: {}" -#: authentication/api/password.py:33 terminal/api/session/session.py:305 +#: authentication/api/password.py:33 terminal/api/session/session.py:325 #: users/views/profile/reset.py:63 msgid "User does not exist: {}" msgstr "ユーザーが存在しない: {}" @@ -4387,7 +4387,7 @@ msgstr "保存後に実行" msgid "Job type" msgstr "タスクの種類" -#: ops/serializers/job.py:65 terminal/serializers/session.py:53 +#: ops/serializers/job.py:65 terminal/serializers/session.py:55 msgid "Is finished" msgstr "終了しました" @@ -4525,7 +4525,7 @@ msgstr "グローバル組織を表示できます" msgid "Can view all joined org" msgstr "参加しているすべての組織を表示できます" -#: orgs/models.py:233 +#: orgs/models.py:236 msgid "Can not delete virtual org" msgstr "仮想組織を削除できませんでした" @@ -4610,7 +4610,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 "日" @@ -5603,39 +5603,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 @@ -5643,7 +5647,7 @@ msgstr "実行が許可されていないコマンド" msgid "Virtual app" msgstr "仮想アプリケーション" -#: settings/serializers/feature.py:140 +#: settings/serializers/feature.py:141 msgid "Enable virtual app" msgstr "仮想アプリケーションの有効化" @@ -6474,20 +6478,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 "ユーザーに権限がありません" @@ -6835,11 +6839,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 "間違った理由" @@ -7158,31 +7162,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 "ターミナルディスプレイ" @@ -7582,19 +7586,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 "チケットが処理済み- {} ({})" @@ -7660,7 +7664,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 "作業指示の承認" @@ -7668,26 +7672,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 "このユーザーはこの作業指示を承認する権限がありません" @@ -8536,7 +8540,7 @@ msgstr "そして" msgid "Or" msgstr "または" -#: xpack/plugins/cloud/manager.py:57 +#: xpack/plugins/cloud/manager.py:56 msgid "Account unavailable" msgstr "利用できないアカウント" diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 4d4fa5ca9..85a1458c6 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-02-05 16:29+0800\n" +"POT-Creation-Date: 2024-02-19 11:14+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -257,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 @@ -401,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:64 terminal/serializers/session.py:51 msgid "Is success" msgstr "是否成功" @@ -765,7 +765,7 @@ msgstr "类别" #: 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 @@ -987,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 "成功" @@ -1667,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 "协议" @@ -2354,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 "下载" @@ -2362,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" @@ -2401,8 +2401,8 @@ 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/virtualapp/provider.py:14 terminal/serializers/session.py:54 +#: terminal/serializers/session.py:68 msgid "Terminal" msgstr "终端" @@ -2685,7 +2685,7 @@ msgstr "ACL 动作是复核" msgid "Current user not support mfa type: {}" msgstr "当前用户不支持 MFA 类型: {}" -#: authentication/api/password.py:33 terminal/api/session/session.py:305 +#: authentication/api/password.py:33 terminal/api/session/session.py:325 #: users/views/profile/reset.py:63 msgid "User does not exist: {}" msgstr "用户不存在: {}" @@ -4336,7 +4336,7 @@ msgstr "保存后执行" msgid "Job type" msgstr "任务类型" -#: ops/serializers/job.py:65 terminal/serializers/session.py:53 +#: ops/serializers/job.py:65 terminal/serializers/session.py:55 msgid "Is finished" msgstr "是否完成" @@ -4473,7 +4473,7 @@ msgstr "可以查看全局组织" msgid "Can view all joined org" msgstr "可以查看所有加入的组织" -#: orgs/models.py:233 +#: orgs/models.py:236 msgid "Can not delete virtual org" msgstr "无法删除虚拟组织" @@ -4558,7 +4558,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 "天" @@ -5543,39 +5543,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 @@ -5583,7 +5587,7 @@ msgstr "不允许执行的命令" msgid "Virtual app" msgstr "虚拟应用" -#: settings/serializers/feature.py:140 +#: settings/serializers/feature.py:141 msgid "Enable virtual app" msgstr "启用虚拟应用" @@ -6380,20 +6384,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 "用户没有权限" @@ -6741,11 +6745,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 "错误原因" @@ -7057,31 +7061,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 "终端显示" @@ -7477,19 +7481,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 "你的工单已被处理, 处理人 - {} ({})" @@ -7555,7 +7559,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 "工单审批" @@ -7563,24 +7567,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 "此用户无权审批此工单" @@ -8412,7 +8416,7 @@ msgstr "与" msgid "Or" msgstr "或" -#: xpack/plugins/cloud/manager.py:57 +#: xpack/plugins/cloud/manager.py:56 msgid "Account unavailable" msgstr "账号无效" 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 278764c65..b4d66671e 100644 --- a/apps/settings/serializers/public.py +++ b/apps/settings/serializers/public.py @@ -51,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/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/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) From 753ab77c46046196c8046004885d0ed7b18a3735 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:51:06 +0800 Subject: [PATCH 50/69] =?UTF-8?q?perf:=20=E5=85=B3=E9=97=AD=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E7=AD=89=E5=BE=85ws=E7=9A=84=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E9=87=8D=E8=BF=9E=E6=97=B6=E9=97=B4=E6=94=B9=E4=B8=BA6?= =?UTF-8?q?=E7=A7=92=20(#12677)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/notifications/ws.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/notifications/ws.py b/apps/notifications/ws.py index b172c4ed4..653b068d4 100644 --- a/apps/notifications/ws.py +++ b/apps/notifications/ws.py @@ -83,7 +83,7 @@ class SiteMsgWebsocket(JsonWebsocketConsumer): not user_session_manager.check_active(self.session.session_key) def delay_delete_session(self): - timeout = 3 + timeout = 6 check_interval = 0.5 start_time = time.time() From bb6c6c8f6a536ffd0fd9c5ca57e3731cc6f8e4ea Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Thu, 22 Feb 2024 11:25:56 +0800 Subject: [PATCH 51/69] perf: jms-storage==0.0.56 --- poetry.lock | 18 ++++++------------ pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/poetry.lock b/poetry.lock index 503a06cde..d8318a563 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.6.1 and should not be changed by hand. [[package]] name = "adal" @@ -2836,14 +2836,8 @@ files = [ [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" @@ -3585,12 +3579,12 @@ reference = "tsinghua" [[package]] name = "jms-storage" -version = "0.0.55" +version = "0.0.56" description = "Jumpserver storage python sdk tools" optional = false python-versions = "*" files = [ - {file = "jms-storage-0.0.55.tar.gz", hash = "sha256:cab3ac01b9733dd30101b59dd21de104543355c010ca0024cfaed3069e392cfa"}, + {file = "jms-storage-0.0.56.tar.gz", hash = "sha256:8ee4b121f695b8897da66cb7b3fca842d525479e7fd272db2bbbc133ea796543"}, ] [package.dependencies] @@ -7869,4 +7863,4 @@ reference = "tsinghua" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "3f228326a11742303de60a3b1bb8f748b6efc5a3dae1aa200e8a5cc6c9df9c0a" +content-hash = "3f4c08616b1a3ede830282eae1c3f456581e4b926ad134ae3d5af0a807d29c02" diff --git a/pyproject.toml b/pyproject.toml index 21f587678..032043057 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.55" +jms-storage = "0.0.56" simplejson = "3.19.1" six = "1.16.0" sshtunnel = "0.4.0" From d4721e90d5bf24bef155b4ec719f7885627190f4 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Thu, 22 Feb 2024 11:26:12 +0800 Subject: [PATCH 52/69] =?UTF-8?q?fix:=20LDAP=E7=94=A8=E6=88=B7=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E4=BC=9A=E8=B6=85=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/settings/api/ldap.py | 66 +++------------------------------- apps/settings/urls/api_urls.py | 1 - apps/settings/ws.py | 64 +++++++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 66 deletions(-) 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/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 From d4e53be7cea4e4af6dadb114e417cdaafe7cdee6 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:47:26 +0800 Subject: [PATCH 53/69] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9core=20celery?= =?UTF-8?q?=20=E7=BB=84=E4=BB=B6=E7=8A=B6=E6=80=81=20(#12684)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/terminal/models/component/terminal.py | 3 ++- apps/terminal/utils/components.py | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) 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/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 From c4342567ba13b248205230eb1a05bba7880dfe18 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Thu, 22 Feb 2024 16:06:19 +0800 Subject: [PATCH 54/69] =?UTF-8?q?fix:=20=E8=BF=9C=E7=A8=8B=E5=BA=94?= =?UTF-8?q?=E7=94=A8README=E5=9B=BD=E9=99=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api/applet/applet.py | 16 +++++++++++++--- apps/terminal/applets/chrome/README_EN.md | 9 +++++++++ apps/terminal/applets/chrome/README_JA.md | 9 +++++++++ .../applets/chrome/{README.md => README_ZH.md} | 0 apps/terminal/applets/dbeaver/README_EN.md | 4 ++++ apps/terminal/applets/dbeaver/README_JA.md | 3 +++ .../applets/dbeaver/{README.md => README_ZH.md} | 0 7 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 apps/terminal/applets/chrome/README_EN.md create mode 100644 apps/terminal/applets/chrome/README_JA.md rename apps/terminal/applets/chrome/{README.md => README_ZH.md} (100%) create mode 100644 apps/terminal/applets/dbeaver/README_EN.md create mode 100644 apps/terminal/applets/dbeaver/README_JA.md rename apps/terminal/applets/dbeaver/{README.md => README_ZH.md} (100%) diff --git a/apps/terminal/api/applet/applet.py b/apps/terminal/api/applet/applet.py index f85e5f572..de725c332 100644 --- a/apps/terminal/api/applet/applet.py +++ b/apps/terminal/api/applet/applet.py @@ -119,8 +119,7 @@ class AppletViewSet(DownloadUploadMixin, JMSBulkModelViewSet): return queryset @staticmethod - def read_manifest_with_i18n(obj): - lang = get_language() + def read_manifest_with_i18n(obj, lang='zh'): with open(os.path.join(obj.path, 'manifest.yml'), encoding='utf8') as f: manifest = yaml_load_with_i18n(f, lang) return manifest @@ -130,10 +129,21 @@ class AppletViewSet(DownloadUploadMixin, JMSBulkModelViewSet): 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): - manifest = self.read_manifest_with_i18n(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): 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 From edf0630cef69e131d2f53e415242f1aa4c0afb46 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Thu, 22 Feb 2024 17:33:31 +0800 Subject: [PATCH 55/69] =?UTF-8?q?fix:=20=E7=94=A8=E6=88=B7=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=AF=BC=E5=87=BA=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/drf/renders/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From f660c38d803758f0d366eee6e2755e8f4fe55543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E5=B0=8F=E7=99=BD?= <296015668@qq.com> Date: Thu, 22 Feb 2024 19:00:55 +0800 Subject: [PATCH 56/69] =?UTF-8?q?fix:=20=E6=B7=BB=E5=8A=A0=20psycopg2=20?= =?UTF-8?q?=E7=BC=BA=E5=A4=B1=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile-ce | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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" From d7f8ba58ada311300f60326beb08a564c28bcffc Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Mon, 26 Feb 2024 13:37:01 +0800 Subject: [PATCH 57/69] =?UTF-8?q?perf:=20=E4=BD=9C=E4=B8=9A=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=B7=BB=E5=8A=A0=E4=BB=BB=E5=8A=A1=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/audits/serializers.py | 2 +- apps/audits/tasks.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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 667fc5c5f..a22eaeb33 100644 --- a/apps/audits/tasks.py +++ b/apps/audits/tasks.py @@ -43,6 +43,7 @@ def clean_password_change_log_period(): 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(): From 09432b01a7acac15b00eee5bfa6eb6d714d27dfe Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:47:19 +0800 Subject: [PATCH 58/69] =?UTF-8?q?fix:=20=E8=87=AA=E5=8A=A8=E5=8C=96?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=AF=86=E9=92=A5=E4=B8=BA=20None=20?= =?UTF-8?q?=E6=8A=A5=E9=94=99=20(#12709)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/accounts/automations/change_secret/manager.py | 4 ++++ apps/accounts/automations/verify_account/manager.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/accounts/automations/change_secret/manager.py b/apps/accounts/automations/change_secret/manager.py index ee6aa436f..d85e057b5 100644 --- a/apps/accounts/automations/change_secret/manager.py +++ b/apps/accounts/automations/change_secret/manager.py @@ -119,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, 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(), } From 4b7c0b84378def2aad2da2808ae2937caa70d65b Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:47:19 +0800 Subject: [PATCH 59/69] =?UTF-8?q?perf:=20=E7=94=A8=E6=88=B7=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E7=BF=BB=E8=AF=91=E8=B6=85=E7=BA=A7=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=91=98=EF=BC=8C=E7=BB=84=E7=BB=87=E7=AE=A1=E7=90=86=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/ja/LC_MESSAGES/django.po | 94 +++++++++++++++------------- apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 94 +++++++++++++++------------- apps/users/serializers/user.py | 2 + 5 files changed, 108 insertions(+), 90 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 7c5720ca9..45714f01c 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:2fd8cc044dd42750cc1c96a051cdd767172d2e1c6026c65a6db44f4eac21426a -size 171418 +oid sha256:c9446906e12d6db2687753ded172353a7df3b087db0d0d848bf10158d611fc1b +size 171615 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index e209dc2c6..e3ed72e39 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-02-19 11:14+0800\n" +"POT-Creation-Date: 2024-02-26 17:14+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -22,7 +22,7 @@ msgstr "" msgid "The parameter 'action' must be [{}]" msgstr "パラメータ 'action' は [{}] でなければなりません。" -#: accounts/automations/change_secret/manager.py:197 +#: accounts/automations/change_secret/manager.py:201 #, python-format msgid "Success: %s, Failed: %s, Total: %s" msgstr "成功: %s、失敗: %s、合計: %s" @@ -36,7 +36,7 @@ msgstr "成功: %s、失敗: %s、合計: %s" #: 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 @@ -402,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:51 +#: ops/serializers/job.py:71 terminal/serializers/session.py:51 msgid "Is success" msgstr "成功は" @@ -616,7 +616,7 @@ msgstr "パスワードルール" #: terminal/models/applet/applet.py:33 terminal/models/component/endpoint.py:12 #: 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 @@ -636,7 +636,7 @@ msgstr "特権アカウント" #: authentication/serializers/connect_token_secret.py:117 #: terminal/models/applet/applet.py:40 #: terminal/models/component/endpoint.py:120 -#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:167 +#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:169 msgid "Is active" msgstr "アクティブです。" @@ -1133,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 @@ -1612,7 +1612,7 @@ msgstr "ボタンセレクターを確認する" msgid "API mode" msgstr "APIモード" -#: assets/const/types.py:247 +#: assets/const/types.py:248 msgid "All types" msgstr "いろんなタイプ" @@ -2417,7 +2417,7 @@ 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/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" @@ -2653,11 +2653,11 @@ msgstr "仮パスワード" msgid "Passkey" msgstr "Passkey" -#: audits/tasks.py:108 +#: audits/tasks.py:109 msgid "Clean audits session task log" msgstr "資産監査セッションタスクログのクリーンアップ" -#: audits/tasks.py:122 +#: audits/tasks.py:123 msgid "Upload FTP file to external storage" msgstr "外部ストレージへのFTPファイルのアップロード" @@ -3234,7 +3234,7 @@ 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 "期限切れです" @@ -3249,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 "有効です" @@ -4339,7 +4339,7 @@ msgstr "Material" msgid "Material Type" msgstr "Material を選択してオプションを設定します。" -#: ops/models/job.py:558 +#: ops/models/job.py:567 msgid "Job Execution" msgstr "ジョブ実行" @@ -4383,15 +4383,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:55 +#: 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 "時を過ごす" @@ -4882,21 +4882,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 "無効なショートメッセージプラットフォーム" @@ -6230,6 +6222,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 "エクスポート" @@ -6786,28 +6786,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 "ターミナル構成を表示できます" @@ -7847,7 +7847,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 "サービスアカウントです" @@ -7859,7 +7859,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 "電話" @@ -7870,7 +7870,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 "最初のログインです" @@ -8064,35 +8064,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 "名前が一意ではない" @@ -8540,7 +8548,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 fc8da2aa5..ffb6db050 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:68cbef2326c0b3abe8d8358eba96400ead043348c80ab9ece490c18610bf6b6c -size 140527 +oid sha256:78af89ae300362f26852652ebd1abcf24885a2c2ab1154baba2a4a20f16e2817 +size 140688 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 85a1458c6..745e69411 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-02-19 11:14+0800\n" +"POT-Creation-Date: 2024-02-26 17:14+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -21,7 +21,7 @@ msgstr "" msgid "The parameter 'action' must be [{}]" msgstr "参数 'action' 必须是 [{}]" -#: accounts/automations/change_secret/manager.py:197 +#: accounts/automations/change_secret/manager.py:201 #, python-format msgid "Success: %s, Failed: %s, Total: %s" msgstr "成功: %s, 失败: %s, 总数: %s" @@ -35,7 +35,7 @@ msgstr "成功: %s, 失败: %s, 总数: %s" #: 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 @@ -401,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:51 +#: ops/serializers/job.py:71 terminal/serializers/session.py:51 msgid "Is success" msgstr "是否成功" @@ -615,7 +615,7 @@ msgstr "密码规则" #: terminal/models/applet/applet.py:33 terminal/models/component/endpoint.py:12 #: 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 @@ -635,7 +635,7 @@ msgstr "特权账号" #: authentication/serializers/connect_token_secret.py:117 #: terminal/models/applet/applet.py:40 #: terminal/models/component/endpoint.py:120 -#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:167 +#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:169 msgid "Is active" msgstr "激活" @@ -1129,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 @@ -1602,7 +1602,7 @@ msgstr "确认按钮选择器" msgid "API mode" msgstr "API 模式" -#: assets/const/types.py:247 +#: assets/const/types.py:248 msgid "All types" msgstr "所有类型" @@ -2400,7 +2400,7 @@ 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/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" @@ -2636,11 +2636,11 @@ msgstr "临时密码" msgid "Passkey" msgstr "Passkey" -#: audits/tasks.py:108 +#: audits/tasks.py:109 msgid "Clean audits session task log" msgstr "清理资产审计会话任务日志" -#: audits/tasks.py:122 +#: audits/tasks.py:123 msgid "Upload FTP file to external storage" msgstr "上传 FTP 文件到外部存储" @@ -3202,7 +3202,7 @@ 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 "已过期" @@ -3217,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 "是否有效" @@ -4288,7 +4288,7 @@ msgstr "Material" msgid "Material Type" msgstr "Material 类型" -#: ops/models/job.py:558 +#: ops/models/job.py:567 msgid "Job Execution" msgstr "作业执行" @@ -4332,15 +4332,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:55 +#: 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 "花费时间" @@ -4829,19 +4829,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 "无效的短信平台" @@ -6146,6 +6138,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 "导出" @@ -6692,28 +6692,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 "可以查看终端配置" @@ -7740,7 +7740,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 "服务账号" @@ -7752,7 +7752,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 "手机" @@ -7763,7 +7763,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 "首次登录" @@ -7953,35 +7953,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 "名称重复" @@ -8416,7 +8424,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/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 From cea16fc41fe4bfd064e550dbca9f7b5de0d3f924 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Mon, 26 Feb 2024 10:50:44 +0800 Subject: [PATCH 60/69] =?UTF-8?q?perf:=20=E5=91=BD=E4=BB=A4=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=20=E5=8F=96=E6=B6=88input=E9=95=BF=E5=BA=A6=E9=99=90?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/backends/command/db.py | 7 ++++--- apps/terminal/serializers/command.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) 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/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, From fc0891ceeef8bedd6725fa869ce68cbae1e8b40a Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 26 Feb 2024 18:30:11 +0800 Subject: [PATCH 61/69] =?UTF-8?q?perf:=20=E4=BC=9A=E8=AF=9D=E7=94=9F?= =?UTF-8?q?=E5=91=BD=E5=91=A8=E6=9C=9F=E6=97=A5=E5=BF=97=E7=BF=BB=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/ja/LC_MESSAGES/django.po | 88 +++++++++++++++++++++++++++- apps/locale/zh/LC_MESSAGES/django.po | 88 +++++++++++++++++++++++++++- 2 files changed, 172 insertions(+), 4 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index e3ed72e39..aae98f99a 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-02-26 17:14+0800\n" +"POT-Creation-Date: 2024-02-26 18:02+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -7293,6 +7293,90 @@ msgstr "コンテナステータス" msgid "Container Ports" msgstr "コンテナポート" +#: terminal/session_lifecycle.py:30 +msgid "Connect to asset %s success" +msgstr "アセット %s への接続に成功しました" + +#: terminal/session_lifecycle.py:38 +msgid "Connect to asset %s finished: %s" +msgstr "アセット %s への接続が完了しました: %s" + +#: terminal/session_lifecycle.py:48 +msgid "User %s create share link" +msgstr "ユーザー %s が共有リンクを作成しました" + +#: terminal/session_lifecycle.py:57 +msgid "User %s join session" +msgstr "ユーザー %s がセッションに参加しました" + +#: terminal/session_lifecycle.py:69 +msgid "User %s leave session" +msgstr "ユーザー %s がセッションを離れました" + +#: terminal/session_lifecycle.py:81 +msgid "User %s join to monitor session" +msgstr "ユーザー %s がモニターセッションに参加しました" + +#: terminal/session_lifecycle.py:93 +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 +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 +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 "端末の状態を定期的にクリーンアップする" @@ -8548,7 +8632,7 @@ msgstr "そして" msgid "Or" msgstr "または" -#: xpack/plugins/cloud/manager.py:57 +#: xpack/plugins/cloud/manager.py:56 msgid "Account unavailable" msgstr "利用できないアカウント" diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 745e69411..29c889f18 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-02-26 17:14+0800\n" +"POT-Creation-Date: 2024-02-26 18:02+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -7192,6 +7192,90 @@ msgstr "容器状态" msgid "Container Ports" msgstr "容器端口" +#: terminal/session_lifecycle.py:30 +msgid "Connect to asset %s success" +msgstr "连接资产 %s 成功" + +#: terminal/session_lifecycle.py:38 +msgid "Connect to asset %s finished: %s" +msgstr "连接资产 %s 结束: %s" + +#: terminal/session_lifecycle.py:48 +msgid "User %s create share link" +msgstr "用户 %s 创建分享链接" + +#: terminal/session_lifecycle.py:57 +msgid "User %s join session" +msgstr "用户 %s 加入会话" + +#: terminal/session_lifecycle.py:69 +msgid "User %s leave session" +msgstr "用户 %s 离开会话" + +#: terminal/session_lifecycle.py:81 +msgid "User %s join to monitor session" +msgstr "用户 %s 监控会话" + +#: terminal/session_lifecycle.py:93 +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 +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 +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 "周期清理终端状态" @@ -8424,7 +8508,7 @@ msgstr "与" msgid "Or" msgstr "或" -#: xpack/plugins/cloud/manager.py:57 +#: xpack/plugins/cloud/manager.py:56 msgid "Account unavailable" msgstr "账号无效" From 4cfd1bc047bab2b6582706580020980eb896cff2 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Fri, 23 Feb 2024 16:45:23 +0800 Subject: [PATCH 62/69] =?UTF-8?q?fix:=20=E8=BF=9C=E7=A8=8B=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E5=88=97=E8=A1=A8=E6=8E=A5=E5=8F=A3=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api/applet/applet.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/terminal/api/applet/applet.py b/apps/terminal/api/applet/applet.py index de725c332..1a6b31815 100644 --- a/apps/terminal/api/applet/applet.py +++ b/apps/terminal/api/applet/applet.py @@ -120,8 +120,12 @@ class AppletViewSet(DownloadUploadMixin, JMSBulkModelViewSet): @staticmethod def read_manifest_with_i18n(obj, lang='zh'): - with open(os.path.join(obj.path, 'manifest.yml'), encoding='utf8') as f: - manifest = yaml_load_with_i18n(f, lang) + 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): From 889cdca3b001a3e4069fbe2aa4f175656f2daccf Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Mon, 26 Feb 2024 18:51:40 +0800 Subject: [PATCH 63/69] =?UTF-8?q?fix:=20=E6=93=8D=E4=BD=9C=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=B5=84=E6=BA=90=E7=B1=BB=E5=9E=8B=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E6=97=A0=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/audits/api.py | 7 ++----- apps/audits/filters.py | 25 +++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/apps/audits/api.py b/apps/audits/api.py index 5a665777b..8bdc7e070 100644 --- a/apps/audits/api.py +++ b/apps/audits/api.py @@ -31,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 @@ -205,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'] diff --git a/apps/audits/filters.py b/apps/audits/filters.py index 078e68c2c..b82eadad3 100644 --- a/apps/audits/filters.py +++ b/apps/audits/filters.py @@ -1,11 +1,13 @@ +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 common.sessions.cache import user_session_manager from orgs.utils import current_org -from .models import UserSession +from .models import UserSession, OperateLog __all__ = ['CurrentOrgMembersFilter'] @@ -50,3 +52,22 @@ class UserSessionFilterSet(BaseFilterSet): 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' + ] From 7517e77af9400d0a3286e571c562ff291d85e542 Mon Sep 17 00:00:00 2001 From: masix <310916789@qq.com> Date: Tue, 27 Feb 2024 02:41:40 +0000 Subject: [PATCH 64/69] =?UTF-8?q?=E6=8C=87=E5=AE=9Alxml=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E4=B8=BA4.9.3=20=E4=BF=AE=E5=A4=8DSAML2=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E5=9B=9E=E8=B0=83/core/auth/saml2/callback/=E6=97=B6=E5=81=B6?= =?UTF-8?q?=E5=8F=91=E5=87=BA=E7=8E=B0http=20502=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 032043057..e0d084724 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -148,6 +148,7 @@ 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] From e71e335f5c84c0ff12fc6bbd601a9cda612b7faa Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Mon, 26 Feb 2024 18:04:21 +0800 Subject: [PATCH 65/69] =?UTF-8?q?fix:=20=E7=BB=88=E6=96=AD=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=97=B6=E6=8E=A5=E5=8F=A3=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/ja/LC_MESSAGES/django.mo | 4 ++-- apps/locale/ja/LC_MESSAGES/django.po | 24 +++++++++++++++++++----- apps/locale/zh/LC_MESSAGES/django.mo | 4 ++-- apps/locale/zh/LC_MESSAGES/django.po | 22 ++++++++++++++++++---- apps/ops/api/job.py | 21 ++++++++++++++++++++- 5 files changed, 61 insertions(+), 14 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 45714f01c..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:c9446906e12d6db2687753ded172353a7df3b087db0d0d848bf10158d611fc1b -size 171615 +oid sha256:d04781f4f0b0de3ac5f707febb222e239553d6103bca0cec41ab2fd5ab044571 +size 173799 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index aae98f99a..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-02-26 18:02+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" @@ -4077,11 +4077,11 @@ msgstr "タスクは存在しません" 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" @@ -4089,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つのジョブで使用されています" @@ -7294,30 +7299,37 @@ 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 がモニターセッションを離れました" @@ -7330,6 +7342,7 @@ 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" @@ -7342,10 +7355,11 @@ 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" +#: terminal/session_lifecycle.py:152 msgid "connect failed" msgstr "接続に失敗しました" @@ -8632,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 ffb6db050..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:78af89ae300362f26852652ebd1abcf24885a2c2ab1154baba2a4a20f16e2817 -size 140688 +oid sha256:e66a6fa05d25f1c502f95001b5ff0d0a310affd32eac939fd7b840845028074f +size 142298 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 29c889f18..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-02-26 18:02+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" @@ -4028,16 +4028,21 @@ msgstr "任务 {} 不存在" 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 正在作业中使用" @@ -7193,30 +7198,37 @@ 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 离开监控会话" @@ -7229,6 +7241,7 @@ 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" @@ -7241,6 +7254,7 @@ msgid "Replay successfully uploaded" msgstr "录像成功上传" #: terminal/session_lifecycle.py:145 +#, python-format msgid "Replay failed to upload: %s" msgstr "录像上传失败:%s" @@ -8508,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/ops/api/job.py b/apps/ops/api/job.py index 4c60956fd..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,6 +16,7 @@ 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, JobTaskStopSerializer @@ -194,7 +197,23 @@ class JobExecutionViewSet(OrgBulkModelViewSet): if not serializer.is_valid(): return Response({'error': serializer.errors}, status=400) task_id = serializer.validated_data['task_id'] - instance = get_object_or_404(JobExecution, task_id=task_id, creator=request.user) + 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) From 8ebc99339b1bdc0c16b0daa30c04bdbf2b7067b7 Mon Sep 17 00:00:00 2001 From: Bai Date: Wed, 28 Feb 2024 10:20:41 +0800 Subject: [PATCH 66/69] =?UTF-8?q?perf:=20=E6=9B=B4=E6=96=B0=20poetry.lock?= =?UTF-8?q?=20=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- poetry.lock | 964 ++++++++++++++++++++++++++-------------------------- 1 file changed, 485 insertions(+), 479 deletions(-) diff --git a/poetry.lock b/poetry.lock index d8318a563..5262e4337 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.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,13 +730,13 @@ reference = "tsinghua" [[package]] name = "azure-core" -version = "1.29.7" +version = "1.30.0" description = "Microsoft Azure Core Library for Python" optional = false python-versions = ">=3.7" files = [ - {file = "azure-core-1.29.7.tar.gz", hash = "sha256:2944faf1a7ff1558b1f457cabf60f279869cabaeef86b353bed8eb032c7d8c5e"}, - {file = "azure_core-1.29.7-py3-none-any.whl", hash = "sha256:95a7b41b4af102e5fcdfac9500fcc82ff86e936c7145a099b7848b9ac0501250"}, + {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] @@ -1082,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] @@ -1616,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] @@ -1796,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] @@ -1929,7 +1930,7 @@ reference = "tsinghua" [[package]] name = "django-cas-ng" version = "4.3.0" -description = "" +description = "Django CAS 1.0/2.0/3.0 client authentication library, support Django 2.2, 3.0, 3.1, 3.2, 4.0 and Python 3.7+" optional = false python-versions = ">=3.7" files = [ @@ -2262,22 +2263,22 @@ reference = "tsinghua" [[package]] name = "dnspython" -version = "2.5.0" +version = "2.6.1" description = "DNS toolkit" optional = false python-versions = ">=3.8" files = [ - {file = "dnspython-2.5.0-py3-none-any.whl", hash = "sha256:6facdf76b73c742ccf2d07add296f178e629da60be23ce4b0a9c927b1e02c3a6"}, - {file = "dnspython-2.5.0.tar.gz", hash = "sha256:a0034815a59ba9ae888946be7ccca8f7c157b286f8455b379c692efb51022a15"}, + {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, + {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, ] [package.extras] -dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=5.0.3)", "mypy (>=1.0.1)", "pylint (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0.0)", "sphinx (>=7.0.0)", "twine (>=4.0.0)", "wheel (>=0.41.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 (>=0.17.3)", "httpx (>=0.25.1)"] -doq = ["aioquic (>=0.9.20)"] -idna = ["idna (>=2.1)"] -trio = ["trio (>=0.14)"] +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] @@ -2824,13 +2825,13 @@ 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] @@ -2853,13 +2854,13 @@ reference = "tsinghua" [[package]] name = "google-auth" -version = "2.27.0" +version = "2.28.1" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.27.0.tar.gz", hash = "sha256:e863a56ccc2d8efa83df7a80272601e43487fa9a728a376205c86c26aaefa821"}, - {file = "google_auth-2.27.0-py2.py3-none-any.whl", hash = "sha256:8e4bad367015430ff253fe49d500fdc3396c1a434db5740828c728e45bcce245"}, + {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] @@ -2999,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" @@ -3070,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] @@ -3148,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] @@ -3165,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" @@ -3194,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] @@ -3782,96 +3783,110 @@ reference = "tsinghua" [[package]] name = "lxml" -version = "5.1.0" +version = "4.9.3" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" files = [ - {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e"}, - {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da"}, - {file = "lxml-5.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2befa20a13f1a75c751f47e00929fb3433d67eb9923c2c0b364de449121f447c"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22b7ee4c35f374e2c20337a95502057964d7e35b996b1c667b5c65c567d2252a"}, - {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bf8443781533b8d37b295016a4b53c1494fa9a03573c09ca5104550c138d5c05"}, - {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147"}, - {file = "lxml-5.1.0-cp310-cp310-win32.whl", hash = "sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93"}, - {file = "lxml-5.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af8920ce4a55ff41167ddbc20077f5698c2e710ad3353d32a07d3264f3a2021e"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cfced4a069003d8913408e10ca8ed092c49a7f6cefee9bb74b6b3e860683b45"}, - {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9e5ac3437746189a9b4121db2a7b86056ac8786b12e88838696899328fc44bb2"}, - {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204"}, - {file = "lxml-5.1.0-cp311-cp311-win32.whl", hash = "sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b"}, - {file = "lxml-5.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16dd953fb719f0ffc5bc067428fc9e88f599e15723a85618c45847c96f11f431"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16018f7099245157564d7148165132c70adb272fb5a17c048ba70d9cc542a1a1"}, - {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:82cd34f1081ae4ea2ede3d52f71b7be313756e99b4b5f829f89b12da552d3aa3"}, - {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:19a1bc898ae9f06bccb7c3e1dfd73897ecbbd2c96afe9095a6026016e5ca97b8"}, - {file = "lxml-5.1.0-cp312-cp312-win32.whl", hash = "sha256:13521a321a25c641b9ea127ef478b580b5ec82aa2e9fc076c86169d161798b01"}, - {file = "lxml-5.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:1ad17c20e3666c035db502c78b86e58ff6b5991906e55bdbef94977700c72623"}, - {file = "lxml-5.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:24ef5a4631c0b6cceaf2dbca21687e29725b7c4e171f33a8f8ce23c12558ded1"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d2900b7f5318bc7ad8631d3d40190b95ef2aa8cc59473b73b294e4a55e9f30f"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:601f4a75797d7a770daed8b42b97cd1bb1ba18bd51a9382077a6a247a12aa38d"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4b68c961b5cc402cbd99cca5eb2547e46ce77260eb705f4d117fd9c3f932b95"}, - {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:afd825e30f8d1f521713a5669b63657bcfe5980a916c95855060048b88e1adb7"}, - {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:262bc5f512a66b527d026518507e78c2f9c2bd9eb5c8aeeb9f0eb43fcb69dc67"}, - {file = "lxml-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:e856c1c7255c739434489ec9c8aa9cdf5179785d10ff20add308b5d673bed5cd"}, - {file = "lxml-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c7257171bb8d4432fe9d6fdde4d55fdbe663a63636a17f7f9aaba9bcb3153ad7"}, - {file = "lxml-5.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b9e240ae0ba96477682aa87899d94ddec1cc7926f9df29b1dd57b39e797d5ab5"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a96f02ba1bcd330807fc060ed91d1f7a20853da6dd449e5da4b09bfcc08fdcf5"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3898ae2b58eeafedfe99e542a17859017d72d7f6a63de0f04f99c2cb125936"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61c5a7edbd7c695e54fca029ceb351fc45cd8860119a0f83e48be44e1c464862"}, - {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3aeca824b38ca78d9ee2ab82bd9883083d0492d9d17df065ba3b94e88e4d7ee6"}, - {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764"}, - {file = "lxml-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8"}, - {file = "lxml-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b"}, - {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1"}, - {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45"}, - {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:98f3f020a2b736566c707c8e034945c02aa94e124c24f77ca097c446f81b01f1"}, - {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e"}, - {file = "lxml-5.1.0-cp38-cp38-win32.whl", hash = "sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a"}, - {file = "lxml-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f8b0c78e7aac24979ef09b7f50da871c2de2def043d468c4b41f512d831e912"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bcf86dfc8ff3e992fed847c077bd875d9e0ba2fa25d859c3a0f0f76f07f0c8d"}, - {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:49a9b4af45e8b925e1cd6f3b15bbba2c81e7dba6dce170c677c9cda547411e14"}, - {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:280f3edf15c2a967d923bcfb1f8f15337ad36f93525828b40a0f9d6c2ad24890"}, - {file = "lxml-5.1.0-cp39-cp39-win32.whl", hash = "sha256:ed7326563024b6e91fef6b6c7a1a2ff0a71b97793ac33dbbcf38f6005e51ff6e"}, - {file = "lxml-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:8d7b4beebb178e9183138f552238f7e6613162a42164233e2bda00cb3afac58f"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9bd0ae7cc2b85320abd5e0abad5ccee5564ed5f0cc90245d2f9a8ef330a8deae"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8c1d679df4361408b628f42b26a5d62bd3e9ba7f0c0e7969f925021554755aa"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2ad3a8ce9e8a767131061a22cd28fdffa3cd2dc193f399ff7b81777f3520e372"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:304128394c9c22b6569eba2a6d98392b56fbdfbad58f83ea702530be80d0f9df"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d74fcaf87132ffc0447b3c685a9f862ffb5b43e70ea6beec2fb8057d5d2a1fea"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8cf5877f7ed384dabfdcc37922c3191bf27e55b498fecece9fd5c2c7aaa34c33"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:877efb968c3d7eb2dad540b6cabf2f1d3c0fbf4b2d309a3c141f79c7e0061324"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f14a4fb1c1c402a22e6a341a24c1341b4a3def81b41cd354386dcb795f83897"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:25663d6e99659544ee8fe1b89b1a8c0aaa5e34b103fab124b17fa958c4a324a6"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8b9f19df998761babaa7f09e6bc169294eefafd6149aaa272081cbddc7ba4ca3"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e53d7e6a98b64fe54775d23a7c669763451340c3d44ad5e3a3b48a1efbdc96f"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c3cd1fc1dc7c376c54440aeaaa0dcc803d2126732ff5c6b68ccd619f2e64be4f"}, - {file = "lxml-5.1.0.tar.gz", hash = "sha256:3eea6ed6e6c918e468e693c41ef07f3c3acc310b70ddd9cc72d9ef84bc9564ca"}, + {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.8)"] +source = ["Cython (>=0.29.35)"] [package.source] type = "legacy" @@ -4044,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" @@ -4209,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] @@ -4318,15 +4349,18 @@ reference = "tsinghua" [[package]] name = "netaddr" -version = "0.10.1" +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.1-py2.py3-none-any.whl", hash = "sha256:9822305b42ea1020d54fee322d43cee5622b044c07a1f0130b459bb467efcf88"}, - {file = "netaddr-0.10.1.tar.gz", hash = "sha256:f4da4222ca8c3f43c8e18a8263e5426c750a3a837fdfeccf74c68d0408eaa3bf"}, + {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" @@ -4414,13 +4448,13 @@ reference = "tsinghua" [[package]] name = "openai" -version = "1.9.0" +version = "1.12.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.9.0-py3-none-any.whl", hash = "sha256:5774a0582ed82f6de92200ed5024e03e272b93e04e9d31caeda5fb80f63df50d"}, - {file = "openai-1.9.0.tar.gz", hash = "sha256:3e9947a544556c051fa138a4def5bd8b468364ec52803c6628532ab949ddce55"}, + {file = "openai-1.12.0-py3-none-any.whl", hash = "sha256:a54002c814e05222e413664f651b5916714e4700d041d5cf5724d3ae1a3e3481"}, + {file = "openai-1.12.0.tar.gz", hash = "sha256:99c5d257d09ea6533d689d1cc77caa0ac679fa21efef8893d8b0832a86877f1b"}, ] [package.dependencies] @@ -4543,13 +4577,13 @@ reference = "tsinghua" [[package]] name = "oslo-config" -version = "9.3.0" +version = "9.4.0" description = "Oslo Configuration API" optional = false python-versions = ">=3.8" files = [ - {file = "oslo.config-9.3.0-py3-none-any.whl", hash = "sha256:5642e75ab8070aee96563670b1c1ee3b6f3cac3c0302fe7fc78973cd4b4e3d29"}, - {file = "oslo.config-9.3.0.tar.gz", hash = "sha256:a4b1e526135d67c0e9b14d3ed299c6ec8a3887f92afcb26f4f3ea918504a3554"}, + {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] @@ -4563,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" @@ -4572,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] @@ -4591,21 +4625,20 @@ reference = "tsinghua" [[package]] name = "oslo-serialization" -version = "5.3.0" +version = "5.4.0" description = "Oslo Serialization library" optional = false python-versions = ">=3.8" files = [ - {file = "oslo.serialization-5.3.0-py3-none-any.whl", hash = "sha256:0da7248d0e515b875ef9883e3631ff51f9a8d11e8576247f0ded890f3276c0bf"}, - {file = "oslo.serialization-5.3.0.tar.gz", hash = "sha256:228898f4f33b7deabc74289b32bbd302a659c39cf6dda9048510f930fc4f76ed"}, + {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" @@ -4614,13 +4647,13 @@ reference = "tsinghua" [[package]] name = "oslo-utils" -version = "7.0.0" +version = "7.1.0" description = "Oslo Utility library" optional = false python-versions = ">=3.8" files = [ - {file = "oslo.utils-7.0.0-py3-none-any.whl", hash = "sha256:dbb724041a2ea0c342d524c4d7c7f07c8bc5016f4762d38c6a41b2ef805b3a8e"}, - {file = "oslo.utils-7.0.0.tar.gz", hash = "sha256:5263c00980cfab74f6635ef61d0fc91e6bd4a8dd0e78a77897ed6e447c8c6731"}, + {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] @@ -4631,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" @@ -4912,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" @@ -4934,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] @@ -4994,22 +5026,22 @@ reference = "tsinghua" [[package]] name = "protobuf" -version = "4.25.2" +version = "4.25.3" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"}, - {file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"}, - {file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"}, - {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"}, - {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"}, - {file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"}, - {file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"}, - {file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"}, - {file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"}, - {file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"}, - {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, + {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] @@ -5331,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] @@ -5355,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] @@ -6638,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" @@ -6774,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] @@ -6942,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] @@ -7040,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] @@ -7202,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] @@ -7218,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] @@ -7634,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] @@ -7804,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] @@ -7863,4 +7869,4 @@ reference = "tsinghua" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "3f4c08616b1a3ede830282eae1c3f456581e4b926ad134ae3d5af0a807d29c02" +content-hash = "9f9294b5efb21a24625429dddb084c8d7f53b4d9d7d41c534d249bc9ed512905" From 457d2b23599938da3f77a0d3d06b88d5596c5fde Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Wed, 28 Feb 2024 15:51:08 +0800 Subject: [PATCH 67/69] =?UTF-8?q?fix:=20=E4=BD=9C=E4=B8=9A=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E8=B5=84=E4=BA=A7=E6=A0=B9=E6=8D=AE=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E8=BF=87=E6=BB=A4=E8=8E=B7=E5=8F=96=E4=B8=8D=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/perms/api/user_permission/assets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/perms/api/user_permission/assets.py b/apps/perms/api/user_permission/assets.py index 5456af1e3..676a21e5e 100644 --- a/apps/perms/api/user_permission/assets.py +++ b/apps/perms/api/user_permission/assets.py @@ -5,6 +5,7 @@ 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 @@ -38,7 +39,7 @@ class UserPermedAssetRetrieveApi(SelfOrPKUserMixin, RetrieveAPIView): return asset -class BaseUserPermedAssetsApi(SelfOrPKUserMixin, ListAPIView): +class BaseUserPermedAssetsApi(SelfOrPKUserMixin, ExtraFilterFieldsMixin, ListAPIView): ordering = [] search_fields = ('name', 'address', 'comment') ordering_fields = ("name", "address") From b557e264bcdfbac9c409263b00b3d8816545dead Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Thu, 29 Feb 2024 15:58:52 +0800 Subject: [PATCH 68/69] =?UTF-8?q?fix:=20=E8=B4=A6=E5=8F=B7=E5=A4=87?= =?UTF-8?q?=E4=BB=BD=E9=80=89=E6=8B=A9SFTP=E6=9C=89=E5=A4=9A=E4=B8=AA?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E9=87=8D=E5=A4=8D=E7=BC=96=E7=A0=81password?= =?UTF-8?q?=E4=BC=9A=E5=AF=BC=E8=87=B4=E4=BB=BB=E5=8A=A1=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/accounts/automations/backup_account/handlers.py | 4 +--- apps/accounts/automations/change_secret/manager.py | 3 +-- apps/common/utils/file.py | 2 ++ 3 files changed, 4 insertions(+), 5 deletions(-) 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/manager.py b/apps/accounts/automations/change_secret/manager.py index d85e057b5..e4d1a0fd5 100644 --- a/apps/accounts/automations/change_secret/manager.py +++ b/apps/accounts/automations/change_secret/manager.py @@ -230,9 +230,8 @@ 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, summary).publish(attachments) os.remove(filename) 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: From f0ffa2408daceee5a2bf64cd87a94befdd80125b Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Thu, 29 Feb 2024 16:06:26 +0800 Subject: [PATCH 69/69] =?UTF-8?q?fix:=20=E5=93=A8=E5=85=B5redis=20?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E9=87=8C=E6=9C=89@=20=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/jumpserver/conf.py | 3 ++- apps/jumpserver/settings/base.py | 2 +- apps/jumpserver/settings/libs.py | 7 ++++--- utils/start_celery_beat.py | 7 +++---- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 719bc3ae9..d1caba0cd 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -704,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/settings/base.py b/apps/jumpserver/settings/base.py index f05293155..6503b2477 100644 --- a/apps/jumpserver/settings/base.py +++ b/apps/jumpserver/settings/base.py @@ -406,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/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/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, }