90 lines
2.6 KiB
TypeScript
90 lines
2.6 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
||
import connectMongoDB from '@/lib/mongodb';
|
||
import { Image } from '@/lib/models/Image';
|
||
import { IS_FRONTEND_ONLY_BUILD } from '@/lib/runtime/buildVariant';
|
||
import crypto from 'crypto';
|
||
|
||
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
|
||
const ALLOWED_TYPES = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml'];
|
||
|
||
export async function POST(request: NextRequest) {
|
||
try {
|
||
// Проверяем что это полная сборка (с БД)
|
||
if (IS_FRONTEND_ONLY_BUILD) {
|
||
return NextResponse.json(
|
||
{ error: 'Image upload not available in frontend-only mode' },
|
||
{ status: 403 }
|
||
);
|
||
}
|
||
|
||
await connectMongoDB();
|
||
|
||
const formData = await request.formData();
|
||
const file = formData.get('file') as File;
|
||
const funnelId = formData.get('funnelId') as string || undefined;
|
||
const description = formData.get('description') as string || undefined;
|
||
|
||
if (!file) {
|
||
return NextResponse.json(
|
||
{ error: 'No file provided' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// Валидация файла
|
||
if (file.size > MAX_FILE_SIZE) {
|
||
return NextResponse.json(
|
||
{ error: 'File too large. Maximum size is 5MB' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
if (!ALLOWED_TYPES.includes(file.type)) {
|
||
return NextResponse.json(
|
||
{ error: 'Invalid file type. Only images are allowed' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// Генерируем уникальное имя файла
|
||
const ext = file.name.split('.').pop() || 'bin';
|
||
const filename = `${crypto.randomUUID()}.${ext}`;
|
||
|
||
// Конвертируем файл в Buffer
|
||
const bytes = await file.arrayBuffer();
|
||
const buffer = Buffer.from(bytes);
|
||
|
||
// Сохраняем в БД
|
||
const image = new Image({
|
||
filename,
|
||
originalName: file.name,
|
||
mimetype: file.type,
|
||
size: file.size,
|
||
data: buffer,
|
||
funnelId,
|
||
description,
|
||
uploadedBy: 'admin' // TODO: получать из сессии когда будет аутентификация
|
||
});
|
||
|
||
await image.save();
|
||
|
||
// Возвращаем информацию без Buffer данных
|
||
return NextResponse.json({
|
||
id: image._id,
|
||
filename: image.filename,
|
||
originalName: image.originalName,
|
||
mimetype: image.mimetype,
|
||
size: image.size,
|
||
uploadedAt: image.uploadedAt,
|
||
url: `/api/images/${image.filename}`
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('Image upload error:', error);
|
||
return NextResponse.json(
|
||
{ error: 'Internal server error' },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|