61 lines
2.4 KiB
TypeScript
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)]))
|
|
}
|