Merge "refactor: Refactor user"

This commit is contained in:
Zuul 2022-06-09 04:00:57 +00:00 committed by Gerrit Code Review
commit d133705f6f
19 changed files with 518 additions and 1562 deletions

View File

@ -790,6 +790,7 @@
"Edit Share Metadata": "Edit Share Metadata", "Edit Share Metadata": "Edit Share Metadata",
"Edit Subnet": "Edit Subnet", "Edit Subnet": "Edit Subnet",
"Edit System Permission": "Edit System Permission", "Edit System Permission": "Edit System Permission",
"Edit User": "Edit User",
"Edit User Group": "Edit User Group", "Edit User Group": "Edit User Group",
"Edit VPN": "Edit VPN", "Edit VPN": "Edit VPN",
"Edit VPN EndPoint Groups": "Edit VPN EndPoint Groups", "Edit VPN EndPoint Groups": "Edit VPN EndPoint Groups",
@ -1326,7 +1327,6 @@
"MacVTap": "MacVTap", "MacVTap": "MacVTap",
"Macau": "Macau", "Macau": "Macau",
"Madagascar": "Madagascar", "Madagascar": "Madagascar",
"Main Project": "Main Project",
"Maintained": "Maintained", "Maintained": "Maintained",
"Maintenance": "Maintenance", "Maintenance": "Maintenance",
"Malawi": "Malawi", "Malawi": "Malawi",
@ -1351,7 +1351,6 @@
"Manageable": "Manageable", "Manageable": "Manageable",
"Management": "Management", "Management": "Management",
"Management Reason": "Management Reason", "Management Reason": "Management Reason",
"Manager user": "Manager user",
"Manager user group": "Manager user group", "Manager user group": "Manager user group",
"Manu": "Manu", "Manu": "Manu",
"Manual backup": "Manual backup", "Manual backup": "Manual backup",
@ -1958,7 +1957,6 @@
"Select Project": "Select Project", "Select Project": "Select Project",
"Select Project Role": "Select Project Role", "Select Project Role": "Select Project Role",
"Select Snapshot": "Select Snapshot", "Select Snapshot": "Select Snapshot",
"Select System Role": "Select System Role",
"Select User Group": "Select User Group", "Select User Group": "Select User Group",
"Select a domain": "Select a domain", "Select a domain": "Select a domain",
"Select a region": "Select a region", "Select a region": "Select a region",
@ -2161,6 +2159,7 @@
"System Info": "System Info", "System Info": "System Info",
"System Load": "System Load", "System Load": "System Load",
"System Reader": "System Reader", "System Reader": "System Reader",
"System Roles": "System Roles",
"System Running Time": "System Running Time", "System Running Time": "System Running Time",
"System is error, please try again later.": "System is error, please try again later.", "System is error, please try again later.": "System is error, please try again later.",
"TCP": "TCP", "TCP": "TCP",
@ -2189,7 +2188,6 @@
"The Republic of Macedonia": "The Republic of Macedonia", "The Republic of Macedonia": "The Republic of Macedonia",
"The Republic of South Sudan": "The Republic of South Sudan", "The Republic of South Sudan": "The Republic of South Sudan",
"The SSH key is a way to remotely log in to the instance. The cloud platform only helps to keep the public key. Please keep your private key properly.": "The SSH key is a way to remotely log in to the instance. The cloud platform only helps to keep the public key. Please keep your private key properly.", "The SSH key is a way to remotely log in to the instance. The cloud platform only helps to keep the public key. Please keep your private key properly.": "The SSH key is a way to remotely log in to the instance. The cloud platform only helps to keep the public key. Please keep your private key properly.",
"The affiliated Domain cannot be modified after creation": "The affiliated Domain cannot be modified after creation",
"The amphora instance is required for load balancing service setup and is not recommended": "The amphora instance is required for load balancing service setup and is not recommended", "The amphora instance is required for load balancing service setup and is not recommended": "The amphora instance is required for load balancing service setup and is not recommended",
"The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.": "The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.", "The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.": "The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.",
"The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.": "The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.", "The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.": "The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.",
@ -2393,6 +2391,7 @@
"User Data": "User Data", "User Data": "User Data",
"User Detail": "User Detail", "User Detail": "User Detail",
"User Edit": "User Edit", "User Edit": "User Edit",
"User Group": "User Group",
"User Group Detail": "User Group Detail", "User Group Detail": "User Group Detail",
"User Group ID/Name": "User Group ID/Name", "User Group ID/Name": "User Group ID/Name",
"User Group Name": "User Group Name", "User Group Name": "User Group Name",
@ -2485,7 +2484,6 @@
"Whether the boot device should be set only for the next reboot, or persistently.": "Whether the boot device should be set only for the next reboot, or persistently.", "Whether the boot device should be set only for the next reboot, or persistently.": "Whether the boot device should be set only for the next reboot, or persistently.",
"Which Network Interface provider to use when plumbing the network connections for this Node": "Which Network Interface provider to use when plumbing the network connections for this Node", "Which Network Interface provider to use when plumbing the network connections for this Node": "Which Network Interface provider to use when plumbing the network connections for this Node",
"Windows": "Windows", "Windows": "Windows",
"Work Num": "Work Num",
"Workdir": "Workdir", "Workdir": "Workdir",
"Working Directory": "Working Directory", "Working Directory": "Working Directory",
"X86 Architecture": "X86 Architecture", "X86 Architecture": "X86 Architecture",
@ -2515,6 +2513,7 @@
"application credential": "application credential", "application credential": "application credential",
"associate floating ip": "associate floating ip", "associate floating ip": "associate floating ip",
"attach interface": "attach interface", "attach interface": "attach interface",
"authorized by group ": "authorized by group ",
"availability zones": "availability zones", "availability zones": "availability zones",
"available": "available", "available": "available",
"backup": "backup", "backup": "backup",
@ -2619,7 +2618,6 @@
"domain": "domain", "domain": "domain",
"domains": "domains", "domains": "domains",
"e.g. 2001:Db8::/48": "e.g. 2001:Db8::/48", "e.g. 2001:Db8::/48": "e.g. 2001:Db8::/48",
"edit": "edit",
"edit baremetal node": "edit baremetal node", "edit baremetal node": "edit baremetal node",
"edit default pool": "edit default pool", "edit default pool": "edit default pool",
"edit health monitor": "edit health monitor", "edit health monitor": "edit health monitor",

View File

@ -790,6 +790,7 @@
"Edit Share Metadata": "编辑共享元数据", "Edit Share Metadata": "编辑共享元数据",
"Edit Subnet": "编辑子网", "Edit Subnet": "编辑子网",
"Edit System Permission": "编辑系统角色", "Edit System Permission": "编辑系统角色",
"Edit User": "编辑用户",
"Edit User Group": "编辑用户组", "Edit User Group": "编辑用户组",
"Edit VPN": "编辑VPN", "Edit VPN": "编辑VPN",
"Edit VPN EndPoint Groups": "编辑VPN端点组", "Edit VPN EndPoint Groups": "编辑VPN端点组",
@ -1326,7 +1327,6 @@
"MacVTap": "", "MacVTap": "",
"Macau": "澳门", "Macau": "澳门",
"Madagascar": "马达加斯加", "Madagascar": "马达加斯加",
"Main Project": "主项目",
"Maintained": "维护", "Maintained": "维护",
"Maintenance": "运维管理", "Maintenance": "运维管理",
"Malawi": "马拉维", "Malawi": "马拉维",
@ -1351,7 +1351,6 @@
"Manageable": "可管理", "Manageable": "可管理",
"Management": "维护", "Management": "维护",
"Management Reason": "维护原因", "Management Reason": "维护原因",
"Manager user": "管理用户",
"Manager user group": "管理用户组", "Manager user group": "管理用户组",
"Manu": "手动", "Manu": "手动",
"Manual backup": "手动备份", "Manual backup": "手动备份",
@ -1958,7 +1957,6 @@
"Select Project": "选择项目", "Select Project": "选择项目",
"Select Project Role": "选择项目角色", "Select Project Role": "选择项目角色",
"Select Snapshot": "选择快照", "Select Snapshot": "选择快照",
"Select System Role": "选择系统角色",
"Select User Group": "选择用户组", "Select User Group": "选择用户组",
"Select a domain": "请选择Domain", "Select a domain": "请选择Domain",
"Select a region": "请选择Region", "Select a region": "请选择Region",
@ -2161,6 +2159,7 @@
"System Info": "系统信息", "System Info": "系统信息",
"System Load": "系统负载", "System Load": "系统负载",
"System Reader": "系统只读权限", "System Reader": "系统只读权限",
"System Roles": "系统角色",
"System Running Time": "", "System Running Time": "",
"System is error, please try again later.": "系统出错,请稍后再试。", "System is error, please try again later.": "系统出错,请稍后再试。",
"TCP": "", "TCP": "",
@ -2189,7 +2188,6 @@
"The Republic of Macedonia": "马其顿", "The Republic of Macedonia": "马其顿",
"The Republic of South Sudan": "南苏丹共和国", "The Republic of South Sudan": "南苏丹共和国",
"The SSH key is a way to remotely log in to the instance. The cloud platform only helps to keep the public key. Please keep your private key properly.": "SSH 密钥是一种远程登录云主机的方式,云平台只帮助保管公钥,请妥善保管自己的私钥。", "The SSH key is a way to remotely log in to the instance. The cloud platform only helps to keep the public key. Please keep your private key properly.": "SSH 密钥是一种远程登录云主机的方式,云平台只帮助保管公钥,请妥善保管自己的私钥。",
"The affiliated Domain cannot be modified after creation": "所属域不可修改",
"The amphora instance is required for load balancing service setup and is not recommended": "amphora 相关的云主机为负载均衡服务搭建所需,不建议选择", "The amphora instance is required for load balancing service setup and is not recommended": "amphora 相关的云主机为负载均衡服务搭建所需,不建议选择",
"The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.": "绑定的浮动IP、网卡、云硬盘等资源将自动解绑。", "The associated floating IP, virtual adapter, volume and other resources will be automatically disassociated.": "绑定的浮动IP、网卡、云硬盘等资源将自动解绑。",
"The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.": "证书包含证书的公钥和签名等信息证书扩展名为”pem”或”crt”您可直接输入证书内容或上传证书文件。", "The certificate contains information such as the public key and signature of the certificate. The extension of the certificate is \"pem\" or \"crt\", you can directly enter certificate content or upload certificate file.": "证书包含证书的公钥和签名等信息证书扩展名为”pem”或”crt”您可直接输入证书内容或上传证书文件。",
@ -2393,6 +2391,7 @@
"User Data": "用户数据", "User Data": "用户数据",
"User Detail": "用户详情", "User Detail": "用户详情",
"User Edit": "编辑用户", "User Edit": "编辑用户",
"User Group": "用户组",
"User Group Detail": "用户组详情", "User Group Detail": "用户组详情",
"User Group ID/Name": "用户组ID/名称", "User Group ID/Name": "用户组ID/名称",
"User Group Name": "用户组名称", "User Group Name": "用户组名称",
@ -2485,7 +2484,6 @@
"Whether the boot device should be set only for the next reboot, or persistently.": "是否永久使用该引导设置。", "Whether the boot device should be set only for the next reboot, or persistently.": "是否永久使用该引导设置。",
"Which Network Interface provider to use when plumbing the network connections for this Node": "当为这个节点连接网络时,使用哪个网络接口提供者", "Which Network Interface provider to use when plumbing the network connections for this Node": "当为这个节点连接网络时,使用哪个网络接口提供者",
"Windows": "", "Windows": "",
"Work Num": "工号",
"Workdir": "工作目录", "Workdir": "工作目录",
"Working Directory": "工作目录", "Working Directory": "工作目录",
"X86 Architecture": "X86架构", "X86 Architecture": "X86架构",
@ -2515,6 +2513,7 @@
"application credential": "应用凭证", "application credential": "应用凭证",
"associate floating ip": "绑定浮动IP", "associate floating ip": "绑定浮动IP",
"attach interface": "挂载网卡", "attach interface": "挂载网卡",
"authorized by group ": "由组授权",
"availability zones": "可用域", "availability zones": "可用域",
"available": "可用", "available": "可用",
"backup": "备份", "backup": "备份",
@ -2619,7 +2618,6 @@
"domain": "域", "domain": "域",
"domains": "域", "domains": "域",
"e.g. 2001:Db8::/48": "", "e.g. 2001:Db8::/48": "",
"edit": "编辑",
"edit baremetal node": "编辑裸机节点", "edit baremetal node": "编辑裸机节点",
"edit default pool": "编辑资源池", "edit default pool": "编辑资源池",
"edit health monitor": "编辑健康检查器", "edit health monitor": "编辑健康检查器",

