Initial commit: LexMind - Plataforma Jurídica Inteligente
This commit is contained in:
162
src/app/api/uploads/route.ts
Normal file
162
src/app/api/uploads/route.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
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,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user