fix(users): 用户接口添加`org_roles`字段

pull/4517/head
xinwen 2020-08-19 17:38:21 +08:00 committed by 老广
parent 11493b9f3d
commit 64d093e677
7 changed files with 187 additions and 101 deletions

Binary file not shown.

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n" "Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n" "Language-Team: JumpServer team<ibuler@qq.com>\n"
@ -29,7 +29,7 @@ msgstr "自定义"
#: orgs/models.py:22 perms/models/base.py:48 settings/models.py:27 #: 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:27 terminal/models.py:344 terminal/models.py:376
#: terminal/models.py:413 users/forms/profile.py:20 users/models/group.py:15 #: 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:37
#: users/templates/users/user_asset_permission.html:154 #: users/templates/users/user_asset_permission.html:154
#: users/templates/users/user_database_app_permission.html:36 #: 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 #: 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 #: 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 #: 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_database_app.html:38
#: users/templates/users/user_granted_remote_app.html:37 #: users/templates/users/user_granted_remote_app.html:37
#: users/templates/users/user_group_detail.html:62 #: 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/base.py:240 assets/models/cluster.py:28
#: assets/models/cmd_filter.py:26 assets/models/cmd_filter.py:60 #: 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 #: 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 #: orgs/models.py:23 orgs/models.py:374 perms/models/base.py:54
#: users/models/user.py:530 users/serializers/group.py:35 #: users/models/user.py:536 users/serializers/group.py:35
#: users/templates/users/user_detail.html:97 #: users/templates/users/user_detail.html:97
#: xpack/plugins/change_auth_plan/models.py:81 xpack/plugins/cloud/models.py:56 #: 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 #: 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/domain.py:23 assets/models/gathered_user.py:19
#: assets/models/group.py:22 assets/models/label.py:25 common/db/models.py:69 #: 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 #: 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 #: 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 #: xpack/plugins/cloud/models.py:59 xpack/plugins/cloud/models.py:149
msgid "Date created" msgid "Date created"
@ -354,7 +354,7 @@ msgstr ""
#: audits/models.py:99 authentication/forms.py:11 #: audits/models.py:99 authentication/forms.py:11
#: authentication/templates/authentication/login.html:21 #: authentication/templates/authentication/login.html:21
#: authentication/templates/authentication/xpack_login.html:101 #: 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/_select_user_modal.html:14
#: users/templates/users/user_detail.html:53 #: users/templates/users/user_detail.html:53
#: users/templates/users/user_list.html:15 #: users/templates/users/user_list.html:15
@ -395,7 +395,7 @@ msgstr "SSH公钥"
#: assets/models/base.py:239 assets/models/gathered_user.py:20 #: 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 #: 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" msgid "Date updated"
msgstr "更新日期" msgstr "更新日期"
@ -407,7 +407,7 @@ msgstr "带宽"
msgid "Contact" msgid "Contact"
msgstr "联系人" 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 #: users/templates/users/user_detail.html:62
msgid "Phone" msgid "Phone"
msgstr "手机" msgstr "手机"
@ -433,7 +433,7 @@ msgid "Default"
msgstr "默认" msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:14 #: assets/models/cluster.py:36 assets/models/label.py:14
#: users/models/user.py:655 #: users/models/user.py:661
msgid "System" msgid "System"
msgstr "系统" msgstr "系统"
@ -547,7 +547,7 @@ msgstr "默认资产组"
#: assets/models/label.py:15 audits/models.py:36 audits/models.py:56 #: 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 #: 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/asset_permission.py:83 perms/forms/database_app_permission.py:38
#: perms/forms/remote_app_permission.py:40 perms/models/base.py:49 #: perms/forms/remote_app_permission.py:40 perms/models/base.py:49
#: templates/index.html:78 terminal/backends/command/models.py:18 #: 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/models/ticket.py:30 tickets/models/ticket.py:137
#: tickets/serializers/request_asset_perm.py:65 #: tickets/serializers/request_asset_perm.py:65
#: tickets/serializers/ticket.py:31 users/forms/group.py:15 #: tickets/serializers/ticket.py:31 users/forms/group.py:15
#: users/models/user.py:157 users/models/user.py:643 #: users/models/user.py:649 users/serializers/group.py:20
#: users/serializers/group.py:20
#: users/templates/users/user_asset_permission.html:38 #: users/templates/users/user_asset_permission.html:38
#: users/templates/users/user_asset_permission.html:64 #: users/templates/users/user_asset_permission.html:64
#: users/templates/users/user_database_app_permission.html:37 #: users/templates/users/user_database_app_permission.html:37
@ -733,14 +732,14 @@ msgid "Backend"
msgstr "后端" msgstr "后端"
#: assets/serializers/asset_user.py:75 users/forms/profile.py:148 #: 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.html:69
#: users/templates/users/user_profile_update.html:46 #: users/templates/users/user_profile_update.html:46
#: users/templates/users/user_pubkey_update.html:46 #: users/templates/users/user_pubkey_update.html:46
msgid "Public key" msgid "Public key"
msgstr "SSH公钥" 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" msgid "Private key"
msgstr "ssh私钥" msgstr "ssh私钥"
@ -1025,7 +1024,7 @@ msgstr "Agent"
#: audits/models.py:104 #: audits/models.py:104
#: authentication/templates/authentication/_mfa_confirm_modal.html:14 #: authentication/templates/authentication/_mfa_confirm_modal.html:14
#: authentication/templates/authentication/login_otp.html:6 #: 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/serializers/user.py:240 users/templates/users/user_detail.html:77
#: users/templates/users/user_profile.html:87 #: users/templates/users/user_profile.html:87
msgid "MFA" msgid "MFA"
@ -1265,7 +1264,7 @@ msgid "Show"
msgstr "显示" msgstr "显示"
#: authentication/templates/authentication/_access_key_modal.html:66 #: 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:94
#: users/templates/users/user_profile.html:163 #: users/templates/users/user_profile.html:163
#: users/templates/users/user_profile.html:166 #: users/templates/users/user_profile.html:166
@ -1274,7 +1273,7 @@ msgid "Disable"
msgstr "禁用" msgstr "禁用"
#: authentication/templates/authentication/_access_key_modal.html:67 #: 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:92
#: users/templates/users/user_profile.html:170 #: users/templates/users/user_profile.html:170
msgid "Enable" msgid "Enable"
@ -1685,7 +1684,7 @@ msgid "The current organization cannot be deleted"
msgstr "" msgstr ""
#: orgs/mixins/models.py:56 orgs/mixins/serializers.py:25 orgs/models.py:40 #: orgs/mixins/models.py:56 orgs/mixins/serializers.py:25 orgs/models.py:40
#: orgs/models.py:321 #: orgs/models.py:369
msgid "Organization" msgid "Organization"
msgstr "组织" msgstr "组织"
@ -1693,11 +1692,15 @@ msgstr "组织"
msgid "Organization administrator" msgid "Organization administrator"
msgstr "组织管理员" msgstr "组织管理员"
#: orgs/models.py:16
msgid "Organization User"
msgstr "组织用户"
#: orgs/models.py:17 #: orgs/models.py:17
msgid "Organization auditor" msgid "Organization auditor"
msgstr "组织审计员" 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/_select_user_modal.html:15
#: users/templates/users/user_detail.html:73 #: users/templates/users/user_detail.html:73
#: users/templates/users/user_list.html:16 #: 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/asset_permission.py:86 perms/forms/database_app_permission.py:41
#: perms/forms/remote_app_permission.py:43 perms/models/base.py:50 #: 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 #: 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/_select_user_modal.html:16
#: users/templates/users/user_asset_permission.html:39 #: users/templates/users/user_asset_permission.html:39
#: users/templates/users/user_asset_permission.html:67 #: users/templates/users/user_asset_permission.html:67
@ -1789,7 +1792,7 @@ msgid "Asset permission"
msgstr "资产授权" msgstr "资产授权"
#: perms/models/base.py:53 tickets/serializers/request_asset_perm.py:31 #: 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 #: users/templates/users/user_profile.html:120
msgid "Date expired" msgid "Date expired"
msgstr "失效日期" msgstr "失效日期"
@ -2537,36 +2540,37 @@ msgstr "结束日期"
msgid "Args" msgid "Args"
msgstr "参数" msgstr "参数"
#: tickets/api/request_asset_perm.py:45 #: tickets/api/request_asset_perm.py:46
#, python-format #, python-format
msgid "Ticket has %s" msgid "Ticket has %s"
msgstr "工单已%s" msgstr "工单已%s"
#: tickets/api/request_asset_perm.py:90 #: tickets/api/request_asset_perm.py:91
msgid "Confirm assets first" msgid "Confirm assets first"
msgstr "请先确认资产" msgstr "请先确认资产"
#: tickets/api/request_asset_perm.py:93 #: tickets/api/request_asset_perm.py:94
msgid "Confirmed assets changed" msgid "Confirmed assets changed"
msgstr "确认的资产变更了" msgstr "确认的资产变更了"
#: tickets/api/request_asset_perm.py:97 #: tickets/api/request_asset_perm.py:98
msgid "Confirm system-user first" msgid "Confirm system-user first"
msgstr "请先确认系统用户" msgstr "请先确认系统用户"
#: tickets/api/request_asset_perm.py:101 #: tickets/api/request_asset_perm.py:102
msgid "Confirmed system-user changed" msgid "Confirmed system-user changed"
msgstr "确认的系统用户变更了" 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" msgid "Succeed"
msgstr "成功" msgstr "成功"
#: tickets/api/request_asset_perm.py:112 #: tickets/api/request_asset_perm.py:120
msgid "From request ticket: {} {}" msgid "From request ticket: {} {}"
msgstr "来自工单申请: {} {}" msgstr "来自工单申请: {} {}"
#: tickets/api/request_asset_perm.py:114 #: tickets/api/request_asset_perm.py:122
msgid "{} request assets, approved by {}" msgid "{} request assets, approved by {}"
msgstr "{} 申请资产,通过人 {}" msgstr "{} 申请资产,通过人 {}"
@ -2749,7 +2753,7 @@ msgstr ""
" </div>\n" " </div>\n"
" " " "
#: users/api/user.py:147 #: users/api/user.py:158
msgid "Could not reset self otp, use profile reset instead" msgid "Could not reset self otp, use profile reset instead"
msgstr "不能在该页面重置多因子认证, 请去个人信息页面重置" msgstr "不能在该页面重置多因子认证, 请去个人信息页面重置"
@ -2795,7 +2799,7 @@ msgstr "确认密码"
msgid "Password does not match" msgid "Password does not match"
msgstr "密码不一致" 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_detail.html:57
#: users/templates/users/user_profile.html:59 #: users/templates/users/user_profile.html:59
msgid "Email" msgid "Email"
@ -2836,7 +2840,7 @@ msgstr "不能和原来的密钥相同"
msgid "Not a valid ssh public key" msgid "Not a valid ssh public key"
msgstr "SSH密钥不合法" 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_detail.html:89
#: users/templates/users/user_list.html:18 #: users/templates/users/user_list.html:18
#: users/templates/users/user_profile.html:102 #: users/templates/users/user_profile.html:102
@ -2856,15 +2860,15 @@ msgstr "添加到用户组"
msgid "* Your password does not meet the requirements" msgid "* Your password does not meet the requirements"
msgstr "* 您的密码不符合要求" 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" msgid "Reset link will be generated and sent to the user"
msgstr "生成重置密码链接,通过邮件发送给用户" msgstr "生成重置密码链接,通过邮件发送给用户"
#: users/forms/user.py:125 users/serializers/user.py:38 #: users/forms/user.py:125 users/serializers/user.py:37
msgid "Set password" msgid "Set password"
msgstr "设置密码" 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/models.py:61
#: xpack/plugins/change_auth_plan/serializers.py:30 #: xpack/plugins/change_auth_plan/serializers.py:30
msgid "Password strategy" msgid "Password strategy"
@ -2874,6 +2878,10 @@ msgstr "密码策略"
msgid "System administrator" msgid "System administrator"
msgstr "系统管理员" msgstr "系统管理员"
#: users/models/user.py:157
msgid "System User"
msgstr "系统用户"
#: users/models/user.py:158 #: users/models/user.py:158
msgid "System auditor" msgid "System auditor"
msgstr "系统审计员" msgstr "系统审计员"
@ -2882,67 +2890,67 @@ msgstr "系统审计员"
msgid "Application" msgid "Application"
msgstr "应用程序" 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" msgid "Force enable"
msgstr "强制启用" msgstr "强制启用"
#: users/models/user.py:478 #: users/models/user.py:484
msgid "Local" msgid "Local"
msgstr "数据库" msgstr "数据库"
#: users/models/user.py:502 #: users/models/user.py:508
msgid "Avatar" msgid "Avatar"
msgstr "头像" 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" msgid "Wechat"
msgstr "微信" msgstr "微信"
#: users/models/user.py:538 #: users/models/user.py:544
msgid "Date password last updated" msgid "Date password last updated"
msgstr "最后更新密码日期" msgstr "最后更新密码日期"
#: users/models/user.py:651 #: users/models/user.py:657
msgid "Administrator" msgid "Administrator"
msgstr "管理员" msgstr "管理员"
#: users/models/user.py:654 #: users/models/user.py:660
msgid "Administrator is the super user of system" msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员" 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" msgid "Organization role name"
msgstr "组织角色名称" msgstr "组织角色名称"
#: users/serializers/user.py:59 #: users/serializers/user.py:55
msgid "Total role name" msgid "Total role name"
msgstr "汇总角色名称" 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" msgid "Is first login"
msgstr "首次登录" msgstr "首次登录"
#: users/serializers/user.py:85 #: users/serializers/user.py:80
msgid "Is valid" msgid "Is valid"
msgstr "账户是否有效" msgstr "账户是否有效"
#: users/serializers/user.py:86 #: users/serializers/user.py:81
msgid "Is expired" msgid "Is expired"
msgstr " 是否过期" msgstr " 是否过期"
#: users/serializers/user.py:87 #: users/serializers/user.py:82
msgid "Avatar url" msgid "Avatar url"
msgstr "头像路径" msgstr "头像路径"
#: users/serializers/user.py:91 #: users/serializers/user.py:86
msgid "Groups name" msgid "Groups name"
msgstr "用户组名" msgstr "用户组名"
#: users/serializers/user.py:92 #: users/serializers/user.py:87
msgid "Source name" msgid "Source name"
msgstr "用户来源名" msgstr "用户来源名"
#: users/serializers/user.py:94 #: users/serializers/user.py:89
msgid "Super role name" msgid "Super role name"
msgstr "超级角色名称" msgstr "超级角色名称"

