import { prisma } from '@/lib/prisma' import { isSuperAdmin, isSystemAdmin, } from '@/lib/department-permission' export interface MaterialAuthorizationUser { id: string role?: string | null isSuperAdmin?: boolean | null /** 所属部门 ID。未提供时会在需要判定托管权限的场景下按需查库 */ departmentId?: string | null } export interface MaterialAuthorizationTarget { /** 素材 ID。当调用方未查询 custodyDepartmentId 时,用它补查 */ id?: string userId: string /** * 素材托管部门。 * `undefined` 表示调用方没有查这个字段,`null` 表示确认未处于托管状态。 */ custodyDepartmentId?: string | null } /** * 解析用户所属部门 ID。 * * 优先取 departmentId 外键;部分历史账号只填了部门名称字符串而没有回填 * departmentId,这里按名称兜底反查,避免这些人无法接手本部门托管的素材。 */ async function resolveUserDepartmentId(userId: string): Promise { const user = await prisma.user.findUnique({ where: { id: userId }, select: { departmentId: true, department: true }, }) if (!user) return null if (user.departmentId) return user.departmentId const name = user.department?.trim() if (!name) return null const department = await prisma.department.findUnique({ where: { name }, select: { id: true }, }) return department?.id ?? null } /** * 素材写操作的最小统一授权: * - 素材所有者 * - 素材托管部门的成员(原归属人离职后由该部门接手维护) * - 系统管理员(兼容 ADMIN / SYSTEM_ADMIN) * - 超级管理员 * * 部门查看权限不能自动升级为素材写权限。 */ export async function canManageMaterial( user: MaterialAuthorizationUser, material: MaterialAuthorizationTarget, ): Promise { if ( material.userId === user.id || isSystemAdmin(user.role) || user.isSuperAdmin === true ) { return true } // 多数调用方只 select 了 id / userId,没有查托管字段。此处按需补查, // 避免因为某个调用点漏 select 就让托管权限静默失效——调用方若已带上 // custodyDepartmentId(包括显式的 null),这里不会产生任何额外查询。 let custodyDepartmentId = material.custodyDepartmentId if (custodyDepartmentId === undefined && material.id) { const row = await prisma.material.findUnique({ where: { id: material.id }, select: { custodyDepartmentId: true }, }) custodyDepartmentId = row?.custodyDepartmentId ?? null } if (custodyDepartmentId) { const userDepartmentId = user.departmentId ?? (await resolveUserDepartmentId(user.id)) if (userDepartmentId && userDepartmentId === custodyDepartmentId) { return true } } return isSuperAdmin(user.id) }