import { Prisma } from '@prisma/client' import { prisma } from './prisma' import { normalizeTaskDetailOnlyFlags, unionPermissionPacks, type MaterialPermissionFlags, type PermissionPackMap, } from './organization-material-permissions' function isMissingInheritTable(error: unknown) { return error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2021' } export const DEFAULT_INHERIT_PACKS = [ { slug: 'operations', name: '运营', sourceDepartment: '运营中心' }, { slug: 'visual', name: '视觉', sourceDepartment: '视觉中心' }, ] as const export function packItemsToMap( items: Array<{ materialType: string canView: boolean canDownload: boolean canDownloadSource: boolean canShare: boolean canEditAssets?: boolean canAccessPrivate?: boolean }>, ): PermissionPackMap { const pack: PermissionPackMap = {} for (const item of items) { const taskDetailOnlyFlags = normalizeTaskDetailOnlyFlags(item.materialType, item) pack[item.materialType] = { canView: item.canView, canDownload: item.canDownload, canDownloadSource: item.canDownloadSource, canShare: item.canShare, canEditAssets: taskDetailOnlyFlags.canEditAssets, canAccessPrivate: taskDetailOnlyFlags.canAccessPrivate, } } return pack } export async function ensureDefaultPermissionPacks() { for (const preset of DEFAULT_INHERIT_PACKS) { const pack = await prisma.materialPermissionPack.upsert({ where: { slug: preset.slug }, update: {}, create: { slug: preset.slug, name: preset.name }, select: { id: true, _count: { select: { items: true } } }, }) if (pack._count.items > 0) continue const sourceRows = await prisma.departmentMaterialPermission.findMany({ where: { department: preset.sourceDepartment }, select: { materialType: true, canView: true, canDownload: true, canDownloadSource: true, canShare: true, }, }) if (sourceRows.length === 0) continue await prisma.materialPermissionPackItem.createMany({ data: sourceRows.map((row) => ({ packId: pack.id, materialType: row.materialType, canView: row.canView, canDownload: row.canDownload, canDownloadSource: row.canDownloadSource, canShare: row.canShare, canEditAssets: false, canAccessPrivate: false, })), }) } } const PACK_ITEM_SELECT = { materialType: true, canView: true, canDownload: true, canDownloadSource: true, canShare: true, canEditAssets: true, canAccessPrivate: true, } as const export async function loadUserInheritPack(userId: string): Promise { try { const assignments = await prisma.userPermissionInherit.findMany({ where: { userId }, select: { pack: { select: { items: { select: PACK_ITEM_SELECT }, }, }, }, }) if (assignments.length === 0) return null return unionPermissionPacks(...assignments.map((row) => packItemsToMap(row.pack.items))) } catch (error) { if (isMissingInheritTable(error)) return null throw error } } /** * 任务-详情单图编辑授权线:用户的花名册路径权限组(部门组+个人组并集) * 对「任务-详情」勾选了编辑图片即获得。与上传者/管理员/托管部门的既有 * 授权线叠加,任何一边允许即可编辑。 */ export async function canUserEditTaskDetailAssets(userId: string): Promise { if (!userId) return false try { const { resolveRosterPermissionPack } = await import('./department-permission') const pack = await resolveRosterPermissionPack(userId) return pack?.['任务-详情']?.canEditAssets === true } catch (error) { console.error('[user-permission-inherit] 读取任务-详情编辑权限失败:', error) return false } } /** * 私密任务-详情查看/下载:只认权限组勾选,不给上传者/管理员额外豁免。 */ export async function canUserAccessPrivateTaskDetail(userId: string): Promise { if (!userId) return false try { const { resolveRosterPermissionPack } = await import('./department-permission') const pack = await resolveRosterPermissionPack(userId) return pack?.['任务-详情']?.canAccessPrivate === true } catch (error) { console.error('[user-permission-inherit] 读取任务-详情私密权限失败:', error) return false } } /** * 视频提前访问豁免:用户加入的任意权限组开启了该组级能力即获得。 * 部门进组是素材可见范围的底子,不参与此判定;豁免按"人进组是加餐"的口径只认个人挂载。 */ export async function resolveUserVideoEarlyAccess(userId: string): Promise { if (!userId) return false try { const assignment = await prisma.userPermissionInherit.findFirst({ where: { userId, pack: { videoEarlyAccess: true } }, select: { id: true }, }) return Boolean(assignment) } catch (error) { if (isMissingInheritTable(error)) return false throw error } } export async function savePermissionPackItems( slug: string, permissions: Array, ) { const pack = await prisma.materialPermissionPack.findUnique({ where: { slug }, select: { id: true }, }) if (!pack) throw new Error('没有这套继承权限') await prisma.$transaction([ prisma.materialPermissionPackItem.deleteMany({ where: { packId: pack.id } }), prisma.materialPermissionPackItem.createMany({ data: permissions .filter((item) => item.materialType) .map((item) => { const taskDetailOnlyFlags = normalizeTaskDetailOnlyFlags(item.materialType, item) return { packId: pack.id, materialType: item.materialType, canView: item.canView, canDownload: item.canDownload, canDownloadSource: item.canDownloadSource, canShare: item.canShare, canEditAssets: taskDetailOnlyFlags.canEditAssets, canAccessPrivate: taskDetailOnlyFlags.canAccessPrivate, } }), }), ]) }