52 lines
2.4 KiB
TypeScript
52 lines
2.4 KiB
TypeScript
import { getServerSession } from 'next-auth'
|
|
import { NextResponse } from 'next/server'
|
|
import { authOptions } from '@/lib/auth'
|
|
import { isSuperAdmin } from '@/lib/department-permission'
|
|
import { prisma } from '@/lib/prisma'
|
|
|
|
export class DetailGeneratorError extends Error {
|
|
constructor(message: string, readonly status = 400, readonly code = 'invalid_request') {
|
|
super(message)
|
|
this.name = 'DetailGeneratorError'
|
|
}
|
|
}
|
|
|
|
/** Beta access is deliberately independent of ordinary administrator roles. */
|
|
export async function assertDetailGeneratorUser(userId: string | null | undefined): Promise<string> {
|
|
if (!userId) throw new DetailGeneratorError('请先登录', 401, 'unauthenticated')
|
|
if (process.env.DETAIL_GENERATOR_ENABLED !== 'true') throw new DetailGeneratorError('详情页生成功能尚未启用', 403, 'feature_disabled')
|
|
if (!(await isSuperAdmin(userId))) {
|
|
throw new DetailGeneratorError('此功能暂仅向超级管理员开放', 403, 'forbidden')
|
|
}
|
|
const user = await prisma.user.findUnique({ where: { id: userId }, select: { status: true, isActive: true, archivedAt: true } })
|
|
const status = user?.status || (user?.isActive ? 'active' : 'pending')
|
|
if (!user || status !== 'active' || user.archivedAt) throw new DetailGeneratorError('账号当前不可用,无法使用详情页生成', 403, 'account_inactive')
|
|
return userId
|
|
}
|
|
|
|
export async function requireDetailGeneratorUser(): Promise<string> {
|
|
const session = await getServerSession(authOptions)
|
|
return assertDetailGeneratorUser((session?.user as { id?: string } | undefined)?.id)
|
|
}
|
|
|
|
export async function assertDetailGeneratorAccess(session: { user?: { id?: string } } | null): Promise<string> {
|
|
return assertDetailGeneratorUser(session?.user?.id)
|
|
}
|
|
|
|
export function detailGeneratorErrorResponse(error: unknown): NextResponse {
|
|
const known = error instanceof DetailGeneratorError
|
|
return NextResponse.json({
|
|
error: known ? error.message : '详情页操作暂未完成,请稍后重试',
|
|
code: known ? error.code : 'internal_error',
|
|
}, { status: known ? error.status : 500, headers: { 'Cache-Control': 'private, no-store' } })
|
|
}
|
|
|
|
export async function detailGeneratorRoute<T>(action: (userId: string) => Promise<T>): Promise<NextResponse> {
|
|
try {
|
|
const userId = await requireDetailGeneratorUser()
|
|
return NextResponse.json(await action(userId), { headers: { 'Cache-Control': 'private, no-store' } })
|
|
} catch (error) {
|
|
return detailGeneratorErrorResponse(error)
|
|
}
|
|
}
|