Merge pull request #6680 from jumpserver/dev

v2.13.0 rc4
pull/6697/head
Jiangjie.Bai 2021-08-18 19:50:17 +08:00 committed by GitHub
commit 6c8d1c4e77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 298 additions and 223 deletions

View File

@ -40,6 +40,11 @@ class RemoteAppSerializer(serializers.Serializer):
max_length=128, label=_('Application path'), allow_null=True
)
def validate_asset(self, asset):
if not asset:
raise serializers.ValidationError(_('This field is required'))
return asset
@staticmethod
def get_asset_info(obj):
asset_id = obj.get('asset')

View File

@ -40,7 +40,7 @@ class AccountFilterSet(BaseFilterSet):
if not node_id:
return qs
node = get_object_or_404(Node, pk=node_id)
node_ids = node.get_children(with_self=True).values_list('id', flat=True)
node_ids = node.get_all_children(with_self=True).values_list('id', flat=True)
node_ids = list(node_ids)
qs = qs.filter(asset__nodes__in=node_ids)
return qs

View File

@ -17,7 +17,7 @@ __all__ = [
class ProtocolField(serializers.RegexField):
protocols = '|'.join(dict(Asset.Protocol.choices).keys())
default_error_messages = {
'invalid': _('Protocol format should {}/{}'.format(protocols, '1-65535'))
'invalid': _('Protocol format should {}/{}').format(protocols, '1-65535')
}
regex = r'^(%s)/(\d{1,5})$' % protocols

View File

@ -48,7 +48,6 @@ def expire_node_assets_mapping_for_memory(org_id):
Node.expire_node_all_asset_ids_mapping_from_cache(root_org_id)
node_assets_mapping_for_memory_pub_sub.publish(org_id)
node_assets_mapping_for_memory_pub_sub.publish(root_org_id)
@receiver(post_save, sender=Node)
@ -86,7 +85,9 @@ def subscribe_node_assets_mapping_expire(sender, **kwargs):
if message["type"] != "message":
continue
org_id = message['data'].decode()
root_org_id = Organization.ROOT_ID
Node.expire_node_all_asset_ids_mapping_from_memory(org_id)
Node.expire_node_all_asset_ids_mapping_from_memory(root_org_id)
logger.debug(
"Expire node assets id mapping from memory of org={}, pid={}"
"".format(str(org_id), os.getpid())

View File

@ -4,7 +4,7 @@ from itertools import groupby
from celery import shared_task
from common.db.utils import get_object_if_need, get_objects
from django.utils.translation import ugettext as _
from django.db.models import Empty
from django.db.models import Empty, Q
from common.utils import encrypt_password, get_logger
from assets.models import SystemUser, Asset, AuthBook
@ -239,9 +239,12 @@ def push_system_user_util(system_user, assets, task_name, username=None):
no_special_auth = []
special_auth_set = set()
auth_books = AuthBook.objects.filter(username__in=usernames, asset_id__in=asset_ids)
auth_books = AuthBook.objects.filter(asset_id__in=asset_ids).filter(
Q(username__in=usernames) | Q(systemuser__username__in=usernames)
).prefetch_related('systemuser')
for auth_book in auth_books:
auth_book.load_auth()
special_auth_set.add((auth_book.username, auth_book.asset_id))
for _username in usernames:

View File

@ -11,7 +11,7 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework.renderers import JSONRenderer
from rest_framework.request import Request
from assets.models import Asset
from assets.models import Asset, SystemUser
from common.const.signals import POST_ADD, POST_REMOVE, POST_CLEAR
from jumpserver.utils import current_request
from common.utils import get_request_ip, get_logger, get_syslogger
@ -38,7 +38,7 @@ MODELS_NEED_RECORD = (
'LoginACL', 'LoginAssetACL',
# assets
'Asset', 'Node', 'AdminUser', 'SystemUser', 'Domain', 'Gateway', 'CommandFilterRule',
'CommandFilter', 'Platform',
'CommandFilter', 'Platform', 'AuthBook',
# applications
'Application',
# orgs
@ -106,6 +106,11 @@ M2M_NEED_RECORD = {
_('{User} *JOINED* {UserGroup}'),
_('{User} *LEFT* {UserGroup}')
),
SystemUser.assets.through._meta.object_name: (
_('Asset and SystemUser'),
_('{Asset} *ADD* {SystemUser}'),
_('{Asset} *REMOVE* {SystemUser}')
),
Asset.nodes.through._meta.object_name: (
_('Node and Asset'),
_('{Node} *ADD* {Asset}'),

View File

@ -110,8 +110,11 @@ class IDSpmFilter(filters.BaseFilterBackend):
return queryset
cache_key = const.KEY_CACHE_RESOURCE_IDS.format(spm)
resource_ids = cache.get(cache_key)
if resource_ids is None or not isinstance(resource_ids, list):
return queryset
if resource_ids is None:
return queryset.none()
if isinstance(resource_ids, str):
resource_ids = [resource_ids]
if hasattr(view, 'filter_spm_queryset'):
queryset = view.filter_spm_queryset(resource_ids, queryset)
else:

View File

@ -36,7 +36,7 @@ class Services(TextChoices):
@classmethod
def web_services(cls):
return [cls.gunicorn, cls.daphne]
return [cls.gunicorn, cls.daphne, cls.flower]
@classmethod
def celery_services(cls):
@ -44,7 +44,7 @@ class Services(TextChoices):
@classmethod
def task_services(cls):
return cls.celery_services() + [cls.beat, cls.flower]
return cls.celery_services() + [cls.beat]
@classmethod
def all_services(cls):

View File

@ -6,6 +6,7 @@ from django.conf import settings
from common.exceptions import MFAVerifyRequired
from orgs.utils import current_org
from common.utils import is_uuid
class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission):
@ -186,7 +187,7 @@ class IsObjectOwner(IsValidUser):
class HasQueryParamsUserAndIsCurrentOrgMember(permissions.BasePermission):
def has_permission(self, request, view):
query_user_id = request.query_params.get('user')
if not query_user_id:
if not query_user_id or not is_uuid(query_user_id):
return False
query_user = current_org.get_members().filter(id=query_user_id).first()
return bool(query_user)

View File

@ -267,7 +267,7 @@ class Config(dict):
'SECURITY_INSECURE_COMMAND_LEVEL': 5,
'SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER': '',
'SECURITY_LUNA_REMEMBER_AUTH': True,
'SECURITY_WATERMARK_ENABLED': False,
'SECURITY_WATERMARK_ENABLED': True,
'HTTP_BIND_HOST': '0.0.0.0',
'HTTP_LISTEN_PORT': 8080,
@ -310,6 +310,7 @@ class Config(dict):
'FORGOT_PASSWORD_URL': '',
'HEALTH_CHECK_TOKEN': '',
'LOGIN_REDIRECT_TO_BACKEND': None, # 'OPENID / CAS
'CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS': 30,
'TERMINAL_RDP_ADDR': ''
}

View File

@ -131,3 +131,5 @@ SECURITY_LUNA_REMEMBER_AUTH = CONFIG.SECURITY_LUNA_REMEMBER_AUTH
SECURITY_WATERMARK_ENABLED = CONFIG.SECURITY_WATERMARK_ENABLED
LOGIN_REDIRECT_TO_BACKEND = CONFIG.LOGIN_REDIRECT_TO_BACKEND
CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS = CONFIG.CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS

Binary file not shown.

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-08-16 19:17+0800\n"
"POT-Creation-Date: 2021-08-18 18:56+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n"
@ -25,7 +25,7 @@ msgstr ""
#: orgs/models.py:24 perms/models/base.py:49 settings/models.py:29
#: terminal/models/storage.py:23 terminal/models/task.py:16
#: terminal/models/terminal.py:100 users/forms/profile.py:32
#: users/models/group.py:15 users/models/user.py:556
#: users/models/group.py:15 users/models/user.py:561
#: users/templates/users/_select_user_modal.html:13
#: users/templates/users/user_asset_permission.html:37
#: users/templates/users/user_asset_permission.html:154
@ -61,7 +61,7 @@ msgstr "激活中"
#: orgs/models.py:27 perms/models/base.py:57 settings/models.py:34
#: terminal/models/storage.py:26 terminal/models/terminal.py:114
#: tickets/models/ticket.py:73 users/models/group.py:16
#: users/models/user.py:589 xpack/plugins/change_auth_plan/models.py:88
#: users/models/user.py:594 xpack/plugins/change_auth_plan/models.py:88
#: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:113
#: xpack/plugins/gathered_user/models.py:26
msgid "Comment"
@ -98,8 +98,8 @@ msgstr "动作"
#: perms/models/base.py:50 templates/index.html:78
#: terminal/backends/command/models.py:18
#: terminal/backends/command/serializers.py:12 terminal/models/session.py:38
#: tickets/models/comment.py:17 users/models/user.py:176
#: users/models/user.py:757 users/models/user.py:783
#: tickets/models/comment.py:17 users/const.py:14 users/models/user.py:176
#: users/models/user.py:762 users/models/user.py:788
#: users/serializers/group.py:19
#: users/templates/users/user_asset_permission.html:38
#: users/templates/users/user_asset_permission.html:64
@ -172,14 +172,14 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. "
#: acls/serializers/login_asset_acl.py:17
#: acls/serializers/login_asset_acl.py:51
#: applications/serializers/application.py:72
#: applications/serializers/application.py:74
#: applications/serializers/attrs/application_type/chrome.py:20
#: applications/serializers/attrs/application_type/custom.py:21
#: applications/serializers/attrs/application_type/mysql_workbench.py:30
#: applications/serializers/attrs/application_type/vmware_client.py:26
#: assets/models/base.py:176 assets/models/gathered_user.py:15
#: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17
#: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:554
#: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:559
#: users/templates/users/_select_user_modal.html:14
#: xpack/plugins/change_auth_plan/models.py:51
#: xpack/plugins/change_auth_plan/models.py:311
@ -252,7 +252,7 @@ msgid "Applications"
msgstr "应用管理"
#: applications/models/application.py:168
#: applications/serializers/application.py:79 assets/models/label.py:21
#: applications/serializers/application.py:80 assets/models/label.py:21
#: perms/models/application_permission.py:20
#: perms/serializers/application/user_permission.py:33
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:20
@ -260,7 +260,7 @@ msgid "Category"
msgstr "类别"
#: applications/models/application.py:171
#: applications/serializers/application.py:81 assets/models/cmd_filter.py:53
#: applications/serializers/application.py:82 assets/models/cmd_filter.py:53
#: assets/models/user.py:202 perms/models/application_permission.py:23
#: perms/serializers/application/user_permission.py:34
#: terminal/models/storage.py:55 terminal/models/storage.py:116
@ -278,15 +278,15 @@ msgstr "网域"
msgid "Attrs"
msgstr ""
#: applications/serializers/application.py:48
#: applications/serializers/application.py:80 assets/serializers/label.py:13
#: applications/serializers/application.py:50
#: applications/serializers/application.py:81 assets/serializers/label.py:13
#: perms/serializers/application/permission.py:16
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:24
msgid "Category display"
msgstr "类别名称"
#: applications/serializers/application.py:49
#: applications/serializers/application.py:82
#: applications/serializers/application.py:51
#: applications/serializers/application.py:83
#: assets/serializers/system_user.py:26 audits/serializers.py:29
#: perms/serializers/application/permission.py:17
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:31
@ -294,12 +294,12 @@ msgstr "类别名称"
msgid "Type display"
msgstr "类型名称"
#: applications/serializers/application.py:71
#: applications/serializers/application.py:73
msgid "Id"
msgstr ""
#: applications/serializers/application.py:73
#: applications/serializers/application.py:101
#: applications/serializers/application.py:75
#: applications/serializers/application.py:110
#: applications/serializers/attrs/application_type/chrome.py:23
#: applications/serializers/attrs/application_type/custom.py:25
#: applications/serializers/attrs/application_type/mysql_workbench.py:34
@ -318,7 +318,7 @@ msgstr ""
msgid "Password"
msgstr "密码"
#: applications/serializers/application.py:74 assets/models/authbook.py:16
#: applications/serializers/application.py:76 assets/models/authbook.py:16
#: assets/models/user.py:277 audits/models.py:39
#: perms/models/application_permission.py:31
#: perms/models/asset_permission.py:101 templates/_nav.html:45
@ -333,21 +333,32 @@ msgstr "密码"
msgid "System user"
msgstr "系统用户"
#: applications/serializers/application.py:75 assets/serializers/account.py:31
#: applications/serializers/application.py:77 assets/serializers/account.py:31
msgid "System user display"
msgstr "系统用户名称"
#: applications/serializers/application.py:76
#: applications/serializers/application.py:78
msgid "App"
msgstr "应用"
#: applications/serializers/application.py:77
#: applications/serializers/application.py:79
msgid "Application name"
msgstr "应用名称"
#: applications/serializers/application.py:84
msgid "Union id"
msgstr "联合ID"
#: applications/serializers/application.py:78
msgid "Application name"
msgstr "应用名称"
#: applications/serializers/application.py:85 orgs/mixins/models.py:45
#: orgs/mixins/serializers.py:25 orgs/models.py:37 orgs/models.py:432
#: orgs/serializers.py:106 tickets/serializers/ticket/ticket.py:83
msgid "Organization"
msgstr "组织"
#: applications/serializers/application.py:86 assets/serializers/asset.py:97
#: assets/serializers/system_user.py:217 orgs/mixins/serializers.py:26
msgid "Org name"
msgstr "组织名称"
#: applications/serializers/attrs/application_category/cloud.py:9
#: assets/models/cluster.py:40
@ -376,6 +387,11 @@ msgstr "端口"
msgid "Application path"
msgstr "应用路径"
#: applications/serializers/attrs/application_category/remote_app.py:45
#: xpack/plugins/cloud/serializers.py:51
msgid "This field is required"
msgstr "这个字段是必填项"
#: applications/serializers/attrs/application_type/chrome.py:17
#: applications/serializers/attrs/application_type/vmware_client.py:22
msgid "Target URL"
@ -523,7 +539,7 @@ msgstr "标签管理"
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:26
#: assets/models/cmd_filter.py:67 assets/models/group.py:21
#: common/db/models.py:70 common/mixins/models.py:49 orgs/models.py:25
#: orgs/models.py:437 perms/models/base.py:55 users/models/user.py:597
#: orgs/models.py:437 perms/models/base.py:55 users/models/user.py:602
#: users/serializers/group.py:33 xpack/plugins/change_auth_plan/models.py:92
#: xpack/plugins/cloud/models.py:119 xpack/plugins/gathered_user/models.py:30
msgid "Created by"
@ -537,7 +553,7 @@ msgstr "创建者"
#: assets/models/label.py:25 common/db/models.py:72 common/mixins/models.py:50
#: ops/models/adhoc.py:38 ops/models/command.py:29 orgs/models.py:26
#: orgs/models.py:435 perms/models/base.py:56 users/models/group.py:18
#: users/models/user.py:784 xpack/plugins/cloud/models.py:122
#: users/models/user.py:789 xpack/plugins/cloud/models.py:122
msgid "Date created"
msgstr "创建日期"
@ -596,7 +612,7 @@ msgstr "带宽"
msgid "Contact"
msgstr "联系人"
#: assets/models/cluster.py:22 users/models/user.py:575
#: assets/models/cluster.py:22 users/models/user.py:580
msgid "Phone"
msgstr "手机"
@ -622,7 +638,7 @@ msgid "Default"
msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:14
#: users/models/user.py:769
#: users/models/user.py:774
msgid "System"
msgstr "系统"
@ -827,11 +843,6 @@ msgstr "节点名称"
msgid "Hardware info"
msgstr "硬件信息"
#: assets/serializers/asset.py:97 assets/serializers/system_user.py:217
#: orgs/mixins/serializers.py:26
msgid "Org name"
msgstr "组织名称"
#: assets/serializers/asset.py:98
msgid "Admin user display"
msgstr "特权用户名称"
@ -982,17 +993,17 @@ msgstr "推送系统用户到平台: [{}]"
msgid "Hosts count: {}"
msgstr "主机数量: {}"
#: assets/tasks/push_system_user.py:274 assets/tasks/push_system_user.py:307
#: assets/tasks/push_system_user.py:277 assets/tasks/push_system_user.py:310
msgid "Push system users to assets: {}"
msgstr "推送系统用户到入资产: {}"
#: assets/tasks/push_system_user.py:286
#: assets/tasks/push_system_user.py:289
msgid "Push system users to asset: {}({}) => {}"
msgstr "推送系统用户到入资产: {}({}) => {}"
#: assets/tasks/system_user_connectivity.py:56
msgid "Dynamic system user not support test"
msgstr ""
msgstr "动态系统用户不支持测试"
#: assets/tasks/system_user_connectivity.py:105
msgid "Start test system user connectivity for platform: [{}]"
@ -1147,7 +1158,7 @@ msgstr "用户代理"
#: audits/models.py:110
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
#: authentication/templates/authentication/login_otp.html:6
#: users/forms/profile.py:64 users/models/user.py:578
#: users/forms/profile.py:64 users/models/user.py:583
#: users/serializers/profile.py:102
msgid "MFA"
msgstr "多因子认证"
@ -1265,142 +1276,156 @@ msgid "{User} *LEFT* {UserGroup}"
msgstr "{User} *离开了* {UserGroup}"
#: audits/signals_handler.py:110
msgid "Asset and SystemUser"
msgstr "资产与系统用户"
#: audits/signals_handler.py:111
#, python-brace-format
msgid "{Asset} *ADD* {SystemUser}"
msgstr "{Asset} *添加了* {SystemUser}"
#: audits/signals_handler.py:112
#, python-brace-format
msgid "{Asset} *REMOVE* {SystemUser}"
msgstr "{Asset} *移除了* {SystemUser}"
#: audits/signals_handler.py:115
msgid "Node and Asset"
msgstr "节点与资产"
#: audits/signals_handler.py:111
#: audits/signals_handler.py:116
#, python-brace-format
msgid "{Node} *ADD* {Asset}"
msgstr "{Node} *添加了* {Asset}"
#: audits/signals_handler.py:112
#: audits/signals_handler.py:117
#, python-brace-format
msgid "{Node} *REMOVE* {Asset}"
msgstr "{Node} *移除了* {Asset}"
#: audits/signals_handler.py:115
#: audits/signals_handler.py:120
msgid "User asset permissions"
msgstr "用户资产授权"
#: audits/signals_handler.py:116
#: audits/signals_handler.py:121
#, python-brace-format
msgid "{AssetPermission} *ADD* {User}"
msgstr "{AssetPermission} *添加了* {User}"
#: audits/signals_handler.py:117
#: audits/signals_handler.py:122
#, python-brace-format
msgid "{AssetPermission} *REMOVE* {User}"
msgstr "{AssetPermission} *移除了* {User}"
#: audits/signals_handler.py:120
#: audits/signals_handler.py:125
msgid "User group asset permissions"
msgstr "用户组资产授权"
#: audits/signals_handler.py:121
#: audits/signals_handler.py:126
#, python-brace-format
msgid "{AssetPermission} *ADD* {UserGroup}"
msgstr "{AssetPermission} *添加了* {UserGroup}"
#: audits/signals_handler.py:122
#: audits/signals_handler.py:127
#, python-brace-format
msgid "{AssetPermission} *REMOVE* {UserGroup}"
msgstr "{AssetPermission} *移除了* {UserGroup}"
#: audits/signals_handler.py:125 perms/models/asset_permission.py:106
#: audits/signals_handler.py:130 perms/models/asset_permission.py:106
#: templates/_nav.html:78 users/templates/users/_user_detail_nav_header.html:31
msgid "Asset permission"
msgstr "资产授权"
#: audits/signals_handler.py:126
#: audits/signals_handler.py:131
#, python-brace-format
msgid "{AssetPermission} *ADD* {Asset}"
msgstr "{AssetPermission} *添加了* {Asset}"
#: audits/signals_handler.py:127
#: audits/signals_handler.py:132
#, python-brace-format
msgid "{AssetPermission} *REMOVE* {Asset}"
msgstr "{AssetPermission} *移除了* {Asset}"
#: audits/signals_handler.py:130
#: audits/signals_handler.py:135
msgid "Node permission"
msgstr "节点授权"
#: audits/signals_handler.py:131
#: audits/signals_handler.py:136
#, python-brace-format
msgid "{AssetPermission} *ADD* {Node}"
msgstr "{AssetPermission} *添加了* {Node}"
#: audits/signals_handler.py:132
#: audits/signals_handler.py:137
#, python-brace-format
msgid "{AssetPermission} *REMOVE* {Node}"
msgstr "{AssetPermission} *移除了* {Node}"
#: audits/signals_handler.py:135
#: audits/signals_handler.py:140
msgid "Asset permission and SystemUser"
msgstr "资产授权与系统用户"
#: audits/signals_handler.py:136
#: audits/signals_handler.py:141
#, python-brace-format
msgid "{AssetPermission} *ADD* {SystemUser}"
msgstr "{AssetPermission} *添加了* {SystemUser}"
#: audits/signals_handler.py:137
#: audits/signals_handler.py:142
#, python-brace-format
msgid "{AssetPermission} *REMOVE* {SystemUser}"
msgstr "{AssetPermission} *移除了* {SystemUser}"
#: audits/signals_handler.py:140
#: audits/signals_handler.py:145
msgid "User application permissions"
msgstr "用户应用授权"
#: audits/signals_handler.py:141
#: audits/signals_handler.py:146
#, python-brace-format
msgid "{ApplicationPermission} *ADD* {User}"
msgstr "{ApplicationPermission} *添加了* {User}"
#: audits/signals_handler.py:142
#: audits/signals_handler.py:147
#, python-brace-format
msgid "{ApplicationPermission} *REMOVE* {User}"
msgstr "{ApplicationPermission} *移除了* {User}"
#: audits/signals_handler.py:145
#: audits/signals_handler.py:150
msgid "User group application permissions"
msgstr "用户组应用授权"
#: audits/signals_handler.py:146
#: audits/signals_handler.py:151
#, python-brace-format
msgid "{ApplicationPermission} *ADD* {UserGroup}"
msgstr "{ApplicationPermission} *添加了* {UserGroup}"
#: audits/signals_handler.py:147
#: audits/signals_handler.py:152
#, python-brace-format
msgid "{ApplicationPermission} *REMOVE* {UserGroup}"
msgstr "{ApplicationPermission} *移除了* {UserGroup}"
#: audits/signals_handler.py:150 perms/models/application_permission.py:36
#: audits/signals_handler.py:155 perms/models/application_permission.py:36
msgid "Application permission"
msgstr "应用管理"
#: audits/signals_handler.py:151
#: audits/signals_handler.py:156
#, python-brace-format
msgid "{ApplicationPermission} *ADD* {Application}"
msgstr "{ApplicationPermission} *添加了* {Application}"
#: audits/signals_handler.py:152
#: audits/signals_handler.py:157
#, python-brace-format
msgid "{ApplicationPermission} *REMOVE* {Application}"
msgstr "{ApplicationPermission} *移除了* {Application}"
#: audits/signals_handler.py:155
#: audits/signals_handler.py:160
msgid "Application permission and SystemUser"
msgstr "应用授权与系统用户"
#: audits/signals_handler.py:156
#: audits/signals_handler.py:161
#, python-brace-format
msgid "{ApplicationPermission} *ADD* {SystemUser}"
msgstr "{ApplicationPermission} *添加了* {SystemUser}"
#: audits/signals_handler.py:157
#: audits/signals_handler.py:162
#, python-brace-format
msgid "{ApplicationPermission} *REMOVE* {SystemUser}"
msgstr "{ApplicationPermission} *移除了* {SystemUser}"
@ -1637,14 +1662,14 @@ msgid "Show"
msgstr "显示"
#: authentication/templates/authentication/_access_key_modal.html:66
#: settings/serializers/settings.py:149 users/models/user.py:463
#: settings/serializers/settings.py:149 users/models/user.py:468
#: users/serializers/profile.py:99
#: users/templates/users/user_verify_mfa.html:32
msgid "Disable"
msgstr "禁用"
#: authentication/templates/authentication/_access_key_modal.html:67
#: users/models/user.py:464 users/serializers/profile.py:100
#: users/models/user.py:469 users/serializers/profile.py:100
msgid "Enable"
msgstr "启用"
@ -2061,7 +2086,7 @@ msgstr ""
"div>"
#: notifications/backends/__init__.py:12 users/forms/profile.py:101
#: users/models/user.py:558
#: users/models/user.py:563
msgid "Email"
msgstr "邮件"
@ -2210,8 +2235,8 @@ msgstr "监控告警"
#: ops/notifications.py:36
#, python-brace-format
msgid "[Alive] The terminal is offline: {name}"
msgstr ""
msgid "The terminal is offline: {name}"
msgstr "终端已离线: {name}"
#: ops/notifications.py:42
#, python-brace-format
@ -2252,17 +2277,11 @@ msgstr "当前组织 ({}) 不能被删除"
msgid "The organization have resource ({}) cannot be deleted"
msgstr "组织存在资源 ({}) 不能被删除"
#: orgs/mixins/models.py:45 orgs/mixins/serializers.py:25 orgs/models.py:37
#: orgs/models.py:432 orgs/serializers.py:106
#: tickets/serializers/ticket/ticket.py:83
msgid "Organization"
msgstr "组织"
#: orgs/models.py:17
#: orgs/models.py:17 users/const.py:12
msgid "Organization administrator"
msgstr "组织管理员"
#: orgs/models.py:18
#: orgs/models.py:18 users/const.py:13
msgid "Organization auditor"
msgstr "组织审计员"
@ -2270,7 +2289,7 @@ msgstr "组织审计员"
msgid "GLOBAL"
msgstr "全局组织"
#: orgs/models.py:434 users/models/user.py:566
#: orgs/models.py:434 users/models/user.py:571 users/serializers/user.py:36
#: users/templates/users/_select_user_modal.html:15
msgid "Role"
msgstr "角色"
@ -2335,7 +2354,7 @@ msgid "Favorite"
msgstr "收藏夹"
#: perms/models/base.py:51 templates/_nav.html:21 users/models/group.py:31
#: users/models/user.py:562 users/templates/users/_select_user_modal.html:16
#: users/models/user.py:567 users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_asset_permission.html:39
#: users/templates/users/user_asset_permission.html:67
#: users/templates/users/user_database_app_permission.html:38
@ -2348,22 +2367,22 @@ msgstr "用户组"
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:77
#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:43
#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:81
#: users/models/user.py:594
#: users/models/user.py:599
msgid "Date expired"
msgstr "失效日期"
#: perms/serializers/application/permission.py:18
#: perms/serializers/application/permission.py:38
#: perms/serializers/asset/permission.py:42
#: perms/serializers/asset/permission.py:68 users/serializers/user.py:80
#: perms/serializers/asset/permission.py:68 users/serializers/user.py:76
msgid "Is valid"
msgstr "账户是否有效"
#: perms/serializers/application/permission.py:19
#: perms/serializers/application/permission.py:37
#: perms/serializers/asset/permission.py:43
#: perms/serializers/asset/permission.py:67 users/serializers/user.py:33
#: users/serializers/user.py:81
#: perms/serializers/asset/permission.py:67 users/serializers/user.py:28
#: users/serializers/user.py:77
msgid "Is expired"
msgstr "是否过期"
@ -2687,34 +2706,42 @@ msgid ""
"for security"
msgstr "是否允许终端注册,当所有终端启动后,为了安全应该关闭"
#: settings/serializers/settings.py:164
msgid "Replay watermark"
msgstr "录像水印"
#: settings/serializers/settings.py:165
msgid "Enabled, the session replay contains watermark information"
msgstr "启用后,会话录像将包含水印信息"
#: settings/serializers/settings.py:169
msgid "Limit the number of login failures"
msgstr "限制登录失败次数"
#: settings/serializers/settings.py:169
#: settings/serializers/settings.py:173
msgid "Block logon interval"
msgstr "禁止登录时间间隔"
#: settings/serializers/settings.py:170
#: settings/serializers/settings.py:174
msgid ""
"Tip: (unit/minute) if the user has failed to log in for a limited number of "
"times, no login is allowed during this time interval."
msgstr ""
"提示:(单位:分)当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录"
#: settings/serializers/settings.py:174
#: settings/serializers/settings.py:178
msgid "Connection max idle time"
msgstr "连接最大空闲时间"
#: settings/serializers/settings.py:175
#: settings/serializers/settings.py:179
msgid "If idle time more than it, disconnect connection Unit: minute"
msgstr "提示:如果超过该配置没有操作,连接会被断开 (单位:分)"
#: settings/serializers/settings.py:179
#: settings/serializers/settings.py:183
msgid "User password expiration"
msgstr "用户密码过期时间"
#: settings/serializers/settings.py:180
#: settings/serializers/settings.py:184
msgid ""
"Tip: (unit: day) If the user does not update the password during the time, "
"the user password will expire failure;The password expiration reminder mail "
@ -2724,61 +2751,61 @@ msgstr ""
"提示:(单位:天)如果用户在此期间没有更新密码,用户密码将过期失效; 密码过期"
"提醒邮件将在密码过期前5天内由系统每天自动发送给用户"
#: settings/serializers/settings.py:184
#: settings/serializers/settings.py:188
msgid "Number of repeated historical passwords"
msgstr "不能设置近几次密码"
#: settings/serializers/settings.py:185
#: settings/serializers/settings.py:189
msgid ""
"Tip: When the user resets the password, it cannot be the previous n "
"historical passwords of the user"
msgstr "提示:用户重置密码时,不能为该用户前几次使用过的密码"
#: settings/serializers/settings.py:189
#: settings/serializers/settings.py:193
msgid "Password minimum length"
msgstr "密码最小长度"
#: settings/serializers/settings.py:193
#: settings/serializers/settings.py:197
msgid "Admin user password minimum length"
msgstr "管理员密码最小长度"
#: settings/serializers/settings.py:196
#: settings/serializers/settings.py:200
msgid "Must contain capital"
msgstr "必须包含大写字符"
#: settings/serializers/settings.py:198
#: settings/serializers/settings.py:202
msgid "Must contain lowercase"
msgstr "必须包含小写字符"
#: settings/serializers/settings.py:199
#: settings/serializers/settings.py:203
msgid "Must contain numeric"
msgstr "必须包含数字"
#: settings/serializers/settings.py:200
#: settings/serializers/settings.py:204
msgid "Must contain special"
msgstr "必须包含特殊字符"
#: settings/serializers/settings.py:201
#: settings/serializers/settings.py:205
msgid "Insecure command alert"
msgstr "危险命令告警"
#: settings/serializers/settings.py:203
#: settings/serializers/settings.py:207
msgid "Email recipient"
msgstr "邮件收件人"
#: settings/serializers/settings.py:204
#: settings/serializers/settings.py:208
msgid "Multiple user using , split"
msgstr "多个用户,使用 , 分割"
#: settings/serializers/settings.py:212
#: settings/serializers/settings.py:216
msgid "Enable WeCom Auth"
msgstr "启用企业微信认证"
#: settings/serializers/settings.py:219
#: settings/serializers/settings.py:223
msgid "Enable DingTalk Auth"
msgstr "启用钉钉认证"
#: settings/serializers/settings.py:225
#: settings/serializers/settings.py:229
msgid "Enable FeiShu Auth"
msgstr "启用飞书认证"
@ -4086,6 +4113,22 @@ msgstr "你的工单已被处理, 处理人 - {}"
msgid "Could not reset self otp, use profile reset instead"
msgstr "不能在该页面重置多因子认证, 请去个人信息页面重置"
#: users/const.py:10 users/models/user.py:174
msgid "System administrator"
msgstr "系统管理员"
#: users/const.py:11 users/models/user.py:175
msgid "System auditor"
msgstr "系统审计员"
#: users/const.py:18
msgid "Reset link will be generated and sent to the user"
msgstr "生成重置密码链接,通过邮件发送给用户"
#: users/const.py:19
msgid "Set password"
msgstr "设置密码"
#: users/exceptions.py:10
msgid "MFA not enabled"
msgstr "MFA没有开启"
@ -4161,56 +4204,48 @@ msgstr "不能和原来的密钥相同"
msgid "Not a valid ssh public key"
msgstr "SSH密钥不合法"
#: users/forms/profile.py:160 users/models/user.py:586
#: users/forms/profile.py:160 users/models/user.py:591
#: users/templates/users/user_password_update.html:48
msgid "Public key"
msgstr "SSH公钥"
#: users/models/user.py:174
msgid "System administrator"
msgstr "系统管理员"
#: users/models/user.py:175
msgid "System auditor"
msgstr "系统审计员"
#: users/models/user.py:465
#: users/models/user.py:470
msgid "Force enable"
msgstr "强制启用"
#: users/models/user.py:535
#: users/models/user.py:540
msgid "Local"
msgstr "数据库"
#: users/models/user.py:569
#: users/models/user.py:574
msgid "Avatar"
msgstr "头像"
#: users/models/user.py:572
#: users/models/user.py:577
msgid "Wechat"
msgstr "微信"
#: users/models/user.py:583
#: users/models/user.py:588
msgid "Private key"
msgstr "ssh私钥"
#: users/models/user.py:602
#: users/models/user.py:607
msgid "Source"
msgstr "来源"
#: users/models/user.py:606
#: users/models/user.py:611
msgid "Date password last updated"
msgstr "最后更新密码日期"
#: users/models/user.py:609
#: users/models/user.py:614
msgid "Need update password"
msgstr "需要更新密码"
#: users/models/user.py:765
#: users/models/user.py:770
msgid "Administrator"
msgstr "管理员"
#: users/models/user.py:768
#: users/models/user.py:773
msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员"
@ -4218,7 +4253,7 @@ msgstr "Administrator是初始的超级管理员"
msgid "The old password is incorrect"
msgstr "旧密码错误"
#: users/serializers/profile.py:36 users/serializers/user.py:129
#: users/serializers/profile.py:36 users/serializers/user.py:137
msgid "Password does not match security rules"
msgstr "密码不满足安全规则"
@ -4230,88 +4265,80 @@ msgstr "新密码不能是最近 {} 次的密码"
msgid "The newly set password is inconsistent"
msgstr "两次密码不一致"
#: users/serializers/profile.py:120 users/serializers/user.py:79
#: users/serializers/profile.py:120 users/serializers/user.py:75
msgid "Is first login"
msgstr "首次登录"
#: users/serializers/user.py:22
msgid "Reset link will be generated and sent to the user"
msgstr "生成重置密码链接,通过邮件发送给用户"
#: users/serializers/user.py:23
msgid "Set password"
msgstr "设置密码"
#: users/serializers/user.py:27 xpack/plugins/change_auth_plan/models.py:65
#: users/serializers/user.py:22 xpack/plugins/change_auth_plan/models.py:65
#: xpack/plugins/change_auth_plan/serializers.py:33
msgid "Password strategy"
msgstr "密码策略"
#: users/serializers/user.py:29
#: users/serializers/user.py:24
msgid "MFA enabled"
msgstr "是否开启多因子认证"
#: users/serializers/user.py:30
#: users/serializers/user.py:25
msgid "MFA force enabled"
msgstr "强制启用多因子认证"
#: users/serializers/user.py:31
#: users/serializers/user.py:26
msgid "MFA level display"
msgstr "多因子认证等级名称"
#: users/serializers/user.py:32
#: users/serializers/user.py:27
msgid "Login blocked"
msgstr "登录被阻塞"
#: users/serializers/user.py:34
#: users/serializers/user.py:29
msgid "Can update"
msgstr "是否可更新"
#: users/serializers/user.py:35
#: users/serializers/user.py:30
msgid "Can delete"
msgstr "是否可删除"
#: users/serializers/user.py:38 users/serializers/user.py:86
#: users/serializers/user.py:33 users/serializers/user.py:82
msgid "Organization role name"
msgstr "组织角色名称"
#: users/serializers/user.py:82
#: users/serializers/user.py:78
msgid "Avatar url"
msgstr "头像路径"
#: users/serializers/user.py:84
#: users/serializers/user.py:80
msgid "Groups name"
msgstr "用户组名"
#: users/serializers/user.py:85
#: users/serializers/user.py:81
msgid "Source name"
msgstr "用户来源名"
#: users/serializers/user.py:87
#: users/serializers/user.py:83
msgid "Super role name"
msgstr "超级角色名称"
#: users/serializers/user.py:88
#: users/serializers/user.py:84
msgid "Total role name"
msgstr "汇总角色名称"
#: users/serializers/user.py:90
#: users/serializers/user.py:86
msgid "Is wecom bound"
msgstr "是否绑定了企业微信"
#: users/serializers/user.py:91
#: users/serializers/user.py:87
msgid "Is dingtalk bound"
msgstr "是否绑定了钉钉"
#: users/serializers/user.py:92
#: users/serializers/user.py:88
msgid "Is feishu bound"
msgstr "是否绑定了飞书"
#: users/serializers/user.py:115
#: users/serializers/user.py:111
msgid "Role limit to {}"
msgstr "角色只能为 {}"
#: users/serializers/user.py:214
#: users/serializers/user.py:221
msgid "name not unique"
msgstr "名称重复"
@ -4915,12 +4942,6 @@ msgstr "清空当前账号密钥再追加新密钥"
msgid "Password rules"
msgstr "密码规则"
#: xpack/plugins/change_auth_plan/models.py:78
#, fuzzy
#| msgid "Hostname strategy"
msgid "SSH key strategy"
msgstr "主机名策略"
#: xpack/plugins/change_auth_plan/models.py:189
msgid "Manual trigger"
msgstr "手动触发"
@ -4945,27 +4966,23 @@ msgstr "改密计划执行"
#: xpack/plugins/change_auth_plan/models.py:302
msgid "Ready"
msgstr ""
msgstr "准备"
#: xpack/plugins/change_auth_plan/models.py:303
msgid "Preflight check"
msgstr ""
msgstr "改密前的校验"
#: xpack/plugins/change_auth_plan/models.py:304
#, fuzzy
#| msgid "Change auth plan"
msgid "Change auth"
msgstr "改密计划"
msgstr "执行改密"
#: xpack/plugins/change_auth_plan/models.py:305
#, fuzzy
#| msgid "Verify password"
msgid "Verify auth"
msgstr "验密码"
msgstr "验证密码/密钥"
#: xpack/plugins/change_auth_plan/models.py:306
msgid "Keep auth"
msgstr ""
msgstr "保存密码/密钥"
#: xpack/plugins/change_auth_plan/models.py:307
msgid "Finished"
@ -4988,10 +5005,8 @@ msgid "Change SSH Key"
msgstr "修改密钥"
#: xpack/plugins/change_auth_plan/serializers.py:35
#, fuzzy
#| msgid "SSH Key Reset"
msgid "SSH Key strategy"
msgstr "重置SSH密钥"
msgstr "SSH Key 策略"
#: xpack/plugins/change_auth_plan/serializers.py:61
msgid "Run times"
@ -5138,16 +5153,12 @@ msgid "Hostname strategy"
msgstr "主机名策略"
#: xpack/plugins/cloud/models.py:97 xpack/plugins/cloud/serializers.py:208
#, fuzzy
#| msgid "Only admin users"
msgid "Unix admin user"
msgstr "仅管理员"
msgstr "Unix 特权用户"
#: xpack/plugins/cloud/models.py:101 xpack/plugins/cloud/serializers.py:209
#, fuzzy
#| msgid "Only admin users"
msgid "Windows admin user"
msgstr "仅管理员"
msgstr "Windows 特权用户"
#: xpack/plugins/cloud/models.py:107 xpack/plugins/cloud/serializers.py:187
msgid "IP network segment group"
@ -5322,40 +5333,28 @@ msgid "EU-Paris"
msgstr "欧洲-巴黎"
#: xpack/plugins/cloud/serializers.py:21
#, fuzzy
#| msgid "Access key"
msgid "AccessKey ID"
msgstr "Access key"
msgstr ""
#: xpack/plugins/cloud/serializers.py:24
#, fuzzy
#| msgid "Access key"
msgid "AccessKey Secret"
msgstr "Access key"
msgstr ""
#: xpack/plugins/cloud/serializers.py:30
msgid "Client ID"
msgstr ""
msgstr "客户端 ID"
#: xpack/plugins/cloud/serializers.py:33
#, fuzzy
#| msgid "Secret"
msgid "Client Secret"
msgstr "钥"
msgstr "客户端密钥"
#: xpack/plugins/cloud/serializers.py:36
msgid "Tenant ID"
msgstr ""
msgstr "租户 ID"
#: xpack/plugins/cloud/serializers.py:39
#, fuzzy
#| msgid "Session ID"
msgid "Subscription ID"
msgstr "会话ID"
#: xpack/plugins/cloud/serializers.py:51
msgid "This field is required"
msgstr "这个字段是必填项"
msgstr "订阅 ID"
#: xpack/plugins/cloud/serializers.py:85 xpack/plugins/cloud/serializers.py:89
msgid "API Endpoint"

View File

@ -92,7 +92,7 @@ class Message(metaclass=MessageType):
def get_email_msg(self) -> dict:
msg = self.get_common_msg()
subject = f'{msg[:20]} ...' if len(msg) >= 20 else msg
subject = f'{msg[:80]} ...' if len(msg) >= 80 else msg
return {
'subject': subject,
'message': msg

View File

@ -33,7 +33,7 @@ class ServerPerformanceCheckUtil(object):
'is_alive': {
'default': False,
'max_threshold': False,
'alarm_msg_format': _('[Alive] The terminal is offline: {name}')
'alarm_msg_format': _('The terminal is offline: {name}')
},
'disk_usage': {
'default': 0,

View File

@ -54,8 +54,8 @@ class OrgResourceStatisticsCache(OrgRelatedCache):
assets_amount = IntegerField()
nodes_amount = IntegerField(queryset=Node.objects)
admin_users_amount = IntegerField(queryset=SystemUser.objects.filter(type=SystemUser.Type.admin))
system_users_amount = IntegerField(queryset=SystemUser.objects.filter(type=SystemUser.Type.common))
admin_users_amount = IntegerField()
system_users_amount = IntegerField()
domains_amount = IntegerField(queryset=Domain.objects)
gateways_amount = IntegerField(queryset=Gateway.objects)
@ -77,6 +77,12 @@ class OrgResourceStatisticsCache(OrgRelatedCache):
def get_current_org(self):
return self.org
def compute_admin_users_amount(self):
return SystemUser.objects.filter(type=SystemUser.Type.admin).count()
def compute_system_users_amount(self):
return SystemUser.objects.filter(type=SystemUser.Type.common).count()
def compute_users_amount(self):
users = User.objects.exclude(role='App')

View File

@ -160,6 +160,10 @@ class SecuritySettingSerializer(serializers.Serializer):
required=True, label=_('Enable terminal register'),
help_text=_("Allow terminal register, after all terminal setup, you should disable this for security")
)
SECURITY_WATERMARK_ENABLED = serializers.BooleanField(
required=True, label=_('Replay watermark'),
help_text=_('Enabled, the session replay contains watermark information')
)
SECURITY_LOGIN_LIMIT_COUNT = serializers.IntegerField(
min_value=3, max_value=99999,
label=_('Limit the number of login failures')

View File

@ -22,7 +22,7 @@ from ..serializers import UserSerializer, UserRetrieveSerializer, MiniUserSerial
from .mixins import UserQuerysetMixin
from ..models import User
from ..signals import post_user_create
from ..filters import OrgRoleUserFilterBackend
from ..filters import OrgRoleUserFilterBackend, UserFilter
logger = get_logger(__name__)
__all__ = [
@ -32,8 +32,8 @@ __all__ = [
class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
filterset_fields = ('username', 'email', 'name', 'id', 'source', 'role')
search_fields = filterset_fields
filterset_class = UserFilter
search_fields = ('username', 'email', 'name', 'id', 'source', 'role')
permission_classes = (IsOrgAdmin, CanUpdateDeleteUser)
serializer_classes = {
'default': UserSerializer,

19
apps/users/const.py Normal file
View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
#
from django.db.models import TextChoices
from django.utils.translation import ugettext_lazy as _
TICKET_DETAIL_URL = '/ui/#/tickets/tickets/{id}'
class SystemOrOrgRole(TextChoices):
SYSTEM_ADMIN = 'system_admin', _('System administrator')
SYSTEM_AUDITOR = 'system_auditor', _('System auditor')
ORG_ADMIN = 'org_admin', _('Organization administrator')
ORG_AUDITOR = 'org_auditor', _("Organization auditor")
USER = 'user', _('User')
class PasswordStrategy(TextChoices):
email = 'email', _('Reset link will be generated and sent to the user')
custom = 'custom', _('Set password')

View File

@ -1,11 +1,15 @@
from django_filters import rest_framework as filters
from django.db.models import Q
from rest_framework.compat import coreapi, coreschema
from rest_framework import filters
from rest_framework.filters import BaseFilterBackend
from common.drf.filters import BaseFilterSet
from users.models.user import User
from users.const import SystemOrOrgRole
from orgs.utils import current_org
class OrgRoleUserFilterBackend(filters.BaseFilterBackend):
class OrgRoleUserFilterBackend(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
org_role = request.query_params.get('org_role')
if not org_role:
@ -30,3 +34,30 @@ class OrgRoleUserFilterBackend(filters.BaseFilterBackend):
)
)
]
class UserFilter(BaseFilterSet):
system_or_org_role = filters.ChoiceFilter(choices=SystemOrOrgRole.choices, method='filter_system_or_org_role')
class Meta:
model = User
fields = (
'id', 'username', 'email', 'name', 'source', 'system_or_org_role'
)
def filter_system_or_org_role(self, queryset, name, value):
value = value.split('_')
if len(value) == 1:
role_type, value = None, value[0]
else:
role_type, value = value
value = value.title()
system_queries = Q(role=value)
org_queries = Q(m2m_org_members__role=value, m2m_org_members__org_id=current_org.id)
if not role_type:
queries = system_queries | org_queries
elif role_type == 'system':
queries = system_queries
elif role_type == 'org':
queries = org_queries
return queryset.filter(queries)

View File

@ -2,14 +2,13 @@
#
from django.core.cache import cache
from django.utils.translation import ugettext_lazy as _
from django.db.models import TextChoices
from rest_framework import serializers
from common.mixins import CommonBulkSerializerMixin
from common.permissions import CanUpdateDeleteUser
from orgs.models import ROLE as ORG_ROLE
from ..models import User
from ..const import SystemOrOrgRole, PasswordStrategy
__all__ = [
'UserSerializer', 'UserRetrieveSerializer', 'MiniUserSerializer',
@ -18,10 +17,6 @@ __all__ = [
class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
class PasswordStrategy(TextChoices):
email = 'email', _('Reset link will be generated and sent to the user')
custom = 'custom', _('Set password')
password_strategy = serializers.ChoiceField(
choices=PasswordStrategy.choices, default=PasswordStrategy.email, required=False,
write_only=True, label=_('Password strategy')
@ -38,6 +33,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
label=_('Organization role name'), allow_null=True, required=False,
child=serializers.ChoiceField(choices=ORG_ROLE.choices), default=["User"]
)
system_or_org_role = serializers.ChoiceField(read_only=True, choices=SystemOrOrgRole.choices, label=_('Role'))
class Meta:
model = User
@ -60,7 +56,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
fields_verbose = fields_small + [
'total_role_display', 'org_role_display',
'mfa_level_display', 'mfa_force_enabled', 'is_first_login',
'date_password_last_updated', 'avatar_url',
'date_password_last_updated', 'avatar_url', 'system_or_org_role'
]
# 外键的字段
fields_fk = ['role', 'role_display']
@ -196,7 +192,6 @@ class InviteSerializer(serializers.Serializer):
class ServiceAccountSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'name', 'access_key']