import { immutable } from '../decorators'; import { View, Element, config } from '..'; import nuimsService from '../../service/nuims'; const roleName2Permission = new Map(); interface Role{ DomainName: string, RoleId: string, RoleName: string, RoleStatus: number, } interface RoleItem extends Role { permission?: Permission, checked?: Boolean, toggling?: Boolean, } interface Permission{ DomainName: string, PermissionId: string, PermissionValue: string, } interface PermissionResource{ Action: string, Description: string, DomainName: string, Label: string, ResourceId: string, ResourceType: string, ResourceValue: string, } interface Resource{ Description?: string, DomainName: string, Label?: string, ParentResourceType?: string, ParentResourceValue?: string, ReferenceCount?: string, ResourceId?: string, ResourceType: string, ResourceValue: string, } export class Nuims { /** * App Name */ @immutable() public readonly domainName: string = undefined; /** * 上报权限后的资源id */ @immutable() public readonly resourceId: string = undefined; /** * view */ @immutable() public readonly view: View = undefined; /** * element */ @immutable() public readonly element: Element = undefined; /** * @param source 需要合并的部分参数 */ constructor(source?: Partial) { const { domainName } = source; Object.assign(this, source); if (!domainName) { throw new Error('Nuims need domainName!'); } } async getInitRoles() { let isCreated = false; let resource = await this.getResource(); if (!resource) { isCreated = true; resource = await this.createResource(); } const { ResourceId, ResourceValue } = resource; Object.assign(this, { resourceId: ResourceId }); const roles = await this.getRoles(); const initRoles: RoleItem[] = await Promise.all(roles.map(async (role: Role) => { const roleItem: RoleItem = role; let permission = await this.getDefaultPermissionForRole(role); if (permission) { permission.PermissionValue = permission.PermissionValue || `${role.RoleName}-default-permission`; } else { permission = await this.createDefaultPermission(role); await this.bindRolesAndPermissions(role, permission); } roleName2Permission.set(role.RoleName, permission); // 创建 /dashboard 资源时自动关联 DEV-AdminRole 权限 if (isCreated && (ResourceValue === '/dashboard' || ((ResourceValue === '/index' || ResourceValue === '/user') && config.scope === 'h5')) && role.RoleName === 'DEV-AdminRole') { await this.attachPermissionResourceAction(); } roleItem.permission = permission; const resources = await this.getResourcesFromPermission(permission); roleItem.checked = !!resources.find((resource: Resource) => resource.ResourceId === ResourceId); roleItem.toggling = false; return roleItem; })); return initRoles; } /** * 绑定dev权限 * 用于用户创建页面、子页面的时候 * @returns */ async attachDevRole() { // 获取权限树资源Id let resource = await this.getResource(); if (!resource) { resource = await this.createResource(); } Object.assign(this, { resourceId: resource.ResourceId }); // 处理角色与默认权限 await this.handleDefaultPermisssionForRole(); // 绑定Dev role权限与资源 await this.attachPermissionResourceAction(); } async handleDefaultPermisssionForRole() { // 获取角色列表 const roles = await this.getRoles(); // 遍历角色列表,如果角色没有关联的默认权限,创建默认权限 const promises = roles.map(async (role: Role) => { let permission = await this.getDefaultPermissionForRole(role); if (permission) { permission.PermissionValue = permission.PermissionValue || `${role.RoleName}-default-permission`; } else { permission = await this.createDefaultPermission(role); await this.bindRolesAndPermissions(role, permission); } roleName2Permission.set(role.RoleName, permission); }); await Promise.all(promises); } /** * 获取当前资源 */ async getResource() { const resourceValue = this.getResourceValue(); const resource = await this.getResourceFromResourceValue(resourceValue); return resource; } /** * 创建资源 */ async createResource() { const resourceValue = this.getResourceValue(); await this.createResourceFromResourceValue(resourceValue); const resource = await this.getResourceFromResourceValue(resourceValue); return resource; } /** * 批量创建资源,创建当前 View / Element 及其子页面/元素关联的所有资源 */ async createResources() { if (this.element) { this.createElementResources(this.element); } } /** * 批量创建资源,创建 Element 及其子元素关联的所有资源 */ createElementResources(element: Element) { this.createResourceFromResourceValue(this.getResourceValueFromElement(element)); const { children } = element; if (children.length) { children.forEach((child: Element) => { this.createElementResources(child); }); } } /** * 删除当前 View / Element 及其子页面/元素关联的所有资源 */ deleteResources() { if (this.element) { this.deleteElementResources(this.element); } else { this.deleteViewResources(this.view); } } /** * 批量删除资源,删除 View 及其子页面关联的所有资源 */ deleteViewResources(view: View) { const { children, tempPath } = view; this.deleteResourceFromResourceValue(tempPath); if (children.length) { children.forEach((child: View) => { this.deleteViewResources(child); }); } } /** * 批量删除资源,删除 Element 及其子元素关联的所有资源 */ deleteElementResources(element: Element) { this.deleteResourceFromResourceValue(this.getResourceValueFromElement(element)); const { children } = element; if (children.length) { children.forEach((child: Element) => { this.deleteElementResources(child); }); } } /** * 根据 resourceValue 获取关联资源 */ async getResourceFromResourceValue(resourceValue: string) { if (!resourceValue) return; const { Data: resources } = await nuimsService.getResources({ query: { Limit: 1000, }, body: { filter: { DomainName: this.domainName, ResourceValue: resourceValue, ResourceType: 'ui', }, }, }); return resources.find((item: Resource) => item.ResourceValue === resourceValue); } /** * 根据 resourceValue 创建关联资源 */ async createResourceFromResourceValue(resourceValue: string) { if (!resourceValue) return; await nuimsService.createResources({ body: [{ DomainName: this.domainName, ResourceValue: resourceValue, ResourceType: 'ui', Description: this.getDescription(), }], }); } /** * 根据 resourceValue 删除关联资源 */ async deleteResourceFromResourceValue(resourceValue: string) { if (!resourceValue) return; try { await nuimsService.deleteResources({ body: [{ DomainName: this.domainName, ResourceValue: resourceValue, ResourceType: 'ui', }], config: { noErrorTip: true }, }); } catch (error) { console.error(error); } } /** * 根据 resourceValue 编辑关联资源 */ async editResourceFromResourceValue(resourceValue: string) { if (!resourceValue) return; const oldResource = await this.getResourceFromResourceValue(resourceValue); if (!oldResource) { return; } const { ResourceId } = oldResource; Object.assign(this, { resourceId: ResourceId }); await nuimsService.editResources({ body: [{ ResourceId, ResourceValue: this.getResourceValue() }], config: { noErrorTip: true }, }) } /** * 根据 Permission 获取关联资源 */ async getResourcesFromPermission(permission: Permission) { const res = await nuimsService.getPermissionResources({ query: { Limit: 1000, }, body: { DomainName: this.domainName, PermissionValue: permission.PermissionValue, filter: {}, }, }); return res.Data; } getResourceValueFromElement(element: Element) { return element.name ? `${element.view.tempPath}/${element.name}` : null; } getResourceValue() { return this.element ? this.getResourceValueFromElement(this.element) : this.view.tempPath; } getDescription() { return this.element ? this.element.view.title : this.view.title; } /** * 获取角色列表 */ async getRoles() { const res = await nuimsService.getRoles({ query: { DomainName: this.domainName, }, }); return res.Data; } /** * 1.创建角色 * 2.创建角色的默认权限 * 3.绑定角色和权限 */ async createDefaultRoleFromRoleName(roleName: string) { if (!roleName) return; const res = await nuimsService.createRole({ body: { DomainName: this.domainName, RoleName: roleName, }, }); const role = res.Data; const permission = await this.createDefaultPermission(role); await this.bindRolesAndPermissions(role, permission); } async getDefaultPermissionForRole(role: Role) { const { RoleName } = role; if (roleName2Permission.has(RoleName)) return roleName2Permission.get(RoleName); const permissionValue = `${RoleName}-default-permission`; const res = await nuimsService.getPermissionsForRole({ query: { Limit: 1000, }, body: { DomainName: this.domainName, RoleName, Filter: { PermissionValue: permissionValue, }, }, }); return res.Data[0]; } getPermissionResources(permission: Permission) { const { PermissionValue } = permission; return nuimsService.getPermissionResources({ query: { Limit: 1000, }, body: { DomainName: this.domainName, PermissionValue, filter: {}, }, }).then((res:any) => res.Data); } /** * 为角色创建默认权限 */ async createDefaultPermission(role: Role) { const { RoleName } = role; if (!RoleName) return; const { domainName } = this; const permissionValue = `${RoleName}-default-permission`; const permission = await nuimsService.getPermissions({ body: { filter: { DomainName: domainName, PermissionValue: permissionValue, }, }, }).then((res: any) => res.Data[0]); if (permission) return permission; const res = await nuimsService.createPermission({ body: { DomainName: domainName, PermissionValue: permissionValue, }, }); return Object.assign({ DomainName: domainName, PermissionValue: permissionValue }, res.Data); } /** * 关联角色和权限 */ bindRolesAndPermissions(role: Role, permission: Permission) { const { RoleId } = role; const { PermissionId } = permission; return nuimsService.bindRolesAndPermissions({ body: { RoleIdList: [RoleId], PermissionIdList: [PermissionId], }, }); } /** * 绑定权限和资源 */ async attachPermissionResourceAction() { const permission = roleName2Permission.get('DEV-AdminRole'); const { PermissionId } = permission; // 查找权限绑定的资源,如果该资源未绑定才需要调绑定接口 const resources = await this.getPermissionResources(permission); const checked = !!resources.find((item: PermissionResource) => item.ResourceId === this.resourceId); if (checked) { return; } try { await this.attachPermissionResource(PermissionId); } catch (err) { } } /** * 解绑权限和资源 */ async attachPermissionResource(permissionId: string) { await nuimsService.attachPermissionResourceAction({ body: { PermissionId: permissionId, ResourceIdActionList: [{ ResourceId: this.resourceId }], }, config: { noErrorTip: true, }, }); } async detachPermissionResource(permissionId: string) { await nuimsService.detachPermissionResourceAction({ body: { PermissionId: permissionId, ResourceIdActionList: [{ ResourceId: this.resourceId }], }, config: { noErrorTip: true, }, }); } } export default Nuims;