gongxiangp2/lib/material-organization-access.ts

61 lines
2.4 KiB
TypeScript

import { prisma } from '@/lib/prisma'
import { getEmployeeByUserId, getEmployeeOrganizationPathsByUserId } from '@/lib/employee-directory'
import { isUnderOrganizationPath } from '@/lib/organization-material-permissions'
import { normalizeMaterialAccessScope, type MaterialAccessScope } from '@/lib/material-access-scope'
// HR 组织树中运营中心 G 的稳定部门编号。
export const OPERATIONS_G_SOURCE_DEPT_ID = 911666246
export async function canAccessOperationsGMaterials(userId?: string | null): Promise<boolean> {
if (!userId) return false
const [employee, paths, organization] = await Promise.all([
getEmployeeByUserId(userId),
getEmployeeOrganizationPathsByUserId(userId),
prisma.organizationUnit.findUnique({
where: { sourceDeptId: OPERATIONS_G_SOURCE_DEPT_ID },
select: { path: true, isActive: true },
}),
])
return employee != null && employee.employmentState !== 'RESIGNED'
&& organization?.isActive === true
&& paths.some((path) => isUnderOrganizationPath(path, organization.path))
}
export class MaterialAccessScopeError extends Error {
constructor(message: string, readonly status = 400) {
super(message)
this.name = 'MaterialAccessScopeError'
}
}
export async function resolveMaterialUploadAccessScope(
value: unknown,
userId: string,
): Promise<MaterialAccessScope> {
let scope: MaterialAccessScope
try {
scope = normalizeMaterialAccessScope(value)
} catch (error) {
throw new MaterialAccessScopeError((error as Error).message)
}
if (scope === 'operations_g' && !(await canAccessOperationsGMaterials(userId))) {
throw new MaterialAccessScopeError('仅运营中心 G 成员可以上传或设置专属素材', 403)
}
return scope
}
export async function buildMaterialOrganizationWhere(userId?: string | null) {
return await canAccessOperationsGMaterials(userId) ? {} : { accessScope: 'general' }
}
export async function getOperationsGMaterialIds(): Promise<string[]> {
const [materials, purges] = await Promise.all([
prisma.material.findMany({ where: { accessScope: 'operations_g' }, select: { id: true } }),
prisma.materialPurgeJob.findMany({
where: { materialSnapshot: { path: ['accessScope'], equals: 'operations_g' } },
select: { materialId: true },
}),
])
return Array.from(new Set([...materials.map((row) => row.id), ...purges.map((row) => row.materialId)]))
}