View File

@ -53,6 +53,10 @@ export class Detail extends Base {
dataIndex: 'name', dataIndex: 'name',
}, },
enabledColumn, enabledColumn,
{
title: t('Affiliated Domain'),
dataIndex: 'domainName',
},
{ {
title: t('User Num'), title: t('User Num'),
dataIndex: 'userCount', dataIndex: 'userCount',

View File

@ -46,7 +46,7 @@ export class ManagerUser extends ModalAction {
} }
getUser() { getUser() {
this.userStore.fetchAllWithDomain(); this.userStore.fetchList({ withProjectRole: false, withSystemRole: false });
} }
getInitRoleMap() { getInitRoleMap() {

View File

@ -214,6 +214,11 @@ export class Projects extends Base {
)}${groupCount}`; )}${groupCount}`;
}, },
}, },
{
title: t('Affiliated Domain'),
dataIndex: 'domainName',
isHideable: true,
},
enabledColumn, enabledColumn,
{ {
title: t('Tags'), title: t('Tags'),

View File

@ -12,11 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import React from 'react';
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import { UserStore } from 'stores/keystone/user'; import { UserStore } from 'stores/keystone/user';
import globalDomainStore from 'stores/keystone/domain';
import Base from 'containers/TabDetail'; import Base from 'containers/TabDetail';
import Credentials from 'src/pages/user-center/containers/Credentials'; import Credentials from 'src/pages/user-center/containers/Credentials';
import { emptyActionConfig } from 'utils/constants';
import { enabledColumn } from 'resources/keystone/domain'; import { enabledColumn } from 'resources/keystone/domain';
import UserGroup from '../../UserGroup'; import UserGroup from '../../UserGroup';
import Project from '../../Project'; import Project from '../../Project';
@ -36,33 +37,13 @@ export class UserDetail extends Base {
} }
get actionConfigs() { get actionConfigs() {
return this.isAdminPage return this.isAdminPage ? actionConfigs : emptyActionConfig;
? actionConfigs.adminConfigs
: actionConfigs.actionConfigs;
} }
init() { init() {
this.store = new UserStore(); this.store = new UserStore();
this.domainStore = globalDomainStore;
this.getDomains();
} }
getDomains() {
this.domainStore.fetchDomain();
}
get domainList() {
const { domains } = this.domainStore;
return domains || [];
}
goEdit = () => {
const {
params: { id },
} = this.props.match;
this.routing.push(`${this.listUrl}/edit/${id}`);
};
get detailInfos() { get detailInfos() {
return [ return [
{ {
@ -70,25 +51,27 @@ export class UserDetail extends Base {
dataIndex: 'name', dataIndex: 'name',
}, },
enabledColumn, enabledColumn,
{
title: t('System Roles'),
dataIndex: 'systemRoles',
render: (value) => {
if (!value || !value.length) {
return '-';
}
return (value || []).map((it) => <div key={it.id}>{it.name}</div>);
},
},
{ {
title: t('Real Name'), title: t('Real Name'),
dataIndex: 'real_name', dataIndex: 'real_name',
}, },
// { // {
// title: t('User Group Num'), // title: t('User Group Num'),
// dataIndex: 'group_num', // dataIndex: 'groupCount',
// }, // },
{ {
title: t('Affiliated Domain'), title: t('Affiliated Domain'),
dataIndex: 'domain_id', dataIndex: 'domainName',
isHideable: true,
render: (domain_id) => {
const domain = this.domainList.filter((it) => it.id === domain_id);
if (domain[0]) {
return domain[0].name;
}
return domain_id;
},
}, },
{ {
title: t('Email'), title: t('Email'),

View File

@ -13,56 +13,61 @@
// limitations under the License. // limitations under the License.
import React from 'react'; import React from 'react';
import { has } from 'lodash';
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import globalGroupStore from 'stores/keystone/user-group'; import { GroupStore } from 'stores/keystone/user-group';
import globalUserStore from 'stores/keystone/user'; import globalUserStore from 'stores/keystone/user';
import { FormAction } from 'containers/Action'; import { FormAction } from 'containers/Action';
import { Select } from 'antd'; import { Select } from 'antd';
import globalProjectStore from 'stores/keystone/project'; import { ProjectStore } from 'stores/keystone/project';
import globalRoleStore from 'stores/keystone/role'; import globalRoleStore from 'stores/keystone/role';
import globalDomainStore from 'stores/keystone/domain';
import { import {
getPasswordOtherRule, getPasswordOtherRule,
phoneNumberValidate, phoneNumberValidate,
emailValidate, emailValidate,
} from 'utils/validate'; } from 'utils/validate';
import { statusTypes } from 'resources/keystone/domain'; import {
statusTypes,
getDomainFormItem,
nameDomainColumns,
transferFilterOption,
} from 'resources/keystone/domain';
export class CreateForm extends FormAction { export class Create extends FormAction {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
domain: 'default', domain: 'default',
more: false, more: false,
newProjectRoles: {}, projectRoles: {},
}; };
} }
init() { init() {
this.store = globalUserStore; this.store = globalUserStore;
this.userGroupStore = globalGroupStore; this.userGroupStore = new GroupStore();
this.projectStore = globalProjectStore; this.projectStore = new ProjectStore();
this.roleStore = globalRoleStore; this.roleStore = globalRoleStore;
this.getUserGroup(); this.getUserGroups();
this.getProject(); this.getProjects();
this.getRole(); this.getRoles();
this.getDomains(); this.getDomains();
} }
getDomains() { getDomains() {
this.store.fetchDomain(); globalDomainStore.fetchDomain();
} }
getUserGroup() { getUserGroups() {
this.userGroupStore.fetchList(); this.userGroupStore.fetchList({ withRole: false });
} }
getProject() { getProjects() {
this.projectStore.fetchList(); this.projectStore.fetchList({ withRole: false });
} }
getRole() { getRoles() {
this.roleStore.fetchList(); this.roleStore.fetchList();
} }
@ -97,13 +102,10 @@ export class CreateForm extends FormAction {
} }
get defaultValue() { get defaultValue() {
const { domains } = this.store;
const { domain } = this.state;
const domainDefault = (domains || []).filter((it) => it.id === domain)[0];
const data = { const data = {
more: false, more: false,
enabled: statusTypes[0].value, enabled: statusTypes[0].value,
domain_id: domainDefault ? domainDefault.name : 'Default', domain_id: 'default',
}; };
return data; return data;
} }
@ -129,96 +131,81 @@ export class CreateForm extends FormAction {
})); }));
} }
// get roleList() {
// return (this.roleStore.list.data || []).map(it => ({
// label: it.name,
// value: it.id,
// }));
// }
// get adminRole() {
// return (this.roleStore.list.data || []).filter(it =>
// it.name === 'admin'
// )[0];
// }
onValuesChange = (changedFields) => {
if (has(changedFields, 'more')) {
this.setState({
more: changedFields.more,
});
}
};
static allowed = () => Promise.resolve(true); static allowed = () => Promise.resolve(true);
get leftProjectTable() { get leftProjectTable() {
return [ return nameDomainColumns;
{
dataIndex: 'name',
title: t('Name'),
},
];
} }
get projectRoleList() { get projectRoleList() {
const projectRole = this.roleStore.list.data || []; return this.roleStore.list.data || [];
return projectRole;
} }
userRolesList = (role_id) => projectRolesList = (projectId) =>
(this.projectRoleList || []).map((it) => ({ (this.projectRoleList || []).map((it) => ({
label: it.name, label: it.name,
value: it.id, value: it.id,
role_id, projectId,
})); }));
defaultRoles = () => [this.projectRoleList[0].id]; defaultRoles = () => [(this.projectRoleList[0] || {}).id];
userRoleChange = (value, option) => { onSelectChange = (value, option, projectId) => {
const { newProjectRoles } = this.state; const { projectRoles } = this.state;
const { role_id } = option; if (value.length && option.length) {
newProjectRoles[role_id] = value; projectRoles[projectId] = value;
this.setState({ newProjectRoles }); } else {
projectRoles[projectId] = {};
}
this.setState({ projectRoles });
};
renderSelect = (projectId) => {
return (
<Select
size="small"
mode="multiple"
options={this.projectRolesList(projectId)}
defaultValue={this.defaultRoles()}
onChange={(value, option) => {
this.onSelectChange(value, option, projectId);
}}
/>
);
}; };
get rightProjectTable() { get rightProjectTable() {
return [ return [
{ ...nameDomainColumns,
dataIndex: 'name',
title: t('Name'),
},
{ {
title: t('Select Project Role'), title: t('Select Project Role'),
dataIndex: 'id', dataIndex: 'id',
render: (id) => ( render: (id) => this.renderSelect(id),
<Select
size="small"
options={this.userRolesList(id)}
defaultValue={this.defaultRoles()}
onChange={this.userRoleChange}
/>
),
}, },
]; ];
} }
onChangeProject = (value) => {
const { projectRoles } = this.state;
(value || []).forEach((projectId) => {
if (!projectRoles[projectId]) {
projectRoles[projectId] = this.defaultRoles();
}
});
Object.keys(projectRoles).forEach((projectId) => {
if (!(value || []).includes(projectId)) {
delete projectRoles[projectId];
}
});
this.setState(projectRoles);
};
get leftUserGroupTable() { get leftUserGroupTable() {
return [ return nameDomainColumns;
{
dataIndex: 'name',
title: t('Name'),
},
];
} }
get rightUserGroupTable() { get rightUserGroupTable() {
return [ return nameDomainColumns;
{
dataIndex: 'name',
title: t('Name'),
},
];
} }
checkName = (rule, value) => { checkName = (rule, value) => {
@ -236,17 +223,22 @@ export class CreateForm extends FormAction {
}; };
get formItems() { get formItems() {
const { more, domain } = this.state; const { more } = this.state;
const labelCol = { const labelCol = {
xs: { span: 5 }, xs: { span: 5 },
sm: { span: 6 }, sm: { span: 6 },
}; };
const domainFormItem = getDomainFormItem(this);
const currentDomainFormItem = {
...domainFormItem,
labelCol,
colNum: 2,
};
return [ return [
{ {
name: 'name', name: 'name',
label: t('User Name'), label: t('User Name'),
type: 'input', type: 'input',
placeholder: t('Please input user name'),
validator: this.checkName, validator: this.checkName,
extra: t('User name can not be duplicated'), extra: t('User name can not be duplicated'),
required: true, required: true,
@ -291,20 +283,7 @@ export class CreateForm extends FormAction {
labelCol, labelCol,
colNum: 2, colNum: 2,
}, },
{ currentDomainFormItem,
name: 'domain_id',
label: t('Affiliated Domain'),
type: 'input',
// options: this.domainList,
// onChange: (e) => {
// this.setState({
// domain: e,
// });
// },
disabled: true,
colNum: 2,
labelCol,
},
{ {
name: 'enabled', name: 'enabled',
label: t('Status'), label: t('Status'),
@ -315,14 +294,6 @@ export class CreateForm extends FormAction {
labelCol, labelCol,
colNum: 2, colNum: 2,
}, },
// {
// name: 'default_project_id',
// label: t('Main Project'),
// type: 'select',
// options: this.projectList,
// labelCol,
// colNum: 2,
// },
{ {
name: 'description', name: 'description',
label: t('Description'), label: t('Description'),
@ -339,13 +310,6 @@ export class CreateForm extends FormAction {
colNum: 2, colNum: 2,
maxLength: 30, maxLength: 30,
}, },
// {
// name: 'work num',
// label: t('Work Num'),
// type: 'input',
// labelCol,
// colNum: 2,
// },
{ {
type: 'divider', type: 'divider',
}, },
@ -360,12 +324,11 @@ export class CreateForm extends FormAction {
type: 'transfer', type: 'transfer',
leftTableColumns: this.leftProjectTable, leftTableColumns: this.leftProjectTable,
rightTableColumns: this.rightProjectTable, rightTableColumns: this.rightProjectTable,
dataSource: domain dataSource: this.projects,
? this.projects.filter((it) => it.domain_id === domain)
: [],
disabled: false,
showSearch: true, showSearch: true,
hidden: !more || !domain, hidden: !more,
onChange: this.onChangeProject,
filterOption: transferFilterOption,
}, },
{ {
name: 'select_user_group', name: 'select_user_group',
@ -373,12 +336,10 @@ export class CreateForm extends FormAction {
type: 'transfer', type: 'transfer',
leftTableColumns: this.leftUserGroupTable, leftTableColumns: this.leftUserGroupTable,
rightTableColumns: this.rightUserGroupTable, rightTableColumns: this.rightUserGroupTable,
dataSource: domain dataSource: this.userGroupList,
? this.userGroupList.filter((it) => it.domain_id === domain)
: [],
disabled: false,
showSearch: true, showSearch: true,
hidden: !more || !domain, hidden: !more,
filterOption: transferFilterOption,
}, },
]; ];
} }
@ -386,11 +347,11 @@ export class CreateForm extends FormAction {
onSubmit = async (values) => { onSubmit = async (values) => {
const { domain } = this.state; const { domain } = this.state;
values.defaultRole = this.projectRoleList[0].id; values.defaultRole = this.projectRoleList[0].id;
values.newProjectRoles = this.state.newProjectRoles; values.projectRoles = this.state.projectRoles;
values.domain_id = domain; values.domain_id = domain;
const { confirmPassword, more, ...rest } = values; const { confirmPassword, more, ...rest } = values;
return this.store.create(rest); return this.store.create(rest);
}; };
} }
export default inject('rootStore')(observer(CreateForm)); export default inject('rootStore')(observer(Create));

View File

@ -15,101 +15,44 @@
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import { ModalAction } from 'containers/Action'; import { ModalAction } from 'containers/Action';
import globalUserStore from 'stores/keystone/user'; import globalUserStore from 'stores/keystone/user';
import globalDomainStore from 'stores/keystone/domain';
import { phoneNumberValidate, emailValidate } from 'utils/validate'; import { phoneNumberValidate, emailValidate } from 'utils/validate';
import parsePhoneNumberFromString from 'libphonenumber-js'; import parsePhoneNumberFromString from 'libphonenumber-js';
export class EditForm extends ModalAction { export class EditForm extends ModalAction {
init() { init() {
this.store = globalUserStore; this.store = globalUserStore;
this.domainStore = globalDomainStore;
this.getDomains();
this.getProject();
}
componentDidMount() {
const { item } = this.props;
const { id } = this.item;
this.store.fetchDetail({ ...item, id });
}
getDomains() {
this.domainStore.fetchDomain();
}
getProject() {
this.store.fetchProject();
} }
static id = 'user-edit'; static id = 'user-edit';
static title = t('Edit'); static title = t('Edit');
// static path(item) {
// return `/identity/user-admin/edit/${item.id}`;
// }
static policy = 'identity:update_user'; static policy = 'identity:update_user';
static allowed() { static allowed() {
return Promise.resolve(true); return Promise.resolve(true);
} }
get domainList() { get actionName() {
return (this.userGroupStore.list.data || []).map((it) => ({ return t('Edit User');
label: it.name,
value: it.id,
}));
}
get projectList() {
const { projects } = this.store;
return (projects || []).map((it) => ({
label: it.name,
value: it.id,
}));
}
get data() {
return this.store.detail || [];
}
get name() {
const { name } = this.data;
return `${t('edit')} ${name}`;
} }
get defaultValue() { get defaultValue() {
const { const { name, email, phone, real_name, description, domain, domain_id } =
name, this.item;
email,
phone,
real_name,
description,
domain_id,
default_project_id,
} = this.data;
const { domains } = this.domainStore;
const { projects } = this.store;
const domain = domains.filter((it) => it.id === domain_id)[0];
const project = projects.filter((it) => it.id === default_project_id)[0];
if (name && this.formRef.current) {
const formattedPhone = parsePhoneNumberFromString(phone || '', 'CN') || { const formattedPhone = parsePhoneNumberFromString(phone || '', 'CN') || {
countryCallingCode: '86', countryCallingCode: '86',
nationalNumber: '', nationalNumber: '',
}; };
const { countryCallingCode, nationalNumber } = formattedPhone; const { countryCallingCode, nationalNumber } = formattedPhone;
this.formRef.current.setFieldsValue({ return {
name, name,
domain_id: domain ? domain.name : '', domainName: (domain || {}).name || domain_id,
default_project_id: project ? project.name : '',
email, email,
phone: `+${countryCallingCode} ${nationalNumber}`, phone: `+${countryCallingCode} ${nationalNumber}`,
real_name, real_name,
description, description,
}); };
}
return {};
} }
checkName = (rule, value) => { checkName = (rule, value) => {
@ -119,9 +62,9 @@ export class EditForm extends ModalAction {
const { const {
list: { data }, list: { data },
} = this.store; } = this.store;
const { name } = this.item; const { id } = this.item;
const nameUsed = data.filter((it) => it.name === value); const nameUsed = data.find((it) => it.name === value && it.id !== id);
if (nameUsed[0] && nameUsed[0].name !== name) { if (nameUsed) {
return Promise.reject(t('Invalid: User name can not be duplicated')); return Promise.reject(t('Invalid: User name can not be duplicated'));
} }
return Promise.resolve(); return Promise.resolve();
@ -159,10 +102,9 @@ export class EditForm extends ModalAction {
required: true, required: true,
}, },
{ {
name: 'domain_id', name: 'domainName',
label: t('Affiliated Domain'), label: t('Affiliated Domain'),
type: 'input', type: 'input',
required: true,
disabled: true, disabled: true,
}, },
{ {

View File

@ -29,6 +29,10 @@ export default class ForbiddenAction extends ConfirmAction {
return t('Forbidden'); return t('Forbidden');
} }
get isDanger() {
return true;
}
get actionName() { get actionName() {
return t('Forbidden User'); return t('Forbidden User');
} }

View File

@ -11,17 +11,22 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import React from 'react';
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import { Select } from 'antd';
import globalProjectStore from 'stores/keystone/project';
import globalUserStore from 'stores/keystone/user';
import { RoleStore } from 'stores/keystone/role';
import { ModalAction } from 'containers/Action'; import { ModalAction } from 'containers/Action';
import globalDomainStore from 'stores/keystone/domain'; import { UserStore } from 'stores/keystone/user';
import globalRoleStore from 'stores/keystone/role';
export class SystemRole extends ModalAction { export class SystemRole extends ModalAction {
init() {
this.store = new UserStore();
this.roleStore = globalRoleStore;
this.getRoleList();
}
getRoleList() {
this.roleStore.fetchSystemRoles();
}
static id = 'edit-system-permission'; static id = 'edit-system-permission';
static title = t('Edit System Permission'); static title = t('Edit System Permission');
@ -30,318 +35,70 @@ export class SystemRole extends ModalAction {
return t('edit system permission'); return t('edit system permission');
} }
async init() { get rolesList() {
const systemRole = JSON.stringify(this.item.projectMapSystemRole); return (this.roleStore.systemRoles.data || []).map((it) => ({
this.state.domainDefault = this.item.domain_id;
this.state.projectRoles = JSON.parse(systemRole);
this.store = new RoleStore();
this.domainStore = globalDomainStore;
this.userStore = globalUserStore;
await this.getRoleList();
this.getDomains();
this.getUser();
}
getRoleList() {
return this.store.fetchList();
}
getDomains() {
this.domainStore.fetchDomain();
}
getUser() {
this.userStore.fetchProject();
}
static get modalSize() {
return 'large';
}
getModalSize() {
return 'large';
}
// get defaultSystemRoles() {
// const { projects } = this.item;
// const defaultProjects = Object.keys(projects);
// const systemRole = (this.store.list.data || []).filter(it =>
// ((it.name.indexOf('system_') !== -1) && (it.name.indexOf('_system_') === -1)) ||
// it.name === 'admin'
// );
// const systemRoleId = systemRole.map(it => it.id);
// const defaultSystemRoles = {};
// defaultProjects.forEach((project_id) => {
// const roles = projects[project_id].filter(role_id => systemRoleId.indexOf(role_id) !== -1);
// if (roles[0]) {
// defaultSystemRoles[project_id] = roles;
// }
// });
// return defaultSystemRoles;
// }
get domainList() {
const {
rootStore: { baseDomains },
} = this.props;
const { domains } = this.domainStore;
const domainList = (domains || []).filter(
(it) =>
baseDomains.indexOf(it.name) === -1 || it.id === this.item.domain_id
);
return domainList.map((it) => ({
label: it.name, label: it.name,
value: it.id, value: it.id,
key: it.id,
}));
}
get item() {
const { item } = this.props;
item.roles = {};
return item;
}
get multipleMode() {
return 'multiple';
}
get projectList() {
return (this.userStore.projects || []).map((it) => ({
...it,
key: it.id,
}));
}
get systemRoleList() {
const systemRole = this.store.list.data || [];
return systemRole;
}
get adminRoleId() {
const adminRole = (this.store.list.data || []).filter(
(it) => it.name === 'admin'
);
return adminRole[0].id;
}
adminRoleList = (project_id) => {
const adminRole = (this.store.list.data || []).filter(
(it) => it.name === 'admin'
);
return adminRole.map((it) => ({
label: it.name,
value: it.id,
key: it.id,
project_id,
}));
};
projectRolesList = (project_id) =>
this.systemRoleList.map((it) => ({
label: it.name,
value: it.id,
key: it.id,
project_id,
}));
defaultRoles = (projectId) => {
const { roles, projects } = this.item;
const { projectRoles } = this.state;
const filterRoles = this.multipleMode ? projects : projectRoles;
if (!filterRoles[projectId]) {
roles[projectId] = [this.systemRoleList[0].id];
} else {
const usersSystemRole = filterRoles[projectId].filter((it) => {
const systemRole = this.systemRoleList.filter((role) => role.id === it);
if (systemRole[0]) {
return true;
}
return false;
});
return this.multipleMode ? usersSystemRole : usersSystemRole.slice(0, 1);
}
return roles[projectId];
};
static policy = 'identity:update_project';
static allowed = () => Promise.resolve(true);
get leftUserTable() {
return [
{
dataIndex: 'name',
title: t('Name'),
},
];
}
get rightUserTable() {
return [
{
dataIndex: 'name',
title: t('Name'),
},
{
title: t('Select System Role'),
dataIndex: 'id',
render: (id) => this.renderSelect(id),
},
];
}
renderSelect = (id) => {
let disable = false;
if (this.item.projects && this.item.projects[id]) {
// eslint-disable-next-line prefer-destructuring
disable = this.item.projects[id].filter(
(it) => it === this.adminRoleId
)[0];
}
// for test e2e, will delete by next patch
localStorage.setItem('test-project-role', this.projectRolesList(id));
localStorage.setItem('test-total-role', this.systemRoleList);
localStorage.setItem('test-actual', 'can get localstorage');
return (
<Select
size="small"
mode={this.multipleMode}
options={disable ? this.adminRoleList(id) : this.projectRolesList(id)}
defaultValue={disable ? this.adminRoleId : this.defaultRoles(id)}
onChange={this.onSubChange}
disabled={disable}
/>
);
};
onSubChange = (value, option) => {
if (
(this.multipleMode && value.length && option.length) ||
(!this.multipleMode && value && option)
) {
const { projectRoles } = this.state;
const { project_id } = this.multipleMode ? option[0] : option;
projectRoles[project_id] = this.multipleMode ? value : [value];
this.setState({ projectRoles });
} else {
this.setState({ projectRoles: {} });
}
};
get checkedList() {
const { domains } = this.domainStore;
return (domains || []).map((it) => ({
label: it.name,
value: it.id,
key: it.id,
})); }));
} }
get defaultValue() { get defaultValue() {
const { domain_id: domain } = this.item; const { name, systemRoles = [] } = this.item;
const data = { const roles = systemRoles.map((it) => it.id);
domain_id: domain || 'default', const role = roles[0];
}; if (role) {
return data; return { name, role };
}
return { name };
}
static policy = 'identity:list_roles';
static allowed(item, containerProps) {
const { match: { path = '' } = {} } = containerProps || {};
if (path.indexOf('domain-admin/detail') >= 0) {
return Promise.resolve(false);
}
return Promise.resolve(true);
} }
get formItems() { get formItems() {
const { projects } = this.item;
const { domainDefault } = this.state;
return [ return [
{ {
name: 'domain_id', name: 'name',
label: t('Affiliated Domain'), label: t('User'),
type: 'select', type: 'label',
checkOptions: this.checkedList, iconType: 'user',
checkBoxInfo: t('Show All Domain'),
options: this.domainList,
onChange: (e) => {
this.setState({
domainDefault: e,
});
},
required: true,
}, },
{ {
name: 'select_project', name: 'role',
type: 'transfer', label: t('Role'),
label: t('Project'), type: 'select',
leftTableColumns: this.leftUserTable, options: this.rolesList,
rightTableColumns: this.rightUserTable, loading: this.roleStore.systemRoles.isLoading,
dataSource: this.projectList
? this.projectList.filter((it) => it.domain_id === domainDefault)
: [],
disabled: false,
showSearch: true,
oriTargetKeys: projects ? Object.keys(projects) : [],
}, },
]; ];
} }
onSubmit = async (values) => { onSubmit = async (values) => {
const { projectRoles } = this.state; const { role: newRole } = values;
if (!this.multipleMode) { const { systemRoles: oldRoles, id } = this.item;
// If it is not multiple choices, role only takes the first item of the array
Object.keys(projectRoles).forEach((key) => {
projectRoles[key] = projectRoles[key].slice(0, 1);
});
}
const { id: user_id, projects } = this.item;
const oldProjectRoles = projects;
const defaultProjects = Object.keys(oldProjectRoles);
const promiseList = []; const promiseList = [];
defaultProjects.forEach((id) => { const newRoles = newRole ? [newRole] : [];
if (values.select_project && !values.select_project.includes(id)) { const oldRoleIds = oldRoles.map((it) => it.id);
(oldProjectRoles[id] || []).forEach((role_id) => { oldRoles.forEach((role) => {
promiseList.push( const { id: roleId } = role;
globalProjectStore.removeUserRole({ id, user_id, role_id }) if (!newRoles.includes(roleId)) {
); promiseList.push(this.store.deleteSystemRole({ id, roleId }));
});
} else {
(oldProjectRoles[id] || []).forEach((role_id) => {
if (projectRoles[id] && !projectRoles[id].includes(role_id)) {
promiseList.push(
globalProjectStore.removeUserRole({ id, user_id, role_id })
);
}
});
}
});
(values.select_project || []).forEach((id) => {
if (defaultProjects && !defaultProjects.includes(id)) {
if (projectRoles[id]) {
projectRoles[id].forEach((role_id) => {
promiseList.push(
globalProjectStore.assignUserRole({ id, user_id, role_id })
);
});
} else {
promiseList.push(
globalProjectStore.assignUserRole({
id,
user_id,
role_id: this.systemRoleList[0].id,
})
);
}
} else {
(projectRoles[id] || []).forEach((role_id) => {
if (
(oldProjectRoles[id] && !oldProjectRoles[id].includes(role_id)) ||
!oldProjectRoles[id]
) {
promiseList.push(
globalProjectStore.assignUserRole({ id, user_id, role_id })
);
} }
}); });
newRoles.forEach((roleId) => {
if (!oldRoleIds.includes(roleId)) {
promiseList.push(this.store.assignSystemRole({ id, roleId }));
} }
}); });
const results = await Promise.all(promiseList); const results = await Promise.all(promiseList);
return results; return results;
}; };
} }
export default inject('rootStore')(observer(SystemRole)); export default inject('rootStore')(observer(SystemRole));

View File

@ -17,23 +17,15 @@ import Delete from './Delete';
import Edit from './Edit'; import Edit from './Edit';
import Enable from './Enable'; import Enable from './Enable';
import Forbidden from './Forbidden'; import Forbidden from './Forbidden';
import SystemPermission from './SystemRole'; import SystemRole from './SystemRole';
import Password from './Password'; import Password from './Password';
const actionConfigs = { const actionConfigs = {
rowActions: {
moreActions: [],
},
batchActions: [],
primaryActions: [],
};
const adminConfigs = {
rowActions: { rowActions: {
firstAction: Edit, firstAction: Edit,
moreActions: [ moreActions: [
{ {
action: SystemPermission, action: SystemRole,
}, },
// { // {
// action: DomainPermission, // action: DomainPermission,
@ -59,4 +51,4 @@ const adminConfigs = {
primaryActions: [Create], primaryActions: [Create],
}; };
export default { actionConfigs, adminConfigs }; export default actionConfigs;

View File

@ -1,256 +0,0 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { inject, observer } from 'mobx-react';
import globalGroupStore from 'stores/keystone/user-group';
import globalUserStore from 'stores/keystone/user';
import { ModalAction } from 'containers/Action';
import globalProjectStore from 'stores/keystone/project';
import globalRoleStore from 'stores/keystone/role';
import { getPasswordOtherRule, phoneNumberValidate } from 'utils/validate';
import globalDomainStore from 'stores/keystone/domain';
import { statusTypes } from 'resources/keystone/domain';
export class CreateForm extends ModalAction {
init() {
this.store = globalUserStore;
this.userGroupStore = globalGroupStore;
this.projectStore = globalProjectStore;
this.roleStore = globalRoleStore;
this.domainStore = globalDomainStore;
this.getAllUser();
this.getUserGroup();
this.getProject();
this.getRole();
// this.getDomains();
}
get name() {
return t('Create User');
}
async getAllUser() {
this.allUser = await this.store.pureFetchList();
}
getUserGroup() {
this.userGroupStore.fetchList();
}
getProject() {
this.store.fetchProject();
}
getRole() {
this.roleStore.fetchList();
}
static id = 'user-create';
static title = t('Create User');
static policy = [
'identity:create_user',
'identity:update_user',
'identity:list_roles',
'identity:list_projects',
'identity:list_domains',
];
checkName = (rule, value) => {
if (!value) {
return Promise.reject(t('Please input'));
}
const nameUsed = this.allUser.find((i) => i.name === value);
if (nameUsed) {
return Promise.reject(t('Invalid: User name can not be duplicated'));
}
return Promise.resolve();
};
static allowed(item, containerProps) {
const {
match: { path },
} = containerProps;
if (path.indexOf('domain-admin/detail') >= 0) {
return Promise.resolve(false);
}
return Promise.resolve(true);
}
get defaultValue() {
const { name } = this.item;
const data = {
domain_name: name,
password: '',
confirmPassword: '',
enabled: statusTypes[0].value,
};
return data;
}
get nameForStateUpdate() {
return ['password', 'confirmPassword'];
}
get domainList() {
const { domains } = this.store;
return (domains || []).map((it) => ({
label: it.name,
value: it.id,
}));
}
get projectList() {
const { projects } = this.store;
return (projects || []).map((it) => ({
label: it.name,
value: it.id,
}));
}
get userGroupList() {
return (this.userGroupStore.list.data || []).map((it) => ({
...it,
key: it.id,
}));
}
get projects() {
return (this.projectStore.list.data || []).map((it) => ({
...it,
key: it.id,
}));
}
get roleList() {
return (this.roleStore.list.data || []).map((it) => ({
label: it.name,
value: it.id,
}));
}
static allowed = () => Promise.resolve(true);
get formItems() {
// const { more } = this.state;
// const labelCol = {
// xs: { span: 5 },
// sm: { span: 6 },
// };
return [
{
name: 'name',
label: t('User Name'),
type: 'input',
validator: this.checkName,
placeholder: t('Please input user name'),
required: true,
},
{
name: 'email',
label: t('Email'),
type: 'input',
required: true,
},
{
name: 'password',
label: t('Password'),
type: 'input-password',
required: true,
otherRule: getPasswordOtherRule('password'),
},
{
name: 'confirmPassword',
label: t('Confirm Password'),
type: 'input-password',
dependencies: ['password'],
required: true,
otherRule: getPasswordOtherRule('confirmPassword'),
},
{
name: 'phone',
label: t('Phone'),
validator: phoneNumberValidate,
type: 'phone',
required: true,
},
{
name: 'domain_name',
label: t('Affiliated Domain'),
type: 'input',
disabled: true,
help: t('The affiliated Domain cannot be modified after creation'),
},
{
name: 'enabled',
label: t('Status'),
type: 'radio',
optionType: 'default',
options: statusTypes,
required: true,
},
// {
// name: 'default_project_id',
// label: t('Main Project'),
// type: 'select',
// options: this.projectList,
// },
{
name: 'description',
label: t('Description'),
type: 'textarea',
},
{
name: 'real_name',
label: t('Real Name'),
type: 'input',
required: true,
},
];
}
get instanceName() {
const { name } = this.values || {};
return name;
}
onSubmit = (values) => {
const {
name,
email,
password,
phone,
enabled,
default_project_id,
description,
real_name,
} = values;
const { id: domain_id } = this.item;
const data = {
name,
email,
password,
phone,
domain_id,
enabled,
description,
real_name,
default_project_id,
};
return this.store.create(data);
};
}
export default inject('rootStore')(observer(CreateForm));

View File

@ -1,52 +0,0 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Create from './Create';
import Delete from '../actions/Delete';
import Edit from '../actions/Edit';
import Enable from '../actions/Enable';
import Forbidden from '../actions/Forbidden';
import Password from '../actions/Password';
const actionConfigs = {
rowActions: {
moreActions: [],
},
batchActions: [],
primaryActions: [],
};
const adminConfigs = {
rowActions: {
firstAction: Edit,
moreActions: [
{
action: Password,
},
{
action: Delete,
},
{
action: Enable,
},
{
action: Forbidden,
},
],
},
batchActions: [Delete],
primaryActions: [Create],
};
export default { actionConfigs, adminConfigs };

View File

@ -14,28 +14,15 @@
import React from 'react'; import React from 'react';
import { observer, inject } from 'mobx-react'; import { observer, inject } from 'mobx-react';
import { Badge, Table, Popover } from 'antd';
import Base from 'containers/List'; import Base from 'containers/List';
import globalUserStore, { UserStore } from 'stores/keystone/user'; import globalUserStore, { UserStore } from 'stores/keystone/user';
import { yesNoOptions, emptyActionConfig } from 'utils/constants'; import { yesNoOptions, emptyActionConfig } from 'utils/constants';
import { Link } from 'react-router-dom';
import { FileTextOutlined } from '@ant-design/icons';
import { enabledColumn } from 'resources/keystone/domain'; import { enabledColumn } from 'resources/keystone/domain';
import actionConfigs from './actions'; import actionConfigs from './actions';
import actionConfigsInDomain from './actionsInDomain';
export class User extends Base { export class User extends Base {
init() { init() {
this.store = this.inDetailPage ? new UserStore() : globalUserStore; this.store = this.inDetailPage ? new UserStore() : globalUserStore;
this.getDomains();
}
getDomains() {
this.store.fetchDomain();
}
get tabs() {
return [];
} }
get policy() { get policy() {
@ -74,126 +61,79 @@ export class User extends Base {
return this.inDetailPage && path.includes('identity/role-admin'); return this.inDetailPage && path.includes('identity/role-admin');
} }
getColumns() { getBaseColumns() {
// const { return [
// match: { path },
// } = this.props;
const columns = [
{ {
title: t('User ID/Name'), title: t('User ID/Name'),
dataIndex: 'name', dataIndex: 'name',
routeName: 'userDetailAdmin', routeName: 'userDetailAdmin',
}, },
{
title: t('Project Scope'),
dataIndex: 'projects',
isHideable: true,
render: (value) => {
if (value && value.length) {
return value.map((it) => {
const { id, name } = it;
const url = `/identity/project-admin/detail/${id}`;
return <Link to={url}>{name}</Link>;
});
}
},
stringify: (value) => value.map((it) => it.name).join('; '),
},
{
title: t('Roles'),
dataIndex: 'project_roles',
isHideable: true,
render: (project_roles) => {
if (project_roles && project_roles[0]) {
return project_roles.map((it, idx) => <div key={idx}>{it}</div>);
}
},
},
{ {
title: t('Real Name'), title: t('Real Name'),
dataIndex: 'real_name', dataIndex: 'real_name',
isHideable: true, isHideable: true,
}, },
{
title: t('Roles'),
dataIndex: 'projectRoles',
isHideable: true,
render: (_, record) => {
const { projects } = record;
return Object.values(projects).map((it) => {
const { roles = [] } = it || {};
return roles.map((role) => {
return <div key={role.id}>{role.name}</div>;
});
});
},
stringify: (_, record) => {
const { projects } = record;
return Object.values(projects).map((it) => {
const { roles = [] } = it || {};
return roles
.map((role) => {
return role.name;
})
.join(', ');
});
},
},
{
title: t('Project Scope'),
dataIndex: 'projects',
isHideable: true,
render: (value) => {
return Object.values(value).map((it) => {
const {
project: { id, name },
} = it;
const link = this.getLinkRender('projectDetail', name, {
id,
});
return <div key={id}>{link}</div>;
});
},
stringify: (value) => {
return Object.values(value)
.map((it) => {
const { project } = it;
return project.name;
})
.join('; ');
},
},
{ {
title: t('Affiliated Domain'), title: t('Affiliated Domain'),
dataIndex: 'domain_name', dataIndex: 'domainName',
isHideable: true, isHideable: true,
}, },
{ {
title: t('Project Num'), title: t('System Roles'),
dataIndex: 'project_num', dataIndex: 'systemRoles',
render: (project_num) => {
if (project_num === 0) {
return <Badge color="red" text={project_num} />;
}
return <Badge color="green" text={project_num} />;
},
},
{
title: t('Project Num'),
dataIndex: 'projectItems',
render: (_, record) => {
const { project_num } = record;
if (project_num === 0) {
return <Badge color="red" text={project_num} />;
}
const { projectItems = [] } = record;
const projectColumns = [
{
title: t('Project'),
dataIndex: 'name',
key: 'id',
render: (value, data) => {
const url = `/identity/project-admin/detail/${data.id}`;
return <Link to={url}>{value}</Link>;
},
},
{
title: t('Role'),
dataIndex: 'roles',
key: 'roles',
render: (value) => { render: (value) => {
if (!value) { return (value || []).map((it) => <div key={it.id}>{it.name}</div>);
return '-';
}
return value.map((it) => it.name).join(', ');
},
},
];
const table = (
<Table
columns={projectColumns}
dataSource={projectItems}
pagination={false}
rowKey="id"
size="small"
/>
);
return (
<>
<Badge color="green" text={project_num} />
<Popover
getPopupContainer={(node) => node.parentNode}
placement="right"
content={table}
destroyTooltipOnHide
>
<FileTextOutlined />
</Popover>
</>
);
},
stringify: (value, record) => {
const { project_num, projectItems = [] } = record;
const projectRoleStr = projectItems
.map((it) => {
const { name, roles } = it;
const roleStr = roles.map((role) => role.name).join(', ');
return `${name}: ${roleStr}`;
})
.join('\n');
return `${project_num}\n${projectRoleStr}`;
}, },
stringify: (value) => (value || []).map((it) => it.name).join('; '),
}, },
{ {
title: t('Email'), title: t('Email'),
@ -207,58 +147,35 @@ export class User extends Base {
}, },
enabledColumn, enabledColumn,
]; ];
if (!this.inDetailPage) {
return columns.filter(
(it) =>
!['project_roles', 'projects', 'project_num'].includes(it.dataIndex)
);
} }
if (this.inUserGroupDetail) {
getColumns() {
const columns = this.getBaseColumns();
if (!this.inDetailPage || this.inUserGroupDetail) {
return columns.filter( return columns.filter(
(it) => (it) => !['projectRoles', 'projects'].includes(it.dataIndex)
!['project_roles', 'projects', 'projectItems'].includes(it.dataIndex)
); );
} }
if (this.inDomainDetail) { if (this.inDomainDetail) {
return columns.filter( return columns.filter(
(it) => (it) => !['domain', 'projects', 'projectRoles'].includes(it.dataIndex)
![
'project_roles',
'projects',
'domain_name',
'projectItems',
].includes(it.dataIndex)
); );
} }
if (this.inRoleDetail) { if (this.inRoleDetail) {
return columns.filter( return columns.filter((it) => !['projectRoles'].includes(it.dataIndex));
(it) =>
!['project_roles', 'project_num', 'projectItems'].includes(
it.dataIndex
)
);
} }
if (this.inProjectDetail) { if (this.inProjectDetail) {
return columns.filter( return columns.filter((it) => !['projects'].includes(it.dataIndex));
(it) => !['projects', 'projectItems'].includes(it.dataIndex)
);
} }
return columns; return columns;
} }
get actionConfigs() { get actionConfigs() {
if (this.inDomainDetail) { if (this.inDetailPage) {
return this.isAdminPage
? actionConfigsInDomain.adminConfigs
: actionConfigsInDomain.actionConfigs;
}
if (!this.inDetailPage) {
return this.isAdminPage
? actionConfigs.adminConfigs
: actionConfigs.actionConfigs;
}
return emptyActionConfig; return emptyActionConfig;
} }
return actionConfigs;
}
get searchFilters() { get searchFilters() {
return [ return [
@ -278,31 +195,32 @@ export class User extends Base {
]; ];
} }
async getData({ silent, ...params } = {}) { updateFetchParams = (params) => {
const { match } = this.props; const { match } = this.props;
const { id } = match.params || {};
const newParams = { ...params }; const newParams = { ...params };
silent && (this.list.silent = true); if (this.inUserGroupDetail) {
if (this.inDomainDetail) {
const { id } = match.params;
newParams.domainId = id;
await this.store.fetchListInDomainDetail(newParams);
} else if (this.inProjectDetail) {
const { id } = match.params;
newParams.projectId = id;
await this.store.fetchListInProjectDetail(newParams);
} else if (this.inUserGroupDetail) {
const { id } = match.params;
newParams.groupId = id; newParams.groupId = id;
await this.store.fetchListInGroupDetail(newParams); newParams.withProjectRole = false;
newParams.withSystemRole = true;
} else if (this.inDomainDetail) {
newParams.domain_id = id;
newParams.withProjectRole = false;
newParams.withSystemRole = true;
} else if (this.inProjectDetail) {
newParams.projectId = id;
newParams.withProjectRole = true;
newParams.withSystemRole = true;
} else if (this.inRoleDetail) { } else if (this.inRoleDetail) {
const { id } = match.params;
newParams.roleId = id; newParams.roleId = id;
await this.store.fetchListInRoleDetail(newParams); newParams.withProjectRole = true;
} else { newParams.withSystemRole = true;
await this.store.fetchList(newParams); } else if (!this.inDetailPage) {
} newParams.withProjectRole = false;
this.list.silent = false; newParams.withSystemRole = true;
} }
return newParams;
};
} }
export default inject('rootStore')(observer(User)); export default inject('rootStore')(observer(User));

View File

@ -47,7 +47,7 @@ export class ManageUser extends ModalAction {
} }
getAllUser() { getAllUser() {
this.userStore.fetchAllWithDomain(); this.userStore.fetchList({ withProjectRole: false, withSystemRole: false });
} }
async getGroupUsers() { async getGroupUsers() {

View File

@ -13,7 +13,6 @@
// limitations under the License. // limitations under the License.
import { action, observable } from 'mobx'; import { action, observable } from 'mobx';
import { get } from 'lodash';
import List from 'stores/base-list'; import List from 'stores/base-list';
import client from 'client'; import client from 'client';
import globalRootStore from 'stores/root'; import globalRootStore from 'stores/root';
@ -22,27 +21,9 @@ import globalGroupStore from 'stores/keystone/user-group';
import Base from 'stores/base'; import Base from 'stores/base';
export class UserStore extends Base { export class UserStore extends Base {
@observable
domains = [];
@observable
roleAssignments = [];
@observable @observable
userProjects = new List(); userProjects = new List();
@observable
userGroups = new List();
@observable
projects = [];
@observable
systemRoles = [];
@observable
domainRoles = [];
get client() { get client() {
return client.keystone.users; return client.keystone.users;
} }
@ -75,13 +56,37 @@ export class UserStore extends Base {
return client.keystone.groups; return client.keystone.groups;
} }
listFetchByClient(params, originParams) {
const { groupId } = originParams;
if (groupId) {
return this.groupClient.users.list(groupId, params);
}
return this.client.list(params);
}
get paramsFunc() {
return (params) => {
const {
id,
projectId,
groupId,
roleId,
withProjectRole,
withSystemRole,
all_projects,
...rest
} = params;
return rest;
};
}
@action @action
async create(values) { async create(values) {
const body = {}; const body = {};
const { const {
select_project = [], select_project,
select_user_group = [], select_user_group = [],
newProjectRoles, projectRoles,
defaultRole, defaultRole,
...other ...other
} = values; } = values;
@ -90,54 +95,31 @@ export class UserStore extends Base {
this.isSubmitting = true; this.isSubmitting = true;
const result = await this.client.create(body); const result = await this.client.create(body);
const { const {
user: { id: user_id }, user: { id: userId },
} = result; } = result;
const promiseList = []; const promiseList = [];
if (select_user_group[0] || select_project[0]) { select_user_group.forEach((groupId) => {
const newProjects = Object.keys(newProjectRoles); promiseList.push(this.addGroupUsers(groupId, userId));
select_user_group.forEach((id) => { });
promiseList.push(
globalGroupStore.addGroupUsers({ id, userId: user_id }) Object.keys(projectRoles).forEach((projectId) => {
); const roles = projectRoles[projectId];
roles.forEach((roleId) => {
promiseList.push(this.addProjectUser(projectId, userId, roleId));
}); });
select_project.forEach((id) => {
if (!newProjects.includes(id)) {
const roleId = defaultRole;
promiseList.push(
globalProjectStore.assignUserRole({ id, userId: user_id, roleId })
);
} else {
promiseList.push(
globalProjectStore.assignUserRole({
id,
userId: user_id,
roleId: newProjectRoles[id],
})
);
}
}); });
await Promise.all(promiseList); await Promise.all(promiseList);
}
this.isSubmitting = false; this.isSubmitting = false;
return result; return result;
} }
@action addGroupUsers = (groupId, userId) => {
async fetchDomain() { return globalGroupStore.addGroupUsers({ id: groupId, userId });
const domainsResult = await this.domainClient.list(); };
this.domains = domainsResult.domains;
} addProjectUser = (projectId, userId, roleId) => {
return globalProjectStore.assignUserRole({ id: projectId, userId, roleId });
get mapper() {
return (item) => {
const domain = this.domains.find((it) => it.id === item.domain_id);
if (domain) {
item.domain_name = domain.name;
item.domainName = domain.name;
}
return item;
}; };
}
@action @action
async getUserProjects() { async getUserProjects() {
@ -157,166 +139,166 @@ export class UserStore extends Base {
return projects; return projects;
} }
@action getProjectMapRoles = (user, projectRoleAssignments, roles, projects) => {
async getUserGroups() { const projectMapRoles = {};
this.userGroups.update({ const { id } = user;
isLoading: true, projectRoleAssignments.forEach((roleAssignment) => {
});
const { const {
user: { scope: { project: { id: projectId } = {} } = {},
user: { id }, role: { id: roleId } = {},
}, user: { id: userId } = {},
} = globalRootStore;
const { groups } = await this.client.groups.list(id);
this.userGroups.update({
data: groups,
isLoading: false,
});
}
@action
getUserProjectRole = (user, roleAssignment, projectMapRole) => {
if (roleAssignment.user) {
const {
user: { id: user_id },
role: { id: role_id },
scope: { project: { id } = {} } = {},
} = roleAssignment; } = roleAssignment;
if (id && user_id === user.id) { if (userId === id && roleId && projectId) {
if (projectMapRole[id]) { const roleItem = roles.find((it) => it.id === roleId);
projectMapRole[id].push(role_id); if (!projectMapRoles[projectId]) {
const projectItem = projects.find((it) => it.id === projectId);
projectMapRoles[projectId] = {
project: projectItem,
roles: [roleItem],
};
} else { } else {
projectMapRole[id] = [role_id]; projectMapRoles[projectId].roles = [
} ...projectMapRoles[projectId].roles,
roleItem,
];
} }
} }
});
return projectMapRoles;
}; };
getUserProjectWithRole = (projectMapRole, roles, projects) => { // eslint-disable-next-line no-unused-vars
return Object.keys(projectMapRole).map((key) => { getSystemRoles = (user, systemRoleAssignments, roles, projects) => {
const item = projects.find((it) => it.id === key); const systemRoles = [];
const roleItems = projectMapRole[key].map((roleId) => const { id } = user || {};
roles.find((it) => it.id === roleId) systemRoleAssignments.forEach((roleAssignment) => {
); const { role: { id: roleId } = {}, user: { id: userId } = {} } =
item.roles = roleItems; roleAssignment;
return item; if (userId === id && roleId) {
const roleItem = roles.find((it) => it.id === roleId);
systemRoles.push(roleItem);
}
}); });
return systemRoles;
}; };
@action updateUser = (
async fetchList({ user,
limit, projectRoleAssignments,
page, systemAssigns,
sortKey,
sortOrder,
conditions,
timeFilter,
...filters
} = {}) {
this.list.isLoading = true;
// todo: no page, no limit, fetch all
const [roleAssignmentsResult, usersResult, roleResult, projectResult] =
await Promise.all([
this.roleAssignmentClient.list(),
this.client.list(),
this.roleClient.list(),
this.projectClient.list(),
]);
const { users } = usersResult;
const { roles } = roleResult;
const systemRoles = roles.filter(
(it) =>
(it.name.includes('system_') && !it.name.includes('_system_')) ||
it.name === 'admin'
);
const systemRoleId = systemRoles.map((it) => it.id);
users.map((user) => {
const projectMapRole = {}; // { project_id: [roles_id] }
const projectMapSystemRole = {}; // { project_id: [systemRoles_id] }
roleAssignmentsResult.role_assignments.forEach((roleAssignment) => {
this.getUserProjectRole(user, roleAssignment, projectMapRole);
});
this.getUsersSystemRole(
projectMapRole,
systemRoleId,
projectMapSystemRole
);
user.projectItems = this.getUserProjectWithRole(
projectMapRole,
roles, roles,
projectResult.projects projects,
domains
) => {
const projectMapRoles = this.getProjectMapRoles(
user,
projectRoleAssignments,
roles,
projects
); );
user.projects = projectMapRole; const systemRoles = this.getSystemRoles(
user.projectMapSystemRole = projectMapSystemRole; user,
user.project_num = Object.keys(projectMapRole).length; systemAssigns,
return users; roles,
}); projects
const newData = users.map(this.mapper);
this.list.update({
data: newData,
total: newData.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
timeFilter,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return newData;
}
@action
async fetchDetail({ id, silent }) {
if (!silent) {
this.isLoading = true;
}
const [roleAssignmentsResult, usersResult, roleResult] = await Promise.all([
this.roleAssignmentClient.list(),
this.client.show(id),
this.roleClient.list(),
]);
const { roles } = roleResult;
const systemRoles = roles.filter(
(it) =>
(it.name.includes('system_') && !it.name.includes('_system_')) ||
it.name === 'admin'
); );
const systemRoleId = systemRoles.map((it) => it.id); const domain = domains.find((it) => it.id === user.domain_id);
const { user } = usersResult; return {
const projectMapRole = {}; ...user,
const projectMapSystemRole = {}; projects: projectMapRoles,
roleAssignmentsResult.role_assignments.forEach((roleAssignment) => { projectCount: Object.keys(projectMapRoles).length,
this.getUserProjectRole(user, roleAssignment, projectMapRole); domain,
}); domainName: (domain || {}).name || user.domain_id,
this.getUsersSystemRole(projectMapRole, systemRoleId, projectMapSystemRole); systemRoles,
user.projects = projectMapRole;
user.projectMapSystemRole = projectMapSystemRole;
user.project_num = Object.keys(projectMapRole).length;
this.detail = user;
this.isLoading = false;
return user;
}
@action
async pureFetchDetail({ id, silent }) {
return super.fetchDetail({ id, silent });
}
@action
getUsersSystemRole = (projectMapRole, systemRoleId, projectMapSystemRole) => {
const systemProject = Object.keys(projectMapRole);
systemProject.forEach((project_id) => {
const roles = projectMapRole[project_id].filter((role_id) =>
systemRoleId.includes(role_id)
);
if (roles[0]) {
projectMapSystemRole[project_id] = roles;
}
});
}; };
};
async listDidFetch(items, allProjects, filters) {
if (!items.length) {
return items;
}
const {
withProjectRole = true,
withSystemRole = true,
projectId,
roleId,
domain_id,
} = filters;
const withRole = withProjectRole || withSystemRole;
const params = {};
if (roleId) {
params['role.id'] = roleId;
}
if (projectId) {
params['scope.project.id'] = projectId;
}
const reqs = [
withProjectRole ? this.roleAssignmentClient.list(params) : null,
withSystemRole
? this.roleAssignmentClient.list({ 'scope.system': 'all' })
: null,
withRole ? this.roleClient.list() : null,
withProjectRole ? this.projectClient.list() : null,
domain_id ? null : this.domainClient.list(),
];
const [
projectRoleAssignmentsResult,
systemRoleAssignmentsResult,
roleResult,
projectResult,
domainResult,
] = await Promise.all(reqs);
const { roles = [] } = roleResult || {};
const { domains = [] } = domainResult || {};
const { role_assignments: assigns = [] } =
projectRoleAssignmentsResult || {};
const { role_assignments: systemAssigns = [] } =
systemRoleAssignmentsResult || {};
const { projects = [] } = projectResult || {};
const newItems = items.map((user) => {
return this.updateUser(
user,
assigns,
systemAssigns,
roles,
projects,
domains
);
});
if (projectId) {
return newItems.filter((it) => !!it.projectCount);
}
if (roleId) {
return newItems.filter((it) => {
const { projectCount, systemRoles } = it;
if (projectCount) {
return true;
}
const systemRole = systemRoles.find((role) => role.id === roleId);
return !!systemRole;
});
}
return newItems;
}
async detailDidFetch(item) {
const { id } = item;
const params = { 'user.id': id, 'scope.system': 'all' };
const reqs = [
this.roleAssignmentClient.list(params),
this.roleClient.list(),
this.domainClient.list(),
];
const [systemRoleAssignmentsResult, roleResult, domainResult] =
await Promise.all(reqs);
const { roles = [] } = roleResult || {};
const { domains = [] } = domainResult;
const { role_assignments: systemAssigns = [] } =
systemRoleAssignmentsResult || {};
return this.updateUser(item, [], systemAssigns, roles, [], domains);
}
@action @action
async enable({ id }) { async enable({ id }) {
@ -351,50 +333,13 @@ export class UserStore extends Base {
} }
@action @action
async fetchProject() { async assignSystemRole({ id, roleId }) {
const projectsResult = await this.projectClient.list(); return this.systemUserClient.roles.update(id, roleId);
this.projects = projectsResult.projects;
} }
@action @action
async fetchSystemRole({ id, projects }) { async deleteSystemRole({ id, roleId }) {
this.systemRoles = []; return this.systemUserClient.roles.delete(id, roleId);
const project_id = projects[0].id;
const projectResult = await this.projectClient.users.roles.list(
project_id,
id
);
const systemRole = projectResult.roles.filter(
(it) => it.name.includes('system_') && !it.name.includes('_system_')
);
this.systemRoles = systemRole;
}
@action
async assignSystemRole({ id, role_id }) {
return this.systemUserClient.roles.update(id, role_id);
}
@action
async deleteSystemRole({ id, role_id }) {
return this.systemUserClient.delete(id, role_id);
}
@action
async fetchDomainRole({ id, domain_id }) {
this.domainRoles = [];
const rolesResult = await this.domainClient.users.roles.list(id, domain_id);
this.domainRoles = rolesResult.roles;
}
@action
async assignDomainRole({ id, role_id, domain_id }) {
return this.domainClient.users.roles.update(domain_id, id, role_id);
}
@action
async deleteDomainRole({ id, role_id, domain_id }) {
return this.domainClient.users.roles.delete(domain_id, id, role_id);
} }
@action @action
@ -410,240 +355,6 @@ export class UserStore extends Base {
}; };
return this.submitting(this.client.patch(id, reqBody)); return this.submitting(this.client.patch(id, reqBody));
} }
@action
async fetchListInDomainDetail({
limit,
page,
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
const { domainId } = filters;
const params = {};
const result = await this.client.list(params);
let data = get(result, this.listResponseKey, []);
data = data.filter((it) => it.domain_id === domainId);
const items = data.map(this.mapper);
const newData = await this.listDidFetch(items);
Promise.all(newData.map((it) => this.client.projects.list(it.id))).then(
(projectResult) => {
newData.map((it, index) => {
const { projects } = projectResult[index];
it.projects = projects;
it.project_num = projects.length;
return it;
});
this.list.update({
data: newData,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return items;
}
);
}
@action
async fetchListInProjectDetail({
limit,
page,
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
const { projectId } = filters;
const params = {};
const [roleAssignmentsResult, roleResult, result] = await Promise.all([
this.roleAssignmentClient.list(),
this.roleClient.list(),
this.client.list(params),
]);
const projectUserIds = [];
const userMapRole = {};
roleAssignmentsResult.role_assignments.forEach((roleAssignment) => {
if (roleAssignment.user) {
const {
user: { id: user_id },
role: { id: role_id },
scope: { project: { id } = {} } = {},
} = roleAssignment;
if (id && id === projectId) {
projectUserIds.push(user_id);
if (userMapRole[user_id]) {
userMapRole[user_id].push(role_id);
} else {
userMapRole[user_id] = [role_id];
}
}
}
});
let data = get(result, this.listResponseKey, []);
data = data.filter((it) => projectUserIds.includes(it.id));
const items = data.map(this.mapper);
const newData = await this.listDidFetch(items);
Promise.all(newData.map((it) => this.client.projects.list(it.id))).then(
(projectResult) => {
newData.map((it, index) => {
const { projects } = projectResult[index];
it.projects = projects;
it.project_num = projects.length;
it.project_roles = userMapRole[it.id].map(
(r) => roleResult.roles.filter((role) => role.id === r)[0].name
);
return it;
});
this.list.update({
data: newData,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return items;
}
);
}
@action
async fetchListInGroupDetail({
limit,
page,
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
const { groupId } = filters;
const params = {};
const result = await this.groupClient.users.list(groupId, params);
const data = get(result, this.listResponseKey, []);
const items = data.map(this.mapper);
const newData = await this.listDidFetch(items);
Promise.all(newData.map((it) => this.client.projects.list(it.id))).then(
(projectResult) => {
newData.map((it, index) => {
const { projects } = projectResult[index];
it.projects = projects;
it.project_num = projects.length;
return it;
});
this.list.update({
data: newData,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return items;
}
);
}
@action
async fetchListInRoleDetail({
limit,
page,
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
const { roleId } = filters;
const params = {};
const [roleAssignmentsResult, projectResult, result] = await Promise.all([
this.roleAssignmentClient.list(),
this.projectClient.list(),
this.client.list(params),
]);
const projectRoleUsers = {};
const systemRoleUsers = {};
roleAssignmentsResult.role_assignments.forEach((roleAssignment) => {
if (roleAssignment.user) {
const {
user: { id: user_id },
role: { id: role_id },
scope: { project, system } = {},
} = roleAssignment;
if (role_id === roleId && project) {
const projectData = projectResult.projects.find(
(it) => it.id === project.id
);
if (projectRoleUsers[user_id]) {
projectRoleUsers[user_id].push(projectData);
} else {
projectRoleUsers[user_id] = [projectData];
}
} else if (role_id === roleId && system) {
systemRoleUsers[user_id] = system.all;
}
}
});
const data = get(result, this.listResponseKey, []);
const items = data
.filter((it) => projectRoleUsers[it.id] || systemRoleUsers[it.id])
.map((it) => ({
projects: projectRoleUsers[it.id] || [],
systemScope: systemRoleUsers[it.id] || [],
...it,
}));
const newData = items.map(this.mapper);
// const newData = await this.listDidFetch(items);
this.list.update({
data: newData,
total: newData.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return newData;
}
@action
async fetchAllWithDomain() {
this.list.isLoading = true;
await this.fetchDomain();
const result = await this.client.list();
const data = get(result, this.listResponseKey, []);
const items = data.map(this.mapper);
const newData = await this.listDidFetch(items);
this.list.update({
data: newData,
total: items.length || 0,
isLoading: false,
});
return items;
}
} }
const globalUserStore = new UserStore(); const globalUserStore = new UserStore();

View File

@ -20,9 +20,6 @@ import { getQueryString } from 'utils/index';
import { setLocalStorageItem } from 'utils/local-storage'; import { setLocalStorageItem } from 'utils/local-storage';
import { isEmpty, values } from 'lodash'; import { isEmpty, values } from 'lodash';
const checkItemPolicy = require('resources/skyline/policy').default;
const { onlyAdminCanReadPolicy } = require('resources/skyline/policy');
export class RootStore { export class RootStore {
@observable @observable
user = null; user = null;
@ -115,23 +112,35 @@ export class RootStore {
return this.getUserProfileAndPolicy(); return this.getUserProfileAndPolicy();
} }
checkAdminRole(roles) { async getUserSystemRoles(user) {
if (checkItemPolicy({ policy: onlyAdminCanReadPolicy })) { // only user admin or system roles has admin/reader can go to administrator
const { id, name } = user;
if (name === 'admin') {
return true; return true;
} }
const regex = /^[\w-_]*(system_admin|system_reader)$/; try {
return roles.some((role) => regex.test(role.name)); const result = await client.keystone.systemUsers.roles.list(id);
const { roles = [] } = result;
return roles.some((it) => it.name === 'admin' || it.name === 'reader');
} catch (e) {
console.log(e);
return false;
}
} }
@action @action
updateUserRoles(user) { async updateUserRoles(user) {
const { roles = [], base_roles = [], base_domains } = user || {}; const {
roles = [],
base_roles = [],
base_domains,
user: userInfo = {},
} = user || {};
this.roles = roles; this.roles = roles;
this.baseRoles = base_roles; this.baseRoles = base_roles;
this.baseDomains = base_domains; this.baseDomains = base_domains;
// TODO: fix system/project admin/member/reader for W this.hasAdminPageRole = await this.getUserSystemRoles(userInfo);
this.hasAdminRole = checkItemPolicy({ policy: onlyAdminCanReadPolicy }); this.hasAdminRole = this.hasAdminPageRole;
this.hasAdminPageRole = this.checkAdminRole(roles);
} }
@action @action
@ -148,15 +157,9 @@ export class RootStore {
this.projectName = projectName; this.projectName = projectName;
this.license = license || {}; this.license = license || {};
this.version = version; this.version = version;
this.endpoints = endpoints;
this.updateUserRoles(user); this.updateUserRoles(user);
this.setKeystoneToken(user); this.setKeystoneToken(user);
this.endpoints = endpoints;
}
@action
async getUserPolices() {
const result = await this.client.policies.list();
this.policies = result.policies;
} }
checkLicense(key) { checkLicense(key) {
@ -183,7 +186,7 @@ export class RootStore {
this.client.profile(), this.client.profile(),
this.client.policies.list(), this.client.policies.list(),
]); ]);
this.updateUser(profile, policies.policies || []); await this.updateUser(profile, policies.policies || []);
return this.getNeutronExtensions(); return this.getNeutronExtensions();
} }

View File

@ -57,16 +57,13 @@ describe('The Project Page', () => {
.clickModalActionSubmitButton(); .clickModalActionSubmitButton();
}); });
// it('successfully manage user', () => { it('successfully manage user', () => {
// cy.tableSearchText(name) cy.tableSearchText(name)
// .clickActionInMore('Manage User') .clickActionInMore('Manage User')
// .wait(10000) .wait(10000)
// .formTransfer('select_user', username) .formTransfer('select_user', username)
// .formTransferRight('select_user', username) .clickModalActionSubmitButton();
// .wait(10000) });
// .formSelect('select_user', 'admin')
// .clickModalActionSubmitButton();
// });
it('successfully manage user group', () => { it('successfully manage user group', () => {
cy.tableSearchText(name) cy.tableSearchText(name)

View File

@ -54,8 +54,6 @@ describe('The User Page', () => {
.formButtonClick('more') .formButtonClick('more')
.wait(2000) .wait(2000)
.formTransfer('select_project', projectName) .formTransfer('select_project', projectName)
.formTransferRight('select_project', projectName)
.formSelect('select_project', 'admin')
.wait(2000) .wait(2000)
.formTransfer('select_user_group', userGroupName) .formTransfer('select_user_group', userGroupName)
.clickFormActionSubmitButton() .clickFormActionSubmitButton()
@ -75,20 +73,13 @@ describe('The User Page', () => {
cy.goBackToList(listUrl); cy.goBackToList(listUrl);
}); });
// it('successfully edit system permission', () => { it('successfully edit system permission', () => {
// cy.tableSearchText(name) cy.tableSearchText(name)
// .clickActionInMore('Edit System Permission') .clickActionInMore('Edit System Permission')
// .wait(10000) .wait(10000)
// .formTransfer('select_project', projectName2) .formSelect('role', 'admin')
// .formTransferRight('select_project', projectName2) .clickModalActionSubmitButton();
// .wait(10000) });
// .log('test-project-role', localStorage.getItem('test-project-role'))
// .log('test-total-role', localStorage.getItem('test-total-role'))
// .log('test-actual', localStorage.getItem('test-actual'))
// .wait(2000)
// .formSelect('select_project', 'admin')
// .clickModalActionSubmitButton();
// });
it('successfully forbidden user', () => { it('successfully forbidden user', () => {
cy.tableSearchText(name).clickConfirmActionInMore('Forbidden'); cy.tableSearchText(name).clickConfirmActionInMore('Forbidden');