205 lines
6.7 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
import { prisma } from '@/lib/prisma'
import { getAllMaterialTypes, isSuperAdmin } from '@/lib/department-permission'
import { filterSelectableMaterialTypes } from '@/lib/material-type-options'
import {
collectOccupiedOrganizationPaths,
pruneOrganizationTree,
resolveOrganizationPermissionKey,
type MaterialPermissionFlags,
} from '@/lib/organization-material-permissions'
type OrgNode = {
id: string
name: string
path: string
level: number
parentId: string | null
children: OrgNode[]
}
const emptyFlags = (): MaterialPermissionFlags => ({
canView: false,
canDownload: false,
canDownloadSource: false,
canShare: true,
canEditAssets: false,
canAccessPrivate: false,
})
async function requireSuperAdmin() {
const session = await getServerSession(authOptions)
const userId = (session?.user as { id?: string } | undefined)?.id
if (!session || !(await isSuperAdmin(userId))) {
return null
}
return session
}
export async function GET() {
try {
if (!(await requireSuperAdmin())) {
return NextResponse.json({ error: '需要超级管理员权限' }, { status: 403 })
}
const [units, rows, materialTypes, bindings] = await Promise.all([
prisma.organizationUnit.findMany({
where: { isActive: true },
select: { id: true, name: true, path: true, level: true, parentId: true },
orderBy: [{ level: 'asc' }, { name: 'asc' }],
}),
prisma.departmentMaterialPermission.findMany({
select: {
department: true,
materialType: true,
canView: true,
canDownload: true,
canDownloadSource: true,
canShare: true,
},
}),
getAllMaterialTypes().then(filterSelectableMaterialTypes),
prisma.userEmployeeBinding.findMany({
where: { status: 'ACTIVE', user: { isActive: true } },
select: { employeeProfile: { select: { departmentPath: true } } },
}),
])
const stored = new Map<string, Record<string, MaterialPermissionFlags>>()
for (const row of rows) {
const current = stored.get(row.department) || {}
current[row.materialType] = {
canView: row.canView,
canDownload: row.canDownload,
canDownloadSource: row.canDownloadSource,
canShare: row.canShare,
canEditAssets: false,
canAccessPrivate: false,
}
stored.set(row.department, current)
}
const storedKeys = new Set(stored.keys())
const nodeMap = new Map<string, OrgNode>()
for (const unit of units) {
nodeMap.set(unit.id, { ...unit, children: [] })
}
const roots: OrgNode[] = []
for (const node of Array.from(nodeMap.values())) {
if (node.parentId && nodeMap.has(node.parentId)) {
nodeMap.get(node.parentId)!.children.push(node)
} else {
roots.push(node)
}
}
const occupiedPaths = collectOccupiedOrganizationPaths(
bindings.map((binding) => binding.employeeProfile?.departmentPath),
)
const tree = pruneOrganizationTree(roots, occupiedPaths)
const permissions: Record<string, Record<string, MaterialPermissionFlags>> = {}
const sources: Record<string, { source: string; storageKey: string | null; inheritFrom: string | null }> = {}
for (const unit of units) {
const resolved = resolveOrganizationPermissionKey(unit.path, storedKeys)
const flags: Record<string, MaterialPermissionFlags> = {}
const storedFlags = resolved && resolved.source !== 'none' ? stored.get(resolved.key) || {} : {}
for (const materialType of materialTypes) {
flags[materialType] = storedFlags[materialType] ? { ...storedFlags[materialType] } : emptyFlags()
}
permissions[unit.path] = flags
sources[unit.path] = {
source: resolved?.source || 'none',
storageKey: resolved && resolved.source !== 'none' ? resolved.key : null,
inheritFrom: resolved?.inheritFrom || null,
}
}
return NextResponse.json({
tree,
materialTypes,
permissions,
sources,
})
} catch (error) {
console.error('[organization material-permissions] GET failed', error)
return NextResponse.json({ error: '获取部门权限配置失败' }, { status: 500 })
}
}
export async function PUT(request: NextRequest) {
try {
if (!(await requireSuperAdmin())) {
return NextResponse.json({ error: '需要超级管理员权限' }, { status: 403 })
}
const body = await request.json()
const path = String(body?.path || '').trim()
const action = String(body?.action || 'save')
const incoming: Array<{
materialType: string
canView?: boolean
canDownload?: boolean
canDownloadSource?: boolean
canShare?: boolean
}> = Array.isArray(body?.permissions) ? body.permissions : []
const unit = await prisma.organizationUnit.findFirst({
where: { isActive: true, path },
select: { path: true, name: true },
})
if (!unit) {
return NextResponse.json({ error: '花名册里没有这个部门' }, { status: 400 })
}
if (action === 'inherit') {
await prisma.departmentMaterialPermission.deleteMany({
where: { department: unit.path },
})
return NextResponse.json({ ok: true })
}
if (incoming.length === 0) {
return NextResponse.json({ error: '素材类型列表不能为空' }, { status: 400 })
}
await prisma.$transaction(
incoming
.filter((item) => item.materialType)
.map((item) =>
prisma.departmentMaterialPermission.upsert({
where: {
department_materialType: {
department: unit.path,
materialType: item.materialType,
},
},
update: {
canView: item.canView ?? false,
canDownload: item.canDownload ?? false,
canDownloadSource: item.canDownloadSource ?? false,
canShare: item.canShare ?? true,
linkedToDepartment: null,
},
create: {
department: unit.path,
materialType: item.materialType,
canView: item.canView ?? false,
canDownload: item.canDownload ?? false,
canDownloadSource: item.canDownloadSource ?? false,
canShare: item.canShare ?? true,
linkedToDepartment: null,
},
}),
),
)
return NextResponse.json({ ok: true })
} catch (error) {
console.error('[organization material-permissions] PUT failed', error)
return NextResponse.json({ error: '保存部门权限配置失败' }, { status: 500 })
}
}