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' import { isSuperAdmin } from '@/lib/department-permission' // HR 组织树中运营中心 G 的稳定部门编号。 export const OPERATIONS_G_SOURCE_DEPT_ID = 911666246 export async function canAccessOperationsGMaterials(userId?: string | null): Promise { 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 { 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 canViewOperationsGMaterials(userId?: string | null): Promise { return await isSuperAdmin(userId) || canAccessOperationsGMaterials(userId) } export async function buildMaterialOrganizationViewWhere(userId?: string | null) { return await canViewOperationsGMaterials(userId) ? {} : { accessScope: 'general' } } export async function getOperationsGMaterialIds(): Promise { 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)])) }