131 lines
3.7 KiB
TypeScript
Executable File
131 lines
3.7 KiB
TypeScript
Executable File
import { Injectable } from '@nestjs/common';
|
|
import {
|
|
db,
|
|
ObjectType,
|
|
StaffMethodSchema,
|
|
UserProfile,
|
|
RolePerms,
|
|
ResPerm,
|
|
Staff,
|
|
RowModelRequest,
|
|
} from '@nice/common';
|
|
import { DepartmentService } from '../department/department.service';
|
|
import { RowCacheService } from '../base/row-cache.service';
|
|
import { z } from 'zod';
|
|
import { isFieldCondition } from '../base/sql-builder';
|
|
@Injectable()
|
|
export class StaffRowService extends RowCacheService {
|
|
constructor(private readonly departmentService: DepartmentService) {
|
|
super(ObjectType.STAFF, false);
|
|
}
|
|
createUnGroupingRowSelect(request?: RowModelRequest): string[] {
|
|
const result = super
|
|
.createUnGroupingRowSelect(request)
|
|
.concat([
|
|
`${this.tableName}.id AS id`,
|
|
`${this.tableName}.username AS username`,
|
|
`${this.tableName}.showname AS showname`,
|
|
`${this.tableName}.avatar AS avatar`,
|
|
`${this.tableName}.officer_id AS officer_id`,
|
|
`${this.tableName}.phone_number AS phone_number`,
|
|
`${this.tableName}.order AS order`,
|
|
`${this.tableName}.enabled AS enabled`,
|
|
'dept.name AS dept_name',
|
|
'domain.name AS domain_name',
|
|
]);
|
|
return result;
|
|
}
|
|
createJoinSql(request?: RowModelRequest): string[] {
|
|
return [
|
|
`LEFT JOIN department dept ON ${this.tableName}.dept_id = dept.id`,
|
|
`LEFT JOIN department domain ON ${this.tableName}.domain_id = domain.id`,
|
|
];
|
|
}
|
|
protected createGetRowsFilters(
|
|
request: z.infer<typeof StaffMethodSchema.getRows>,
|
|
staff: UserProfile,
|
|
) {
|
|
const condition = super.createGetRowsFilters(request);
|
|
const { domainId, includeDeleted = false } = request;
|
|
if (isFieldCondition(condition)) {
|
|
return;
|
|
}
|
|
if (domainId) {
|
|
condition.AND.push({
|
|
field: `${this.tableName}.domain_id`,
|
|
value: domainId,
|
|
op: 'equals',
|
|
});
|
|
} else {
|
|
condition.AND.push({
|
|
field: `${this.tableName}.domain_id`,
|
|
op: 'blank',
|
|
});
|
|
}
|
|
if (!includeDeleted) {
|
|
condition.AND.push({
|
|
field: `${this.tableName}.deleted_at`,
|
|
type: 'date',
|
|
op: 'blank',
|
|
});
|
|
}
|
|
condition.OR = [];
|
|
if (!staff.permissions.includes(RolePerms.MANAGE_ANY_STAFF)) {
|
|
if (staff.permissions.includes(RolePerms.MANAGE_DOM_STAFF)) {
|
|
condition.OR.push({
|
|
field: 'dept.id',
|
|
value: staff.domainId,
|
|
op: 'equals',
|
|
});
|
|
}
|
|
}
|
|
|
|
return condition;
|
|
}
|
|
|
|
async getPermissionContext(id: string, staff: UserProfile) {
|
|
const data = await db.staff.findUnique({
|
|
where: { id },
|
|
select: {
|
|
deptId: true,
|
|
domainId: true,
|
|
},
|
|
});
|
|
const deptId = data?.deptId;
|
|
const isFromSameDept = staff.deptIds?.includes(deptId);
|
|
const domainChildDeptIds = await this.departmentService.getDescendantIds(
|
|
staff.domainId,
|
|
true,
|
|
);
|
|
const belongsToDomain = domainChildDeptIds.includes(deptId);
|
|
return { isFromSameDept, belongsToDomain };
|
|
}
|
|
protected async setResPermissions(data: Staff, staff: UserProfile) {
|
|
const permissions: ResPerm = {};
|
|
const { isFromSameDept, belongsToDomain } = await this.getPermissionContext(
|
|
data.id,
|
|
staff,
|
|
);
|
|
const setManagePermissions = (permissions: ResPerm) => {
|
|
Object.assign(permissions, {
|
|
read: true,
|
|
delete: true,
|
|
edit: true,
|
|
});
|
|
};
|
|
staff.permissions.forEach((permission) => {
|
|
switch (permission) {
|
|
case RolePerms.MANAGE_ANY_STAFF:
|
|
setManagePermissions(permissions);
|
|
break;
|
|
case RolePerms.MANAGE_DOM_STAFF:
|
|
if (belongsToDomain) {
|
|
setManagePermissions(permissions);
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
return { ...data, perm: permissions };
|
|
}
|
|
}
|