163 lines
4.5 KiB
TypeScript
163 lines
4.5 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import { getServerSession } from 'next-auth'
|
|
import { authOptions } from '@/lib/auth'
|
|
import { prisma } from '@/lib/prisma'
|
|
import { uploadFile, buildKey } from '@/lib/spaces'
|
|
|
|
const ALLOWED_TYPES = [
|
|
'application/pdf',
|
|
'application/msword',
|
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
'text/plain',
|
|
]
|
|
|
|
const MAX_SIZE = 50 * 1024 * 1024 // 50MB
|
|
|
|
const STORAGE_LIMITS: Record<string, number> = {
|
|
FREE: 1 * 1024 * 1024 * 1024, // 1GB
|
|
STARTER: 1 * 1024 * 1024 * 1024, // 1GB
|
|
PRO: 5 * 1024 * 1024 * 1024, // 5GB
|
|
ENTERPRISE: 20 * 1024 * 1024 * 1024, // 20GB
|
|
}
|
|
|
|
export async function POST(req: NextRequest) {
|
|
const session = await getServerSession(authOptions)
|
|
if (!session?.user?.id) {
|
|
return NextResponse.json({ error: 'Não autorizado' }, { status: 401 })
|
|
}
|
|
|
|
try {
|
|
const formData = await req.formData()
|
|
const file = formData.get('file') as File | null
|
|
|
|
if (!file) {
|
|
return NextResponse.json({ error: 'Nenhum arquivo enviado' }, { status: 400 })
|
|
}
|
|
|
|
// Validate file extension (defense in depth)
|
|
const ext = file.name.split(".").pop()?.toLowerCase()
|
|
const ALLOWED_EXTENSIONS = ["pdf", "doc", "docx", "txt"]
|
|
if (!ext || !ALLOWED_EXTENSIONS.includes(ext)) {
|
|
return NextResponse.json(
|
|
{ error: "Extensão de arquivo não permitida" },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Validate mime type
|
|
if (!ALLOWED_TYPES.includes(file.type)) {
|
|
return NextResponse.json(
|
|
{ error: 'Tipo de arquivo não permitido. Aceitos: PDF, DOCX, DOC, TXT' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Validate size
|
|
if (file.size > MAX_SIZE) {
|
|
return NextResponse.json(
|
|
{ error: 'Arquivo muito grande. Máximo: 50MB' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Check storage limit
|
|
const user = await prisma.user.findUnique({
|
|
where: { id: session.user.id },
|
|
select: { plan: true },
|
|
})
|
|
|
|
const storageLimit = STORAGE_LIMITS[user?.plan || 'FREE'] || STORAGE_LIMITS.FREE
|
|
|
|
const usedStorage = await prisma.upload.aggregate({
|
|
where: { userId: session.user.id },
|
|
_sum: { size: true },
|
|
})
|
|
|
|
const currentUsage = usedStorage._sum.size || 0
|
|
if (currentUsage + file.size > storageLimit) {
|
|
return NextResponse.json(
|
|
{ error: 'Limite de armazenamento atingido. Faça upgrade do plano para mais espaço.' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Upload to Spaces
|
|
const buffer = Buffer.from(await file.arrayBuffer())
|
|
const key = buildKey(session.user.id, file.name)
|
|
await uploadFile(buffer, key, file.type)
|
|
|
|
// Save to DB
|
|
const upload = await prisma.upload.create({
|
|
data: {
|
|
userId: session.user.id,
|
|
filename: file.name,
|
|
key,
|
|
size: file.size,
|
|
mimeType: file.type,
|
|
},
|
|
})
|
|
|
|
return NextResponse.json({
|
|
upload: {
|
|
id: upload.id,
|
|
filename: upload.filename,
|
|
size: upload.size,
|
|
mimeType: upload.mimeType,
|
|
createdAt: upload.createdAt,
|
|
},
|
|
})
|
|
} catch (error) {
|
|
console.error('Upload error:', error)
|
|
return NextResponse.json({ error: 'Erro ao fazer upload' }, { status: 500 })
|
|
}
|
|
}
|
|
|
|
export async function GET(req: NextRequest) {
|
|
const session = await getServerSession(authOptions)
|
|
if (!session?.user?.id) {
|
|
return NextResponse.json({ error: 'Não autorizado' }, { status: 401 })
|
|
}
|
|
|
|
const { searchParams } = new URL(req.url)
|
|
const page = Math.max(1, Math.min(1000, parseInt(searchParams.get('page') || '1')))
|
|
const limit = Math.max(1, Math.min(100, parseInt(searchParams.get('limit') || '20')))
|
|
const skip = (page - 1) * limit
|
|
|
|
const [uploads, total, storageUsed] = await Promise.all([
|
|
prisma.upload.findMany({
|
|
where: { userId: session.user.id },
|
|
orderBy: { createdAt: 'desc' },
|
|
skip,
|
|
take: limit,
|
|
select: {
|
|
id: true,
|
|
filename: true,
|
|
size: true,
|
|
mimeType: true,
|
|
createdAt: true,
|
|
},
|
|
}),
|
|
prisma.upload.count({ where: { userId: session.user.id } }),
|
|
prisma.upload.aggregate({
|
|
where: { userId: session.user.id },
|
|
_sum: { size: true },
|
|
}),
|
|
])
|
|
|
|
const user = await prisma.user.findUnique({
|
|
where: { id: session.user.id },
|
|
select: { plan: true },
|
|
})
|
|
|
|
const storageLimit = STORAGE_LIMITS[user?.plan || 'FREE'] || STORAGE_LIMITS.FREE
|
|
|
|
return NextResponse.json({
|
|
uploads,
|
|
total,
|
|
page,
|
|
totalPages: Math.ceil(total / limit),
|
|
storageUsed: storageUsed._sum.size || 0,
|
|
storageLimit,
|
|
})
|
|
}
|