origin/apps/server/src/models/rbac/rolemap.service.ts

320 lines
8.9 KiB
TypeScript
Raw Normal View History

2024-12-30 08:26:40 +08:00
import { Injectable } from '@nestjs/common';
import {
db,
RoleMapMethodSchema,
ObjectType,
Prisma,
RowModelRequest,
UserProfile,
2025-01-06 08:45:23 +08:00
} from '@nice/common';
2024-12-30 08:26:40 +08:00
import { DepartmentService } from '@server/models/department/department.service';
import { TRPCError } from '@trpc/server';
import { RowModelService } from '../base/row-model.service';
import { isFieldCondition } from '../base/sql-builder';
import { z } from 'zod';
@Injectable()
export class RoleMapService extends RowModelService {
createJoinSql(request?: RowModelRequest): string[] {
return [
`LEFT JOIN staff ON staff.id = ${this.tableName}.object_id`,
`LEFT JOIN department ON department.id = staff.dept_id`,
];
}
createUnGroupingRowSelect(): string[] {
return [
`${this.tableName}.id AS id`,
`${this.tableName}.object_id AS object_id`,
`${this.tableName}.role_id AS role_id`,
`${this.tableName}.domain_id AS domain_id`,
`${this.tableName}.object_type AS object_type`,
`staff.officer_id AS staff_officer_id`,
`staff.username AS staff_username`,
`department.name AS department_name`,
`staff.showname AS staff_`,
];
}
constructor(private readonly departmentService: DepartmentService) {
super('rolemap');
}
protected createGetRowsFilters(
request: z.infer<typeof RoleMapMethodSchema.getRows>,
staff: UserProfile,
) {
const { roleId, domainId } = request;
// Base conditions
let condition = super.createGetRowsFilters(request, staff);
if (isFieldCondition(condition)) return;
// Adding conditions based on parameters existence
if (roleId) {
condition.AND.push({
field: `${this.tableName}.role_id`,
value: roleId,
op: 'equals',
});
}
if (domainId) {
condition.AND.push({
field: `${this.tableName}.domain_id`,
value: domainId,
op: 'equals',
});
}
return condition;
}
2025-05-27 16:48:09 +08:00
protected async getRowDto(row: any, staff?: UserProfile): Promise<any> {
2024-12-30 08:26:40 +08:00
if (!row.id) return row;
return row;
}
/**
*
* @param data ID的数据
* @returns
*/
async deleteAllRolesForObject(
data: z.infer<typeof RoleMapMethodSchema.deleteWithObject>,
) {
const { objectId } = data;
return await db.roleMap.deleteMany({
where: {
objectId,
},
});
}
/**
*
* @param data
* @returns
*/
async setRoleForObject(data: z.infer<typeof RoleMapMethodSchema.create>) {
return await db.roleMap.create({
data,
});
}
/**
*
* @param data
* @returns
*/
async setRoleForObjects(
data: z.infer<typeof RoleMapMethodSchema.setRoleForObjects>,
) {
const { domainId, roleId, objectIds, objectType } = data;
const roleMaps = objectIds.map((id) => ({
domainId,
objectId: id,
roleId,
objectType,
}));
// 开启事务
const result = await db.$transaction(async (prisma) => {
// 首先,删除现有的角色映射
await prisma.roleMap.deleteMany({
where: {
domainId,
roleId,
objectType,
},
});
// 然后,创建新的角色映射
return await prisma.roleMap.createManyAndReturn({
data: roleMaps,
});
});
2025-05-27 16:48:09 +08:00
const wrapResult = Promise.all(
result.map(async (item) => {
const staff = await db.staff.findMany({
include: { department: true },
where: {
id: item.objectId,
},
});
return { ...item, staff };
}),
);
2024-12-30 08:26:40 +08:00
return wrapResult;
}
async addRoleForObjects(
data: z.infer<typeof RoleMapMethodSchema.setRoleForObjects>,
) {
const { domainId, roleId, objectIds, objectType } = data;
const objects = await db.roleMap.findMany({
where: { domainId, roleId, objectType },
});
data.objectIds = Array.from(
new Set([...objectIds, ...objects.map((obj) => obj.objectId)]),
);
const result = this.setRoleForObjects(data);
return result;
}
/**
*
* @param data
* @returns
*/
async setRolesForObject(
data: z.infer<typeof RoleMapMethodSchema.setRolesForObject>,
) {
const { domainId, objectId, roleIds, objectType } = data;
const roleMaps = roleIds.map((id) => ({
domainId,
objectId,
roleId: id,
objectType,
}));
return await db.roleMap.createMany({ data: roleMaps });
}
/**
*
* @param data IDID和对象ID的数据
* @returns
*/
async getPermsForObject(
data: z.infer<typeof RoleMapMethodSchema.getPermsForObject>,
) {
const { domainId, deptId, staffId } = data;
// Get all ancestor department IDs if deptId is provided.
const ancestorDeptIds = deptId
? await this.departmentService.getAncestorIds(deptId)
: [];
// Define a common filter for querying roles.
const objectFilters: Prisma.RoleMapWhereInput[] = [
{ objectId: staffId, objectType: ObjectType.STAFF },
...(deptId || ancestorDeptIds.length > 0
? [
2025-05-27 16:48:09 +08:00
{
objectId: { in: [deptId, ...ancestorDeptIds].filter(Boolean) },
objectType: ObjectType.DEPARTMENT,
},
]
2024-12-30 08:26:40 +08:00
: []),
];
// Helper function to fetch roles based on domain ID.
const fetchRoles = async (domainId: string) => {
return db.roleMap.findMany({
where: {
AND: {
domainId,
OR: objectFilters,
},
},
include: { role: true },
});
};
// Fetch roles with and without specific domain IDs.
const [nullDomainRoles, userRoles] = await Promise.all([
fetchRoles(null),
fetchRoles(domainId),
]);
// Extract permissions from roles and return them.
return [...userRoles, ...nullDomainRoles].flatMap(
({ role }) => role.permissions,
);
}
/**
*
* @param data ID列表的数据
* @returns
* @throws ID
*/
async deleteMany(data: z.infer<typeof RoleMapMethodSchema.deleteMany>) {
const { ids } = data;
if (!ids || ids.length === 0) {
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'No IDs provided for deletion.',
});
}
const rowData = await this.getRowByIds({ ids, extraCondition: {} });
await db.roleMap.deleteMany({
where: { id: { in: ids } },
});
return rowData;
}
/**
*
* @param data
* @returns
*/
async paginate(data: z.infer<typeof RoleMapMethodSchema.paginate>) {
const { page, pageSize, domainId, roleId } = data;
const [items, totalCount] = await Promise.all([
db.roleMap.findMany({
skip: (page - 1) * pageSize,
take: pageSize,
where: { domainId, roleId },
}),
db.roleMap.count({
where: { domainId, roleId },
}),
]);
// const processedItems = await Promise.all(items.map(item => this.genRoleMapDto(item)));
return { items, totalCount };
}
2025-05-27 16:48:09 +08:00
async getStaffsNotMap(
data: z.infer<typeof RoleMapMethodSchema.getStaffsNotMap>,
) {
2024-12-30 08:26:40 +08:00
const { domainId, roleId } = data;
let staffs = await db.staff.findMany({
where: {
domainId,
},
});
const roleMaps = await db.roleMap.findMany({
where: {
domainId,
roleId,
objectType: ObjectType.STAFF,
},
});
staffs = staffs.filter(
(staff) =>
roleMaps.findIndex((roleMap) => roleMap.objectId === staff.id) === -1,
);
return staffs;
}
/**
*
* @param data
* @returns
*/
async update(data: z.infer<typeof RoleMapMethodSchema.update>) {
const { id, ...others } = data;
const updatedRoleMap = await db.roleMap.update({
where: { id },
data: { ...others },
});
return updatedRoleMap;
}
/**
*
* @param data ID和域ID的数据
* @returns ID和员工ID列表
*/
2025-05-27 16:48:09 +08:00
async getRoleMapDetail(
data: z.infer<typeof RoleMapMethodSchema.getRoleMapDetail>,
) {
2024-12-30 08:26:40 +08:00
const { roleId, domainId } = data;
const res = await db.roleMap.findMany({ where: { roleId, domainId } });
const deptIds = res
.filter((item) => item.objectType === ObjectType.DEPARTMENT)
.map((item) => item.objectId);
const staffIds = res
.filter((item) => item.objectType === ObjectType.STAFF)
.map((item) => item.objectId);
return { deptIds, staffIds };
}
}