View File

@ -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'),
),
]

View File

@ -13,7 +13,7 @@ from common.db.models import ChoiceSet
class ROLE(ChoiceSet): class ROLE(ChoiceSet):
ADMIN = choices.ADMIN, _('Organization administrator') ADMIN = choices.ADMIN, _('Organization administrator')
USER = choices.USER, _('User') USER = choices.USER, _('Organization User')
AUDITOR = choices.AUDITOR, _("Organization auditor") AUDITOR = choices.AUDITOR, _("Organization auditor")
@ -229,15 +229,29 @@ def _none2list(*args):
return ([] if v is None else v for v in 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): class OrgMemeberManager(models.Manager):
def remove_users_by_role(self, org, users=None, admins=None, auditors=None): def remove_users_by_role(self, org, users=None, admins=None, auditors=None):
from users.models import User
if not any((users, admins, auditors)): if not any((users, admins, auditors)):
return return
users, admins, auditors = _none2list(users, admins, auditors) users, admins, auditors = _none2list(users, admins, auditors)
send = partial(signals.m2m_changed.send, sender=self.model, instance=org, reverse=False, 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") send(action="pre_remove")
self.filter(org_id=org.id).filter( self.filter(org_id=org.id).filter(
@ -248,6 +262,8 @@ class OrgMemeberManager(models.Manager):
send(action="post_remove") send(action="post_remove")
def add_users_by_role(self, org, users=None, admins=None, auditors=None): def add_users_by_role(self, org, users=None, admins=None, auditors=None):
from users.models import User
if not any((users, admins, auditors)): if not any((users, admins, auditors)):
return return
users, admins, auditors = _none2list(users, admins, auditors) 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)) 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, 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') send(action='pre_add')
self.bulk_create(oms_add) self.bulk_create(oms_add)
@ -278,24 +294,56 @@ class OrgMemeberManager(models.Manager):
new_users = _convert_to_uuid_set(new_users) new_users = _convert_to_uuid_set(new_users)
return (old_users - new_users), (new_users - old_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): 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') oms = self.filter(org_id=org.id).values_list('role', 'user_id')
old_users, old_admins, old_auditors = set(), set(), set() old_mapper = UserRoleMapper()
mapper = {
ROLE.USER: old_users,
ROLE.ADMIN: old_admins,
ROLE.AUDITOR: old_auditors
}
for role, user_id in oms: for role, user_id in oms:
if role in mapper: if role in old_mapper:
mapper[role].add(user_id) old_mapper[role].add(user_id)
users_remove, users_add = self._get_remove_add_set(users, old_users) users_remove, users_add = self._get_remove_add_set(users, old_mapper.users)
admins_remove, admins_add = self._get_remove_add_set(admins, old_admins) admins_remove, admins_add = self._get_remove_add_set(admins, old_mapper.admins)
auditors_remove, auditors_add = self._get_remove_add_set(auditors, old_auditors) auditors_remove, auditors_add = self._get_remove_add_set(auditors, old_mapper.auditors)
self.remove_users_by_role( self.remove_users_by_role(
org, org,

View File

@ -56,31 +56,25 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
def perform_create(self, serializer): def perform_create(self, serializer):
validated_data = serializer.validated_data 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() users = serializer.save()
if isinstance(users, User): if isinstance(users, User):
users = [users] 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: if current_org and current_org.is_real():
mapper[role].append(user) for user, roles in zip(users, org_roles):
else: if not roles:
mapper[ORG_ROLE.USER].append(user) # 当前组织创建的用户,至少是该组织的`User`
OrganizationMember.objects.set_users_by_role( roles.append(ORG_ROLE.USER)
current_org, users=mapper[ORG_ROLE.USER], OrganizationMember.objects.set_user_roles(current_org, user, roles)
admins=mapper[ORG_ROLE.ADMIN],
auditors=mapper[ORG_ROLE.AUDITOR]
)
self.send_created_signal(users) self.send_created_signal(users)
def get_permissions(self): def get_permissions(self):
@ -101,6 +95,23 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
self.check_object_permissions(self.request, obj) self.check_object_permissions(self.request, obj)
self.perform_destroy(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): def perform_bulk_update(self, serializer):
# TODO: 需要测试 # TODO: 需要测试
users_ids = [ users_ids = [

View File

@ -154,7 +154,7 @@ class AuthMixin:
class RoleMixin: class RoleMixin:
class ROLE(ChoiceSet): class ROLE(ChoiceSet):
ADMIN = choices.ADMIN, _('System administrator') ADMIN = choices.ADMIN, _('System administrator')
USER = choices.USER, _('User') USER = choices.USER, _('System User')
AUDITOR = choices.AUDITOR, _('System auditor') AUDITOR = choices.AUDITOR, _('System auditor')
APP = 'App', _('Application') APP = 'App', _('Application')
@ -164,15 +164,15 @@ class RoleMixin:
def role_display(self): def role_display(self):
return self.get_role_display() return self.get_role_display()
@property @lazyproperty
def org_role_display(self): def org_roles(self):
from orgs.models import ROLE as ORG_ROLE from orgs.models import ROLE as ORG_ROLE
if not current_org.is_real(): if not current_org.is_real():
if self.is_superuser: if self.is_superuser:
return ORG_ROLE.ADMIN.label return [ORG_ROLE.ADMIN]
else: else:
return ORG_ROLE.USER.label return [ORG_ROLE.USER]
if hasattr(self, 'gc_m2m_org_members__role'): if hasattr(self, 'gc_m2m_org_members__role'):
names = 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( roles = set(self.m2m_org_members.filter(
org_id=current_org.id org_id=current_org.id
).values_list('role', flat=True)) ).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): def current_org_roles(self):
from orgs.models import OrganizationMember, ROLE as ORG_ROLE from orgs.models import OrganizationMember, ROLE as ORG_ROLE

View File

@ -7,7 +7,6 @@ from rest_framework import serializers
from common.utils import validate_ssh_public_key from common.utils import validate_ssh_public_key
from common.mixins import CommonBulkSerializerMixin from common.mixins import CommonBulkSerializerMixin
from common.serializers import AdaptedBulkListSerializer
from common.permissions import CanUpdateDeleteUser from common.permissions import CanUpdateDeleteUser
from common.drf.fields import GroupConcatedPrimaryKeyRelatedField from common.drf.fields import GroupConcatedPrimaryKeyRelatedField
from orgs.models import ROLE as ORG_ROLE from orgs.models import ROLE as ORG_ROLE
@ -51,17 +50,13 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
login_blocked = serializers.SerializerMethodField() login_blocked = serializers.SerializerMethodField()
can_update = serializers.SerializerMethodField() can_update = serializers.SerializerMethodField()
can_delete = serializers.SerializerMethodField() can_delete = serializers.SerializerMethodField()
org_role = serializers.ChoiceField( org_roles = serializers.ListField(label=_('Organization role name'), allow_null=True, required=False,
label=_('Organization role name'), write_only=True, child=serializers.ChoiceField(choices=ORG_ROLE.choices))
allow_null=True, required=False, allow_blank=True,
choices=ORG_ROLE.choices
)
total_role_display = serializers.SerializerMethodField(label=_('Total role name')) total_role_display = serializers.SerializerMethodField(label=_('Total role name'))
key_prefix_block = "_LOGIN_BLOCK_{}" key_prefix_block = "_LOGIN_BLOCK_{}"
class Meta: class Meta:
model = User model = User
list_serializer_class = AdaptedBulkListSerializer
# mini 是指能识别对象的最小单元 # mini 是指能识别对象的最小单元
fields_mini = ['id', 'name', 'username'] fields_mini = ['id', 'name', 'username']
# small 指的是 不需要计算的直接能从一张表中获取到的数据 # small 指的是 不需要计算的直接能从一张表中获取到的数据
@ -75,7 +70,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
] ]
fields = fields_small + [ fields = fields_small + [
'groups', 'role', 'groups_display', 'role_display', 'groups', 'role', 'groups_display', 'role_display',
'can_update', 'can_delete', 'login_blocked', 'org_role' 'can_update', 'can_delete', 'login_blocked', 'org_roles'
] ]
extra_kwargs = { extra_kwargs = {