| JumpServer 连接 GPT 资产的组件项目 |
diff --git a/apps/accounts/automations/backup_account/handlers.py b/apps/accounts/automations/backup_account/handlers.py
index df801cda0..763428308 100644
--- a/apps/accounts/automations/backup_account/handlers.py
+++ b/apps/accounts/automations/backup_account/handlers.py
@@ -3,13 +3,13 @@ import time
from collections import defaultdict, OrderedDict
from django.conf import settings
-from openpyxl import Workbook
from rest_framework import serializers
+from xlsxwriter import Workbook
from accounts.const.automation import AccountBackupType
+from accounts.models.automations.backup_account import AccountBackupAutomation
from accounts.notifications import AccountBackupExecutionTaskMsg, AccountBackupByObjStorageExecutionTaskMsg
from accounts.serializers import AccountSecretSerializer
-from accounts.models.automations.backup_account import AccountBackupAutomation
from assets.const import AllTypes
from common.utils.file import encrypt_and_compress_zip_file, zip_files
from common.utils.timezone import local_now_filename, local_now_display
@@ -144,10 +144,11 @@ class AccountBackupHandler:
wb = Workbook(filename)
for sheet, data in data_map.items():
- ws = wb.create_sheet(str(sheet))
+ ws = wb.add_worksheet(str(sheet))
for row in data:
- ws.append(row)
- wb.save(filename)
+ for col, _data in enumerate(row):
+ ws.write_string(0, col, _data)
+ wb.close()
files.append(filename)
timedelta = round((time.time() - time_start), 2)
print('创建备份文件完成: 用时 {}s'.format(timedelta))
diff --git a/apps/accounts/automations/change_secret/manager.py b/apps/accounts/automations/change_secret/manager.py
index 46d3ef2b6..74dfc717e 100644
--- a/apps/accounts/automations/change_secret/manager.py
+++ b/apps/accounts/automations/change_secret/manager.py
@@ -4,7 +4,7 @@ from copy import deepcopy
from django.conf import settings
from django.utils import timezone
-from openpyxl import Workbook
+from xlsxwriter import Workbook
from accounts.const import AutomationTypes, SecretType, SSHKeyStrategy, SecretStrategy
from accounts.models import ChangeSecretRecord
@@ -227,8 +227,9 @@ class ChangeSecretManager(AccountBasePlaybookManager):
rows.insert(0, header)
wb = Workbook(filename)
- ws = wb.create_sheet('Sheet1')
+ ws = wb.add_worksheet('Sheet1')
for row in rows:
- ws.append(row)
- wb.save(filename)
+ for col, data in enumerate(row):
+ ws.write_string(0, col, data)
+ wb.close()
return True
diff --git a/apps/accounts/automations/gather_accounts/manager.py b/apps/accounts/automations/gather_accounts/manager.py
index 0941a78fa..1c9ae990f 100644
--- a/apps/accounts/automations/gather_accounts/manager.py
+++ b/apps/accounts/automations/gather_accounts/manager.py
@@ -72,7 +72,7 @@ class GatherAccountsManager(AccountBasePlaybookManager):
)
gathered_accounts.append(gathered_account)
if not self.is_sync_account:
- return
+ continue
GatheredAccount.sync_accounts(gathered_accounts)
def run(self, *args, **kwargs):
diff --git a/apps/accounts/automations/remove_account/host/posix/main.yml b/apps/accounts/automations/remove_account/host/posix/main.yml
index de91b8552..cddac5541 100644
--- a/apps/accounts/automations/remove_account/host/posix/main.yml
+++ b/apps/accounts/automations/remove_account/host/posix/main.yml
@@ -16,10 +16,11 @@
- name: "Rename user home directory if it exists"
ansible.builtin.command:
cmd: "mv {{ user_home_dir.stdout }} {{ user_home_dir.stdout }}.bak"
- when: home_dir.stat.exists and user_home_dir.stdout != ""
+ when: home_dir.stat | default(false) and user_home_dir.stdout != ""
- name: "Remove account"
ansible.builtin.user:
name: "{{ account.username }}"
state: absent
remove: "{{ home_dir.stat.exists }}"
+ when: home_dir.stat | default(false)
diff --git a/apps/acls/notifications.py b/apps/acls/notifications.py
index cf19b7a51..dc4db25ac 100644
--- a/apps/acls/notifications.py
+++ b/apps/acls/notifications.py
@@ -1,6 +1,7 @@
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
+from accounts.models import Account
from assets.models import Asset
from audits.models import UserLoginLog
from notifications.notifications import UserMessage
@@ -16,12 +17,11 @@ class UserLoginReminderMsg(UserMessage):
def get_html_msg(self) -> dict:
user_log = self.user_log
-
context = {
'ip': user_log.ip,
'city': user_log.city,
'username': user_log.username,
- 'recipient': self.user.username,
+ 'recipient': self.user,
'user_agent': user_log.user_agent,
}
message = render_to_string('acls/user_login_reminder.html', context)
@@ -48,11 +48,14 @@ class AssetLoginReminderMsg(UserMessage):
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,
+ '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,
}
message = render_to_string('acls/asset_login_reminder.html', context)
diff --git a/apps/acls/templates/acls/asset_login_reminder.html b/apps/acls/templates/acls/asset_login_reminder.html
index af836cab5..672c5e8de 100644
--- a/apps/acls/templates/acls/asset_login_reminder.html
+++ b/apps/acls/templates/acls/asset_login_reminder.html
@@ -1,10 +1,10 @@
{% load i18n %}
-{% trans 'Respectful' %}{{ recipient }},
+{% trans 'Respectful' %}: {{ recipient.name }}[{{ recipient.username }}]
-{% trans 'Username' %}: [{{ username }}]
+{% trans 'User' %}: [{{ name }}({{ username }})]
{% trans 'Assets' %}: [{{ asset }}]
-{% trans 'Account' %}: [{{ account }}]
+{% trans 'Account' %}: [{{ account_name }}({{ account }})]
{% trans 'The user has just logged in to the asset. Please ensure that this is an authorized operation. If you suspect that this is an unauthorized access, please take appropriate measures immediately.' %}
diff --git a/apps/acls/templates/acls/user_login_reminder.html b/apps/acls/templates/acls/user_login_reminder.html
index 3af4fd52a..fe4c1d9a9 100644
--- a/apps/acls/templates/acls/user_login_reminder.html
+++ b/apps/acls/templates/acls/user_login_reminder.html
@@ -1,8 +1,8 @@
{% load i18n %}
-{% trans 'Respectful' %}{{ recipient }},
+{% trans 'Respectful' %}: {{ recipient.name }}[{{ recipient.username }}]
-{% trans 'Username' %}: [{{ username }}]
+{% trans 'User' %}: [{{ username }}]
IP: [{{ ip }}]
{% trans 'Login city' %}: [{{ city }}]
{% trans 'User agent' %}: [{{ user_agent }}]
diff --git a/apps/assets/api/asset/asset.py b/apps/assets/api/asset/asset.py
index e0b1aa3bf..eef18a773 100644
--- a/apps/assets/api/asset/asset.py
+++ b/apps/assets/api/asset/asset.py
@@ -93,7 +93,7 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):
model = Asset
filterset_class = AssetFilterSet
search_fields = ("name", "address", "comment")
- ordering_fields = ('name', 'connectivity', 'platform', 'date_updated', 'date_created')
+ ordering_fields = ('name', 'address', 'connectivity', 'platform', 'date_updated', 'date_created')
serializer_classes = (
("default", serializers.AssetSerializer),
("platform", serializers.PlatformSerializer),
diff --git a/apps/audits/signal_handlers/login_log.py b/apps/audits/signal_handlers/login_log.py
index 5829e4f5e..ea53716b4 100644
--- a/apps/audits/signal_handlers/login_log.py
+++ b/apps/audits/signal_handlers/login_log.py
@@ -122,7 +122,8 @@ def send_login_info_to_reviewers(instance: UserLoginLog | str, auth_acl_id):
def on_user_auth_success(sender, user, request, login_type=None, **kwargs):
logger.debug('User login success: {}'.format(user.username))
check_different_city_login_if_need(user, request)
- data = generate_data(user.username, request, login_type=login_type)
+ username = f"{user.name}({user.username})"
+ data = generate_data(username, request, login_type=login_type)
request.session['login_time'] = data['datetime'].strftime('%Y-%m-%d %H:%M:%S')
data.update({'mfa': int(user.mfa_enabled), 'status': True})
instance = write_login_log(**data)
diff --git a/apps/authentication/middleware.py b/apps/authentication/middleware.py
index 10659a53a..eabb90263 100644
--- a/apps/authentication/middleware.py
+++ b/apps/authentication/middleware.py
@@ -152,6 +152,8 @@ class SessionCookieMiddleware(MiddlewareMixin):
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)
diff --git a/apps/jumpserver/__init__.py b/apps/jumpserver/__init__.py
index 8b1378917..ff4333aa4 100644
--- a/apps/jumpserver/__init__.py
+++ b/apps/jumpserver/__init__.py
@@ -1 +1 @@
-
+from jumpserver.rewriting import db # noqa 采用猴子补丁的方式,重写atomic ForeignKey OneToOneField
diff --git a/apps/jumpserver/rewriting/__init__.py b/apps/jumpserver/rewriting/__init__.py
index 72949abe2..139597f9c 100644
--- a/apps/jumpserver/rewriting/__init__.py
+++ b/apps/jumpserver/rewriting/__init__.py
@@ -1,2 +1,2 @@
-from . import db
+
diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po
index d46d47829..92d6c4552 100644
--- a/apps/locale/ja/LC_MESSAGES/django.po
+++ b/apps/locale/ja/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-12-21 16:12+0800\n"
+"POT-Creation-Date: 2023-12-26 14:13+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -476,7 +476,7 @@ 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
-#: terminal/models/applet/applet.py:319 terminal/models/applet/host.py:140
+#: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:140
#: terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:18 terminal/serializers/applet_host.py:136
@@ -742,7 +742,7 @@ msgstr "アカウントの存在ポリシー"
#: assets/models/label.py:21 assets/models/platform.py:96
#: assets/serializers/asset/common.py:122 assets/serializers/cagegory.py:12
#: assets/serializers/platform.py:140 assets/serializers/platform.py:236
-#: perms/serializers/user_permission.py:25 settings/models.py:35
+#: perms/serializers/user_permission.py:26 settings/models.py:35
#: tickets/models/ticket/apply_application.py:13 users/models/preference.py:12
msgid "Category"
msgstr "カテゴリ"
@@ -756,7 +756,7 @@ msgstr "カテゴリ"
#: 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
-#: perms/serializers/user_permission.py:26 terminal/models/applet/applet.py:39
+#: 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
@@ -923,7 +923,7 @@ msgstr "关联平台,可以配置推送参数,如果不关联,则使用默
#: 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
#: settings/models.py:38 terminal/models/applet/applet.py:45
-#: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:143
+#: 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/session/session.py:46
@@ -1720,7 +1720,7 @@ msgstr "アドレス"
#: assets/models/asset/common.py:161 assets/models/platform.py:126
#: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:118
-#: perms/serializers/user_permission.py:24 xpack/plugins/cloud/models.py:329
+#: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:329
msgid "Platform"
msgstr "プラットフォーム"
@@ -1886,8 +1886,7 @@ msgstr "値"
#: assets/serializers/platform.py:119
#: authentication/serializers/connect_token_secret.py:124
#: common/serializers/common.py:85 labels/models.py:17 labels/models.py:33
-#: labels/serializers.py:45 perms/serializers/user_permission.py:27
-#: settings/serializers/msg.py:83
+#: labels/serializers.py:45 settings/serializers/msg.py:83
msgid "Label"
msgstr "ラベル"
@@ -3707,7 +3706,7 @@ msgid "Invalid ids for ids, should be a list"
msgstr "無効なID、リストでなければなりません"
#: common/db/fields.py:585 common/db/fields.py:590
-#: common/serializers/fields.py:134 tickets/serializers/ticket/common.py:58
+#: 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
#: xpack/plugins/cloud/serializers/account_attrs.py:150
@@ -3880,21 +3879,21 @@ msgstr "{} 秒待ってから送信してください"
msgid "Children"
msgstr "ノード"
-#: common/serializers/fields.py:135
+#: common/serializers/fields.py:134
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr "無効な pk \"{pk_value}\" - オブジェクトが存在しません"
-#: common/serializers/fields.py:136
+#: common/serializers/fields.py:135
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr "エラータイプ。 予想される pk 値、受信 {data_type}。"
-#: common/serializers/fields.py:210
+#: common/serializers/fields.py:209
msgid "Invalid data type, should be list"
msgstr "間違ったデータ タイプです。リストにする必要があります"
-#: common/serializers/fields.py:225
+#: common/serializers/fields.py:224
msgid "Invalid choice: {}"
msgstr "無効なオプション: {}"
@@ -4815,7 +4814,7 @@ msgid "My assets"
msgstr "私の資産"
#: rbac/tree.py:58 terminal/models/applet/applet.py:52
-#: terminal/models/applet/applet.py:316 terminal/models/applet/host.py:30
+#: terminal/models/applet/applet.py:317 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:15
msgid "Applet"
msgstr "リモートアプリケーション"
@@ -6597,7 +6596,7 @@ msgstr "カスタムプラットフォームのみをサポート"
msgid "Missing type in platform.yml"
msgstr "platform.ymlにタイプがありません"
-#: terminal/models/applet/applet.py:318 terminal/models/applet/host.py:36
+#: terminal/models/applet/applet.py:319 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138
msgid "Hosting"
msgstr "ホスト マシン"
diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo
index abcc5b418..1fe3d019d 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:853320b42ac7795fa983c4216f89b3a776a889453d90e11dc425d1388ff9b803
+oid sha256:80dd11dde678e4f9b64df18906175125218fd9f719bfe9aaa667ad6e2d055d40
size 139012
diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po
index bd5989a79..472fb7b2e 100644
--- a/apps/locale/zh/LC_MESSAGES/django.po
+++ b/apps/locale/zh/LC_MESSAGES/django.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-12-21 16:12+0800\n"
+"POT-Creation-Date: 2023-12-26 14:13+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler \n"
"Language-Team: JumpServer team\n"
@@ -475,7 +475,7 @@ 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
-#: terminal/models/applet/applet.py:319 terminal/models/applet/host.py:140
+#: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:140
#: terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:18 terminal/serializers/applet_host.py:136
@@ -740,7 +740,7 @@ msgstr "账号存在策略"
#: assets/models/label.py:21 assets/models/platform.py:96
#: assets/serializers/asset/common.py:122 assets/serializers/cagegory.py:12
#: assets/serializers/platform.py:140 assets/serializers/platform.py:236
-#: perms/serializers/user_permission.py:25 settings/models.py:35
+#: perms/serializers/user_permission.py:26 settings/models.py:35
#: tickets/models/ticket/apply_application.py:13 users/models/preference.py:12
msgid "Category"
msgstr "类别"
@@ -754,7 +754,7 @@ msgstr "类别"
#: 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
-#: perms/serializers/user_permission.py:26 terminal/models/applet/applet.py:39
+#: 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
@@ -921,7 +921,7 @@ msgstr "关联平台,可配置推送参数,如果不关联,将使用默认
#: 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
#: settings/models.py:38 terminal/models/applet/applet.py:45
-#: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:143
+#: 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/session/session.py:46
@@ -1712,7 +1712,7 @@ msgstr "地址"
#: assets/models/asset/common.py:161 assets/models/platform.py:126
#: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:118
-#: perms/serializers/user_permission.py:24 xpack/plugins/cloud/models.py:329
+#: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:329
msgid "Platform"
msgstr "系统平台"
@@ -1878,8 +1878,7 @@ msgstr "值"
#: assets/serializers/platform.py:119
#: authentication/serializers/connect_token_secret.py:124
#: common/serializers/common.py:85 labels/models.py:17 labels/models.py:33
-#: labels/serializers.py:45 perms/serializers/user_permission.py:27
-#: settings/serializers/msg.py:83
+#: labels/serializers.py:45 settings/serializers/msg.py:83
msgid "Label"
msgstr "标签"
@@ -3663,7 +3662,7 @@ msgid "Invalid ids for ids, should be a list"
msgstr "无效的ID,应为列表"
#: common/db/fields.py:585 common/db/fields.py:590
-#: common/serializers/fields.py:134 tickets/serializers/ticket/common.py:58
+#: 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
#: xpack/plugins/cloud/serializers/account_attrs.py:150
@@ -3834,21 +3833,21 @@ msgstr "请在 {} 秒后发送"
msgid "Children"
msgstr "节点"
-#: common/serializers/fields.py:135
+#: common/serializers/fields.py:134
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr "错误的 pk \"{pk_value}\" - 对象不存在"
-#: common/serializers/fields.py:136
+#: common/serializers/fields.py:135
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr "错误类型。期望 pk 值,收到 {data_type}。"
-#: common/serializers/fields.py:210
+#: common/serializers/fields.py:209
msgid "Invalid data type, should be list"
msgstr "错误的数据类型,应该是列表"
-#: common/serializers/fields.py:225
+#: common/serializers/fields.py:224
msgid "Invalid choice: {}"
msgstr "无效选项: {}"
@@ -4762,7 +4761,7 @@ msgid "My assets"
msgstr "我的资产"
#: rbac/tree.py:58 terminal/models/applet/applet.py:52
-#: terminal/models/applet/applet.py:316 terminal/models/applet/host.py:30
+#: terminal/models/applet/applet.py:317 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:15
msgid "Applet"
msgstr "远程应用"
@@ -5464,7 +5463,7 @@ msgstr "启用 Vault"
#: settings/serializers/feature.py:55
msgid "Mount Point"
-msgstr "挂在点"
+msgstr "挂载点"
#: settings/serializers/feature.py:60
msgid "Chat AI"
@@ -6504,7 +6503,7 @@ msgstr "只支持自定义平台"
msgid "Missing type in platform.yml"
msgstr "在 platform.yml 中缺少类型"
-#: terminal/models/applet/applet.py:318 terminal/models/applet/host.py:36
+#: terminal/models/applet/applet.py:319 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138
msgid "Hosting"
msgstr "宿主机"
diff --git a/apps/ops/ansible/modules_utils/custom_common.py b/apps/ops/ansible/modules_utils/custom_common.py
index 29b1132b5..0cf1420d2 100644
--- a/apps/ops/ansible/modules_utils/custom_common.py
+++ b/apps/ops/ansible/modules_utils/custom_common.py
@@ -26,6 +26,7 @@ def common_argument_spec():
class SSHClient:
+ TIMEOUT = 20
SLEEP_INTERVAL = 2
COMPLETE_FLAG = 'complete'
@@ -170,7 +171,12 @@ class SSHClient:
time.sleep(self.SLEEP_INTERVAL)
output += self._get_recv()
continue
+ start_time = time.time()
while self.COMPLETE_FLAG not in output:
+ if time.time() - start_time > self.TIMEOUT:
+ error_msg = output
+ print("切换用户操作超时,跳出循环。")
+ break
time.sleep(self.SLEEP_INTERVAL)
received_output = self._get_recv().replace(f'"{self.COMPLETE_FLAG}"', '')
output += received_output
diff --git a/apps/ops/api/job.py b/apps/ops/api/job.py
index f16fefde2..61768f5d9 100644
--- a/apps/ops/api/job.py
+++ b/apps/ops/api/job.py
@@ -217,6 +217,7 @@ class JobExecutionTaskDetail(APIView):
'is_success': execution.is_success,
'time_cost': execution.time_cost,
'job_id': execution.job.id,
+ 'summary': execution.summary
})
diff --git a/apps/perms/serializers/user_permission.py b/apps/perms/serializers/user_permission.py
index 9f7f89cee..0bd9bdc02 100644
--- a/apps/perms/serializers/user_permission.py
+++ b/apps/perms/serializers/user_permission.py
@@ -10,6 +10,7 @@ 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 common.serializers import ResourceLabelsMixin
from orgs.mixins.serializers import OrgResourceModelSerializerMixin
from perms.serializers.permission import ActionChoicesField
@@ -19,12 +20,11 @@ __all__ = [
]
-class AssetPermedSerializer(OrgResourceModelSerializerMixin):
+class AssetPermedSerializer(OrgResourceModelSerializerMixin, ResourceLabelsMixin):
""" 被授权资产的数据结构 """
platform = ObjectRelatedField(required=False, queryset=Platform.objects, label=_('Platform'))
category = LabeledChoiceField(choices=Category.choices, read_only=True, label=_('Category'))
type = LabeledChoiceField(choices=AllTypes.choices(), read_only=True, label=_('Type'))
- labels = AssetLabelSerializer(many=True, required=False, label=_('Label'))
domain = ObjectRelatedField(required=False, queryset=Node.objects, label=_('Domain'))
class Meta:
diff --git a/apps/rbac/const.py b/apps/rbac/const.py
index 71eb47fbc..c47c22dba 100644
--- a/apps/rbac/const.py
+++ b/apps/rbac/const.py
@@ -30,6 +30,7 @@ exclude_permissions = (
('users', 'userpasswordhistory', '*', '*'),
('users', 'usersession', '*', '*'),
('assets', 'adminuser', '*', '*'),
+ ('assets', 'label', '*', '*'),
('assets', 'assetgroup', '*', '*'),
('assets', 'cluster', '*', '*'),
('assets', 'systemuser', '*', '*'),
diff --git a/apps/rbac/serializers/permission.py b/apps/rbac/serializers/permission.py
index cc97b6c8a..3af435e33 100644
--- a/apps/rbac/serializers/permission.py
+++ b/apps/rbac/serializers/permission.py
@@ -7,14 +7,14 @@ from ..models import Permission
__all__ = ['PermissionSerializer', 'UserPermsSerializer']
-class ContentTypeSerializer(serializers.ModelSerializer):
+class PermissionContentTypeSerializer(serializers.ModelSerializer):
class Meta:
model = ContentType
fields = ['id', 'app_label', 'model']
class PermissionSerializer(serializers.ModelSerializer):
- content_type = ContentTypeSerializer(read_only=True)
+ content_type = PermissionContentTypeSerializer(read_only=True)
class Meta:
model = Permission
diff --git a/apps/settings/serializers/feature.py b/apps/settings/serializers/feature.py
index 8dc0de959..083e2749a 100644
--- a/apps/settings/serializers/feature.py
+++ b/apps/settings/serializers/feature.py
@@ -86,7 +86,7 @@ class ChatAISettingSerializer(serializers.Serializer):
return
gpt_api_model = Protocol.gpt_protocols()[Protocol.chatgpt]['setting']['api_mode']
choices = gpt_api_model['choices']
- field_gpt_model._choices = choices
+ field_gpt_model.choices = choices
field_gpt_model.default = gpt_api_model['default']
cls = self.__class__
if cls.GPT_MODEL_CHOICES:
diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py
index fd5934285..9e501eb50 100644
--- a/apps/terminal/models/applet/applet.py
+++ b/apps/terminal/models/applet/applet.py
@@ -172,8 +172,9 @@ class Applet(JMSBaseModel):
return None
spec_label = asset.labels.filter(label__name__in=['AppletHost', '发布机']).first()
- if spec_label:
- matched = [host for host in hosts if host.name == spec_label.value]
+ if spec_label and spec_label.label:
+ label_value = spec_label.label.value
+ matched = [host for host in hosts if host.name == label_value]
if matched:
return matched[0]
diff --git a/apps/users/api/relation.py b/apps/users/api/relation.py
index 4fbf29cc5..e0fa8af2f 100644
--- a/apps/users/api/relation.py
+++ b/apps/users/api/relation.py
@@ -16,6 +16,10 @@ class UserUserGroupRelationViewSet(JMSBulkRelationModelViewSet):
search_fields = filterset_fields
serializer_class = serializers.User2GroupRelationSerializer
m2m_field = User.groups.field
+ rbac_perms = {
+ 'create': 'users.change_usergroup',
+ 'bulk_destroy': 'users.change_usergroup',
+ }
def get_queryset(self):
return super().get_queryset().annotate(
diff --git a/apps/users/models/user.py b/apps/users/models/user.py
index bf03dadce..290c0c1f1 100644
--- a/apps/users/models/user.py
+++ b/apps/users/models/user.py
@@ -867,6 +867,7 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, LabeledMixin, JSONFilterM
queryset = cls.objects.all()
if not current_org.is_root():
queryset = current_org.get_members()
+ queryset = queryset.exclude(is_service_account=True)
return queryset
@property
diff --git a/apps/users/serializers/group.py b/apps/users/serializers/group.py
index e05546bba..2276b6e0e 100644
--- a/apps/users/serializers/group.py
+++ b/apps/users/serializers/group.py
@@ -16,7 +16,8 @@ __all__ = [
class UserGroupSerializer(ResourceLabelsMixin, BulkOrgResourceModelSerializer):
users = ObjectRelatedField(
- required=False, many=True, queryset=User.objects, label=_('User'),
+ required=False, many=True, queryset=User.objects,
+ attrs=("id", "name", "is_service_account"), label=_('User'),
)
class Meta:
diff --git a/poetry.lock b/poetry.lock
index 3bf68f9c9..4b7cac7ea 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -7540,6 +7540,22 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "tsinghua"
+[[package]]
+name = "xlsxwriter"
+version = "3.1.9"
+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"},
+]
+
+[package.source]
+type = "legacy"
+url = "https://pypi.tuna.tsinghua.edu.cn/simple"
+reference = "tsinghua"
+
[[package]]
name = "xmlsec"
version = "1.3.13"
@@ -7755,4 +7771,4 @@ reference = "tsinghua"
[metadata]
lock-version = "2.0"
python-versions = "^3.11"
-content-hash = "397cb294c81da3ce74f1a1c3044bd778669284c0c280177162ed9d51e623a7c8"
+content-hash = "19950a5300f8a4425e3e3c9a096fc3782cb544e02152e92ac1bc09d1d9b5274a"
diff --git a/pyproject.toml b/pyproject.toml
index eff9f4444..58b9991f6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -145,6 +145,7 @@ user-agents = "^2.2.0"
django-cors-headers = "^4.3.0"
mistune = "0.8.4"
openai = "^1.3.7"
+xlsxwriter = "^3.1.9"
[tool.poetry.group.xpack.dependencies]