@lcap/asl
Version:
NetEase Application Specific Language
494 lines (448 loc) • 14.7 kB
text/typescript
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
*/
public readonly domainName: string = undefined;
/**
* 上报权限后的资源id
*/
public readonly resourceId: string = undefined;
/**
* view
*/
public readonly view: View = undefined;
/**
* element
*/
public readonly element: Element = undefined;
/**
* @param source 需要合并的部分参数
*/
constructor(source?: Partial<Nuims>) {
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;