205 lines
6.7 KiB
TypeScript
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 })
|
|
}
|
|
}
|