import type { Prisma } from '@prisma/client' import { prisma } from '@/lib/prisma' import { planDepartmentScopeWithPaidCore } from '@/lib/license' export type MaterialPermissionActor = { id: string role: string isSuperAdmin: boolean isActive: boolean canDownload: boolean department?: string | null managedDepartment?: string | null } export type MaterialPermissionTarget = { userId?: string | null createdByUserId?: string | null ownerType?: string | null ownerId?: string | null user?: { id?: string | null department?: string | null } | null } const normalizeDepartment = (department?: string | null) => (department || '').trim() export async function getMaterialPermissionActor(session: unknown): Promise { const userId = (session as any)?.user?.id if (!userId) { return null } const user = await prisma.user.findUnique({ where: { id: userId }, select: { id: true, role: true, isSuperAdmin: true, isActive: true, canDownload: true, department: true, managedDepartment: true, }, }) if (!user || (!user.isSuperAdmin && user.isActive === false)) { return null } return { id: user.id, role: user.role, isSuperAdmin: Boolean(user.isSuperAdmin), isActive: user.isActive, canDownload: user.canDownload, department: user.department, managedDepartment: user.managedDepartment, } } export function canActorDownloadMaterial(actor: MaterialPermissionActor | null) { if (!actor) { return false } return actor.isSuperAdmin || actor.role === 'ADMIN' || actor.canDownload } export function isMaterialOwnedByActor(material: MaterialPermissionTarget, actor: MaterialPermissionActor | null) { if (!actor) { return false } return ( material.userId === actor.id || (material.ownerType === 'USER' && material.ownerId === actor.id) ) } export async function canManageMaterial( material: MaterialPermissionTarget, actor: MaterialPermissionActor | null ) { if (!actor) { return false } if (actor.isSuperAdmin) { return true } if (isMaterialOwnedByActor(material, actor)) { return true } if (actor.role !== 'ADMIN') { return false } const scopeDepartment = normalizeDepartment(actor.managedDepartment) const targetDepartment = normalizeDepartment(material.user?.department) if (!scopeDepartment || !targetDepartment) { return false } const departments = await prisma.department.findMany({ select: { name: true } }) const scopePlan = await planDepartmentScopeWithPaidCore({ scopeDepartment, targetDepartment, departments, }) return scopePlan.valid ? scopePlan.withinScope : false } export async function buildMaterialManagementScopeWhere( actor: MaterialPermissionActor | null ): Promise { if (!actor) { return { id: { in: [] } } } if (actor.isSuperAdmin) { return {} } const scopeDepartment = normalizeDepartment(actor.managedDepartment) const ownWhere: Prisma.MaterialWhereInput[] = [ { userId: actor.id }, { ownerType: 'USER', ownerId: actor.id }, ] if (actor.role !== 'ADMIN' || !scopeDepartment) { return { OR: ownWhere } } const departments = await prisma.department.findMany({ select: { name: true } }) const scopePlan = await planDepartmentScopeWithPaidCore({ scopeDepartment, departments, }) if (!scopePlan.valid || scopePlan.scopedDepartments.length === 0) { return { OR: ownWhere } } return { OR: [ ...ownWhere, { user: { department: { in: scopePlan.scopedDepartments } } }, { user: { department: { startsWith: `${scopeDepartment}-` } } }, ], } }