123 lines
3.4 KiB
TypeScript
123 lines
3.4 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
||
import { getServerSession } from 'next-auth'
|
||
import { authOptions } from '@/lib/auth'
|
||
import { prisma } from '@/lib/prisma'
|
||
import { randomBytes } from 'crypto'
|
||
import { resolveBaseUrl } from '@/lib/config'
|
||
|
||
// GET - 获取邀请链接列表(仅管理员)
|
||
export async function GET(req: NextRequest) {
|
||
try {
|
||
const session = await getServerSession(authOptions)
|
||
|
||
const isSuperAdmin = (session?.user as any)?.isSuperAdmin
|
||
if (!session || ((session.user as any)?.role !== 'ADMIN' && !isSuperAdmin)) {
|
||
return NextResponse.json(
|
||
{ error: '无权限' },
|
||
{ status: 403 }
|
||
)
|
||
}
|
||
|
||
// 支持分页
|
||
const { searchParams } = new URL(req.url)
|
||
const page = parseInt(searchParams.get('page') || '1', 10)
|
||
const pageSize = Math.min(parseInt(searchParams.get('pageSize') || '20', 10), 100) // 最大100条
|
||
const skip = (page - 1) * pageSize
|
||
|
||
// 并行查询总数和数据
|
||
const [total, invitations] = await Promise.all([
|
||
prisma.invitation.count(),
|
||
prisma.invitation.findMany({
|
||
orderBy: { createdAt: 'desc' },
|
||
skip,
|
||
take: pageSize,
|
||
select: {
|
||
id: true,
|
||
code: true,
|
||
createdBy: true,
|
||
maxUses: true,
|
||
currentUses: true,
|
||
expiresAt: true,
|
||
isActive: true,
|
||
createdAt: true,
|
||
// 不返回敏感信息
|
||
}
|
||
})
|
||
])
|
||
|
||
// 生成完整邀请链接(统一使用集中配置策略)
|
||
const baseUrl = resolveBaseUrl(req)
|
||
const invitationsWithUrl = invitations.map(invitation => ({
|
||
...invitation,
|
||
inviteUrl: `${baseUrl}/register?invite=${invitation.code}`,
|
||
}))
|
||
|
||
return NextResponse.json({
|
||
invitations: invitationsWithUrl,
|
||
pagination: {
|
||
page,
|
||
pageSize,
|
||
total,
|
||
totalPages: Math.ceil(total / pageSize)
|
||
}
|
||
})
|
||
} catch (error) {
|
||
console.error('[Invitations] GET error:', error)
|
||
return NextResponse.json(
|
||
{ error: '获取邀请链接失败' },
|
||
{ status: 500 }
|
||
)
|
||
}
|
||
}
|
||
|
||
// POST - 创建邀请链接(仅管理员)
|
||
export async function POST(req: NextRequest) {
|
||
try {
|
||
const session = await getServerSession(authOptions)
|
||
|
||
const isSuperAdmin = (session?.user as any)?.isSuperAdmin
|
||
if (!session || ((session.user as any)?.role !== 'ADMIN' && !isSuperAdmin)) {
|
||
return NextResponse.json(
|
||
{ error: '无权限' },
|
||
{ status: 403 }
|
||
)
|
||
}
|
||
|
||
const { maxUses, expiresInDays } = await req.json()
|
||
const userId = (session.user as any).id
|
||
|
||
// 生成唯一邀请码(8位随机字符串)
|
||
const code = randomBytes(4).toString('hex').toUpperCase()
|
||
|
||
// 计算过期时间
|
||
const expiresAt = expiresInDays
|
||
? new Date(Date.now() + expiresInDays * 24 * 60 * 60 * 1000)
|
||
: null
|
||
|
||
const invitation = await prisma.invitation.create({
|
||
data: {
|
||
code,
|
||
createdBy: userId,
|
||
maxUses: maxUses || 1,
|
||
expiresAt,
|
||
},
|
||
})
|
||
|
||
// 生成完整邀请链接(统一使用集中配置策略)
|
||
const baseUrl = resolveBaseUrl(req)
|
||
const inviteUrl = `${baseUrl}/register?invite=${code}`
|
||
|
||
return NextResponse.json({
|
||
...invitation,
|
||
inviteUrl,
|
||
})
|
||
} catch (error) {
|
||
console.error('[Invitations] POST error:', error)
|
||
return NextResponse.json(
|
||
{ error: '创建邀请链接失败' },
|
||
{ status: 500 }
|
||
)
|
||
}
|
||
}
|
||
|