diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index c5b96696c..080d1a348 100644 Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index b0e758446..66fb19a2a 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-14 16:50+0800\n" +"POT-Creation-Date: 2020-08-19 17:34+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -29,7 +29,7 @@ msgstr "自定义" #: orgs/models.py:22 perms/models/base.py:48 settings/models.py:27 #: terminal/models.py:27 terminal/models.py:344 terminal/models.py:376 #: terminal/models.py:413 users/forms/profile.py:20 users/models/group.py:15 -#: users/models/user.py:489 users/templates/users/_select_user_modal.html:13 +#: users/models/user.py:495 users/templates/users/_select_user_modal.html:13 #: users/templates/users/user_asset_permission.html:37 #: users/templates/users/user_asset_permission.html:154 #: users/templates/users/user_database_app_permission.html:36 @@ -79,7 +79,7 @@ msgstr "数据库" #: assets/models/label.py:23 ops/models/adhoc.py:37 orgs/models.py:25 #: perms/models/base.py:56 settings/models.py:32 terminal/models.py:37 #: terminal/models.py:383 terminal/models.py:420 users/models/group.py:16 -#: users/models/user.py:522 users/templates/users/user_detail.html:115 +#: users/models/user.py:528 users/templates/users/user_detail.html:115 #: users/templates/users/user_granted_database_app.html:38 #: users/templates/users/user_granted_remote_app.html:37 #: users/templates/users/user_group_detail.html:62 @@ -146,8 +146,8 @@ msgstr "参数" #: assets/models/base.py:240 assets/models/cluster.py:28 #: assets/models/cmd_filter.py:26 assets/models/cmd_filter.py:60 #: assets/models/group.py:21 common/db/models.py:67 common/mixins/models.py:49 -#: orgs/models.py:23 orgs/models.py:326 perms/models/base.py:54 -#: users/models/user.py:530 users/serializers/group.py:35 +#: orgs/models.py:23 orgs/models.py:374 perms/models/base.py:54 +#: users/models/user.py:536 users/serializers/group.py:35 #: users/templates/users/user_detail.html:97 #: xpack/plugins/change_auth_plan/models.py:81 xpack/plugins/cloud/models.py:56 #: xpack/plugins/cloud/models.py:146 xpack/plugins/gathered_user/models.py:30 @@ -161,7 +161,7 @@ msgstr "创建者" #: assets/models/domain.py:23 assets/models/gathered_user.py:19 #: assets/models/group.py:22 assets/models/label.py:25 common/db/models.py:69 #: common/mixins/models.py:50 ops/models/adhoc.py:38 ops/models/command.py:27 -#: orgs/models.py:24 orgs/models.py:324 perms/models/base.py:55 +#: orgs/models.py:24 orgs/models.py:372 perms/models/base.py:55 #: users/models/group.py:18 users/templates/users/user_group_detail.html:58 #: xpack/plugins/cloud/models.py:59 xpack/plugins/cloud/models.py:149 msgid "Date created" @@ -354,7 +354,7 @@ msgstr "" #: audits/models.py:99 authentication/forms.py:11 #: authentication/templates/authentication/login.html:21 #: authentication/templates/authentication/xpack_login.html:101 -#: ops/models/adhoc.py:148 users/forms/profile.py:19 users/models/user.py:487 +#: ops/models/adhoc.py:148 users/forms/profile.py:19 users/models/user.py:493 #: users/templates/users/_select_user_modal.html:14 #: users/templates/users/user_detail.html:53 #: users/templates/users/user_list.html:15 @@ -395,7 +395,7 @@ msgstr "SSH公钥" #: assets/models/base.py:239 assets/models/gathered_user.py:20 #: common/db/models.py:70 common/mixins/models.py:51 ops/models/adhoc.py:39 -#: orgs/models.py:325 +#: orgs/models.py:373 msgid "Date updated" msgstr "更新日期" @@ -407,7 +407,7 @@ msgstr "带宽" msgid "Contact" msgstr "联系人" -#: assets/models/cluster.py:22 users/models/user.py:508 +#: assets/models/cluster.py:22 users/models/user.py:514 #: users/templates/users/user_detail.html:62 msgid "Phone" msgstr "手机" @@ -433,7 +433,7 @@ msgid "Default" msgstr "默认" #: assets/models/cluster.py:36 assets/models/label.py:14 -#: users/models/user.py:655 +#: users/models/user.py:661 msgid "System" msgstr "系统" @@ -547,7 +547,7 @@ msgstr "默认资产组" #: assets/models/label.py:15 audits/models.py:36 audits/models.py:56 #: audits/models.py:69 audits/serializers.py:77 authentication/models.py:46 -#: authentication/models.py:90 orgs/models.py:16 orgs/models.py:322 +#: authentication/models.py:90 orgs/models.py:370 #: perms/forms/asset_permission.py:83 perms/forms/database_app_permission.py:38 #: perms/forms/remote_app_permission.py:40 perms/models/base.py:49 #: templates/index.html:78 terminal/backends/command/models.py:18 @@ -555,8 +555,7 @@ msgstr "默认资产组" #: tickets/models/ticket.py:30 tickets/models/ticket.py:137 #: tickets/serializers/request_asset_perm.py:65 #: tickets/serializers/ticket.py:31 users/forms/group.py:15 -#: users/models/user.py:157 users/models/user.py:643 -#: users/serializers/group.py:20 +#: users/models/user.py:649 users/serializers/group.py:20 #: users/templates/users/user_asset_permission.html:38 #: users/templates/users/user_asset_permission.html:64 #: users/templates/users/user_database_app_permission.html:37 @@ -733,14 +732,14 @@ msgid "Backend" msgstr "后端" #: assets/serializers/asset_user.py:75 users/forms/profile.py:148 -#: users/models/user.py:519 users/templates/users/user_password_update.html:48 +#: users/models/user.py:525 users/templates/users/user_password_update.html:48 #: users/templates/users/user_profile.html:69 #: users/templates/users/user_profile_update.html:46 #: users/templates/users/user_pubkey_update.html:46 msgid "Public key" msgstr "SSH公钥" -#: assets/serializers/asset_user.py:79 users/models/user.py:516 +#: assets/serializers/asset_user.py:79 users/models/user.py:522 msgid "Private key" msgstr "ssh私钥" @@ -1025,7 +1024,7 @@ msgstr "Agent" #: audits/models.py:104 #: authentication/templates/authentication/_mfa_confirm_modal.html:14 #: authentication/templates/authentication/login_otp.html:6 -#: users/forms/profile.py:52 users/models/user.py:511 +#: users/forms/profile.py:52 users/models/user.py:517 #: users/serializers/user.py:240 users/templates/users/user_detail.html:77 #: users/templates/users/user_profile.html:87 msgid "MFA" @@ -1265,7 +1264,7 @@ msgid "Show" msgstr "显示" #: authentication/templates/authentication/_access_key_modal.html:66 -#: users/models/user.py:409 users/serializers/user.py:237 +#: users/models/user.py:415 users/serializers/user.py:237 #: users/templates/users/user_profile.html:94 #: users/templates/users/user_profile.html:163 #: users/templates/users/user_profile.html:166 @@ -1274,7 +1273,7 @@ msgid "Disable" msgstr "禁用" #: authentication/templates/authentication/_access_key_modal.html:67 -#: users/models/user.py:410 users/serializers/user.py:238 +#: users/models/user.py:416 users/serializers/user.py:238 #: users/templates/users/user_profile.html:92 #: users/templates/users/user_profile.html:170 msgid "Enable" @@ -1685,7 +1684,7 @@ msgid "The current organization cannot be deleted" msgstr "" #: orgs/mixins/models.py:56 orgs/mixins/serializers.py:25 orgs/models.py:40 -#: orgs/models.py:321 +#: orgs/models.py:369 msgid "Organization" msgstr "组织" @@ -1693,11 +1692,15 @@ msgstr "组织" msgid "Organization administrator" msgstr "组织管理员" +#: orgs/models.py:16 +msgid "Organization User" +msgstr "组织用户" + #: orgs/models.py:17 msgid "Organization auditor" msgstr "组织审计员" -#: orgs/models.py:323 users/forms/user.py:27 users/models/user.py:499 +#: orgs/models.py:371 users/forms/user.py:27 users/models/user.py:505 #: users/templates/users/_select_user_modal.html:15 #: users/templates/users/user_detail.html:73 #: users/templates/users/user_list.html:16 @@ -1722,7 +1725,7 @@ msgstr "提示:RDP 协议不支持单独控制上传或下载文件" #: perms/forms/asset_permission.py:86 perms/forms/database_app_permission.py:41 #: perms/forms/remote_app_permission.py:43 perms/models/base.py:50 #: templates/_nav.html:21 users/forms/user.py:168 users/models/group.py:31 -#: users/models/user.py:495 users/serializers/user.py:49 +#: users/models/user.py:501 users/serializers/user.py:48 #: users/templates/users/_select_user_modal.html:16 #: users/templates/users/user_asset_permission.html:39 #: users/templates/users/user_asset_permission.html:67 @@ -1789,7 +1792,7 @@ msgid "Asset permission" msgstr "资产授权" #: perms/models/base.py:53 tickets/serializers/request_asset_perm.py:31 -#: users/models/user.py:527 users/templates/users/user_detail.html:93 +#: users/models/user.py:533 users/templates/users/user_detail.html:93 #: users/templates/users/user_profile.html:120 msgid "Date expired" msgstr "失效日期" @@ -2537,36 +2540,37 @@ msgstr "结束日期" msgid "Args" msgstr "参数" -#: tickets/api/request_asset_perm.py:45 +#: tickets/api/request_asset_perm.py:46 #, python-format msgid "Ticket has %s" msgstr "工单已%s" -#: tickets/api/request_asset_perm.py:90 +#: tickets/api/request_asset_perm.py:91 msgid "Confirm assets first" msgstr "请先确认资产" -#: tickets/api/request_asset_perm.py:93 +#: tickets/api/request_asset_perm.py:94 msgid "Confirmed assets changed" msgstr "确认的资产变更了" -#: tickets/api/request_asset_perm.py:97 +#: tickets/api/request_asset_perm.py:98 msgid "Confirm system-user first" msgstr "请先确认系统用户" -#: tickets/api/request_asset_perm.py:101 +#: tickets/api/request_asset_perm.py:102 msgid "Confirmed system-user changed" msgstr "确认的系统用户变更了" -#: tickets/api/request_asset_perm.py:104 xpack/plugins/cloud/models.py:202 +#: tickets/api/request_asset_perm.py:105 tickets/api/request_asset_perm.py:112 +#: xpack/plugins/cloud/models.py:202 msgid "Succeed" msgstr "成功" -#: tickets/api/request_asset_perm.py:112 +#: tickets/api/request_asset_perm.py:120 msgid "From request ticket: {} {}" msgstr "来自工单申请: {} {}" -#: tickets/api/request_asset_perm.py:114 +#: tickets/api/request_asset_perm.py:122 msgid "{} request assets, approved by {}" msgstr "{} 申请资产,通过人 {}" @@ -2749,7 +2753,7 @@ msgstr "" " \n" " " -#: users/api/user.py:147 +#: users/api/user.py:158 msgid "Could not reset self otp, use profile reset instead" msgstr "不能在该页面重置多因子认证, 请去个人信息页面重置" @@ -2795,7 +2799,7 @@ msgstr "确认密码" msgid "Password does not match" msgstr "密码不一致" -#: users/forms/profile.py:89 users/models/user.py:491 +#: users/forms/profile.py:89 users/models/user.py:497 #: users/templates/users/user_detail.html:57 #: users/templates/users/user_profile.html:59 msgid "Email" @@ -2836,7 +2840,7 @@ msgstr "不能和原来的密钥相同" msgid "Not a valid ssh public key" msgstr "SSH密钥不合法" -#: users/forms/user.py:31 users/models/user.py:534 +#: users/forms/user.py:31 users/models/user.py:540 #: users/templates/users/user_detail.html:89 #: users/templates/users/user_list.html:18 #: users/templates/users/user_profile.html:102 @@ -2856,15 +2860,15 @@ msgstr "添加到用户组" msgid "* Your password does not meet the requirements" msgstr "* 您的密码不符合要求" -#: users/forms/user.py:124 users/serializers/user.py:37 +#: users/forms/user.py:124 users/serializers/user.py:36 msgid "Reset link will be generated and sent to the user" msgstr "生成重置密码链接,通过邮件发送给用户" -#: users/forms/user.py:125 users/serializers/user.py:38 +#: users/forms/user.py:125 users/serializers/user.py:37 msgid "Set password" msgstr "设置密码" -#: users/forms/user.py:132 users/serializers/user.py:45 +#: users/forms/user.py:132 users/serializers/user.py:44 #: xpack/plugins/change_auth_plan/models.py:61 #: xpack/plugins/change_auth_plan/serializers.py:30 msgid "Password strategy" @@ -2874,6 +2878,10 @@ msgstr "密码策略" msgid "System administrator" msgstr "系统管理员" +#: users/models/user.py:157 +msgid "System User" +msgstr "系统用户" + #: users/models/user.py:158 msgid "System auditor" msgstr "系统审计员" @@ -2882,67 +2890,67 @@ msgstr "系统审计员" msgid "Application" msgstr "应用程序" -#: users/models/user.py:411 users/templates/users/user_profile.html:90 +#: users/models/user.py:417 users/templates/users/user_profile.html:90 msgid "Force enable" msgstr "强制启用" -#: users/models/user.py:478 +#: users/models/user.py:484 msgid "Local" msgstr "数据库" -#: users/models/user.py:502 +#: users/models/user.py:508 msgid "Avatar" msgstr "头像" -#: users/models/user.py:505 users/templates/users/user_detail.html:68 +#: users/models/user.py:511 users/templates/users/user_detail.html:68 msgid "Wechat" msgstr "微信" -#: users/models/user.py:538 +#: users/models/user.py:544 msgid "Date password last updated" msgstr "最后更新密码日期" -#: users/models/user.py:651 +#: users/models/user.py:657 msgid "Administrator" msgstr "管理员" -#: users/models/user.py:654 +#: users/models/user.py:660 msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员" -#: users/serializers/user.py:55 users/serializers/user.py:93 +#: users/serializers/user.py:53 users/serializers/user.py:88 msgid "Organization role name" msgstr "组织角色名称" -#: users/serializers/user.py:59 +#: users/serializers/user.py:55 msgid "Total role name" msgstr "汇总角色名称" -#: users/serializers/user.py:84 users/serializers/user.py:253 +#: users/serializers/user.py:79 users/serializers/user.py:253 msgid "Is first login" msgstr "首次登录" -#: users/serializers/user.py:85 +#: users/serializers/user.py:80 msgid "Is valid" msgstr "账户是否有效" -#: users/serializers/user.py:86 +#: users/serializers/user.py:81 msgid "Is expired" msgstr " 是否过期" -#: users/serializers/user.py:87 +#: users/serializers/user.py:82 msgid "Avatar url" msgstr "头像路径" -#: users/serializers/user.py:91 +#: users/serializers/user.py:86 msgid "Groups name" msgstr "用户组名" -#: users/serializers/user.py:92 +#: users/serializers/user.py:87 msgid "Source name" msgstr "用户来源名" -#: users/serializers/user.py:94 +#: users/serializers/user.py:89 msgid "Super role name" msgstr "超级角色名称" diff --git a/apps/orgs/migrations/0008_auto_20200819_1732.py b/apps/orgs/migrations/0008_auto_20200819_1732.py new file mode 100644 index 000000000..75a773626 --- /dev/null +++ b/apps/orgs/migrations/0008_auto_20200819_1732.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.13 on 2020-08-19 09:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('orgs', '0007_auto_20200728_1805'), + ] + + operations = [ + migrations.AlterField( + model_name='organizationmember', + name='role', + field=models.CharField(choices=[('Admin', 'Organization administrator'), ('User', 'Organization User'), ('Auditor', 'Organization auditor')], default='User', max_length=16, verbose_name='Role'), + ), + ] diff --git a/apps/orgs/models.py b/apps/orgs/models.py index c72d1ae82..1769787a4 100644 --- a/apps/orgs/models.py +++ b/apps/orgs/models.py @@ -13,7 +13,7 @@ from common.db.models import ChoiceSet class ROLE(ChoiceSet): ADMIN = choices.ADMIN, _('Organization administrator') - USER = choices.USER, _('User') + USER = choices.USER, _('Organization User') AUDITOR = choices.AUDITOR, _("Organization auditor") @@ -229,15 +229,29 @@ def _none2list(*args): return ([] if v is None else v for v in args) +class UserRoleMapper(dict): + def __init__(self, container=set): + super().__init__() + self.users = container() + self.admins = container() + self.auditors = container() + + self[ROLE.USER] = self.users + self[ROLE.ADMIN] = self.admins + self[ROLE.AUDITOR] = self.auditors + + class OrgMemeberManager(models.Manager): def remove_users_by_role(self, org, users=None, admins=None, auditors=None): + from users.models import User + if not any((users, admins, auditors)): return users, admins, auditors = _none2list(users, admins, auditors) send = partial(signals.m2m_changed.send, sender=self.model, instance=org, reverse=False, - model=Organization, pk_set=[*users, *admins, *auditors], using=self.db) + model=User, pk_set=[*users, *admins, *auditors], using=self.db) send(action="pre_remove") self.filter(org_id=org.id).filter( @@ -248,6 +262,8 @@ class OrgMemeberManager(models.Manager): send(action="post_remove") def add_users_by_role(self, org, users=None, admins=None, auditors=None): + from users.models import User + if not any((users, admins, auditors)): return users, admins, auditors = _none2list(users, admins, auditors) @@ -266,7 +282,7 @@ class OrgMemeberManager(models.Manager): oms_add.append(self.model(org_id=org.id, user_id=user, role=role)) send = partial(signals.m2m_changed.send, sender=self.model, instance=org, reverse=False, - model=Organization, pk_set=[*users, *admins, *auditors], using=self.db) + model=User, pk_set=[*users, *admins, *auditors], using=self.db) send(action='pre_add') self.bulk_create(oms_add) @@ -278,24 +294,56 @@ class OrgMemeberManager(models.Manager): new_users = _convert_to_uuid_set(new_users) return (old_users - new_users), (new_users - old_users) + def set_user_roles(self, org, user, roles): + """ + 设置某个用户在某个组织里的角色 + """ + old_roles = set(self.filter(org_id=org.id, user=user).values_list('role', flat=True)) + new_roles = set(roles) + + roles_remove = old_roles - new_roles + roles_add = new_roles - old_roles + + to_remove = UserRoleMapper() + to_add = UserRoleMapper() + + for role in roles_remove: + if role in to_remove: + to_remove[role].add(user) + for role in roles_add: + if role in to_add: + to_add[role].add(user) + + self.remove_users_by_role( + org, + to_remove.users, + to_remove.admins, + to_remove.auditors + ) + + self.add_users_by_role( + org, + to_add.users, + to_add.admins, + to_add.auditors + ) + def set_users_by_role(self, org, users=None, admins=None, auditors=None): + """ + 给组织设置带角色的用户 + """ + oms = self.filter(org_id=org.id).values_list('role', 'user_id') - old_users, old_admins, old_auditors = set(), set(), set() - - mapper = { - ROLE.USER: old_users, - ROLE.ADMIN: old_admins, - ROLE.AUDITOR: old_auditors - } + old_mapper = UserRoleMapper() for role, user_id in oms: - if role in mapper: - mapper[role].add(user_id) + if role in old_mapper: + old_mapper[role].add(user_id) - users_remove, users_add = self._get_remove_add_set(users, old_users) - admins_remove, admins_add = self._get_remove_add_set(admins, old_admins) - auditors_remove, auditors_add = self._get_remove_add_set(auditors, old_auditors) + users_remove, users_add = self._get_remove_add_set(users, old_mapper.users) + admins_remove, admins_add = self._get_remove_add_set(admins, old_mapper.admins) + auditors_remove, auditors_add = self._get_remove_add_set(auditors, old_mapper.auditors) self.remove_users_by_role( org, diff --git a/apps/users/api/user.py b/apps/users/api/user.py index b1c039318..ae4550931 100644 --- a/apps/users/api/user.py +++ b/apps/users/api/user.py @@ -56,31 +56,25 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet): def perform_create(self, serializer): validated_data = serializer.validated_data - if isinstance(validated_data, list): - org_roles = [item.pop('org_role', None) for item in validated_data] - else: - org_roles = [validated_data.pop('org_role', None)] + # `org_roles` 先 `pop` + if isinstance(validated_data, list): + org_roles = [item.pop('org_roles', []) for item in validated_data] + else: + org_roles = [validated_data.pop('org_roles', [])] + + # 创建用户 users = serializer.save() if isinstance(users, User): users = [users] - if current_org and current_org.is_real(): - mapper = { - ORG_ROLE.USER: [], - ORG_ROLE.ADMIN: [], - ORG_ROLE.AUDITOR: [] - } - for user, role in zip(users, org_roles): - if role in mapper: - mapper[role].append(user) - else: - mapper[ORG_ROLE.USER].append(user) - OrganizationMember.objects.set_users_by_role( - current_org, users=mapper[ORG_ROLE.USER], - admins=mapper[ORG_ROLE.ADMIN], - auditors=mapper[ORG_ROLE.AUDITOR] - ) + # 只有真实存在的组织才真正关联用户 + if current_org and current_org.is_real(): + for user, roles in zip(users, org_roles): + if not roles: + # 当前组织创建的用户,至少是该组织的`User` + roles.append(ORG_ROLE.USER) + OrganizationMember.objects.set_user_roles(current_org, user, roles) self.send_created_signal(users) def get_permissions(self): @@ -101,6 +95,23 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet): self.check_object_permissions(self.request, obj) self.perform_destroy(obj) + def perform_update(self, serializer): + validated_data = serializer.validated_data + # `org_roles` 先 `pop` + if isinstance(validated_data, list): + org_roles = [item.pop('org_roles', None) for item in validated_data] + else: + org_roles = [validated_data.pop('org_roles', None)] + + users = serializer.save() + if isinstance(users, User): + users = [users] + if current_org and current_org.is_real(): + for user, roles in zip(users, org_roles): + if roles is not None: + # roles 是 `Node` 表明不需要更新 + OrganizationMember.objects.set_user_roles(current_org, user, roles) + def perform_bulk_update(self, serializer): # TODO: 需要测试 users_ids = [ diff --git a/apps/users/models/user.py b/apps/users/models/user.py index b496f17bd..7a4dc2a4f 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -154,7 +154,7 @@ class AuthMixin: class RoleMixin: class ROLE(ChoiceSet): ADMIN = choices.ADMIN, _('System administrator') - USER = choices.USER, _('User') + USER = choices.USER, _('System User') AUDITOR = choices.AUDITOR, _('System auditor') APP = 'App', _('Application') @@ -164,15 +164,15 @@ class RoleMixin: def role_display(self): return self.get_role_display() - @property - def org_role_display(self): + @lazyproperty + def org_roles(self): from orgs.models import ROLE as ORG_ROLE if not current_org.is_real(): if self.is_superuser: - return ORG_ROLE.ADMIN.label + return [ORG_ROLE.ADMIN] else: - return ORG_ROLE.USER.label + return [ORG_ROLE.USER] if hasattr(self, 'gc_m2m_org_members__role'): names = self.gc_m2m_org_members__role @@ -184,8 +184,14 @@ class RoleMixin: roles = set(self.m2m_org_members.filter( org_id=current_org.id ).values_list('role', flat=True)) + roles = list(roles) + roles.sort() + return roles - return ' | '.join([str(ORG_ROLE[role]) for role in roles if role in ORG_ROLE]) + @lazyproperty + def org_role_display(self): + from orgs.models import ROLE as ORG_ROLE + return ' | '.join([str(ORG_ROLE[role]) for role in self.org_roles if role in ORG_ROLE]) def current_org_roles(self): from orgs.models import OrganizationMember, ROLE as ORG_ROLE diff --git a/apps/users/serializers/user.py b/apps/users/serializers/user.py index e246ba203..6d8caaf8a 100644 --- a/apps/users/serializers/user.py +++ b/apps/users/serializers/user.py @@ -7,7 +7,6 @@ from rest_framework import serializers from common.utils import validate_ssh_public_key from common.mixins import CommonBulkSerializerMixin -from common.serializers import AdaptedBulkListSerializer from common.permissions import CanUpdateDeleteUser from common.drf.fields import GroupConcatedPrimaryKeyRelatedField from orgs.models import ROLE as ORG_ROLE @@ -51,17 +50,13 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer): login_blocked = serializers.SerializerMethodField() can_update = serializers.SerializerMethodField() can_delete = serializers.SerializerMethodField() - org_role = serializers.ChoiceField( - label=_('Organization role name'), write_only=True, - allow_null=True, required=False, allow_blank=True, - choices=ORG_ROLE.choices - ) + org_roles = serializers.ListField(label=_('Organization role name'), allow_null=True, required=False, + child=serializers.ChoiceField(choices=ORG_ROLE.choices)) total_role_display = serializers.SerializerMethodField(label=_('Total role name')) key_prefix_block = "_LOGIN_BLOCK_{}" class Meta: model = User - list_serializer_class = AdaptedBulkListSerializer # mini 是指能识别对象的最小单元 fields_mini = ['id', 'name', 'username'] # small 指的是 不需要计算的直接能从一张表中获取到的数据 @@ -75,7 +70,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer): ] fields = fields_small + [ 'groups', 'role', 'groups_display', 'role_display', - 'can_update', 'can_delete', 'login_blocked', 'org_role' + 'can_update', 'can_delete', 'login_blocked', 'org_roles' ] extra_kwargs = {