w-funnel/src/app/api/images/upload/route.ts
dev.daminik00 5aea1c8a09 fix
2025-10-01 16:47:04 +02:00

90 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 }
);
}
}