116 lines
3.2 KiB
TypeScript
116 lines
3.2 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
||
import connectMongoDB from '@/lib/mongodb';
|
||
import { Image, type IImage } from '@/lib/models/Image';
|
||
import { IS_FRONTEND_ONLY_BUILD } from '@/lib/runtime/buildVariant';
|
||
|
||
export async function GET(
|
||
request: NextRequest,
|
||
{ params }: { params: Promise<{ filename: string }> }
|
||
) {
|
||
try {
|
||
// Проверяем что это полная сборка (с БД)
|
||
if (IS_FRONTEND_ONLY_BUILD) {
|
||
return NextResponse.json(
|
||
{ error: 'Image serving not available in frontend-only mode' },
|
||
{ status: 403 }
|
||
);
|
||
}
|
||
|
||
await connectMongoDB();
|
||
|
||
const { filename } = await params;
|
||
|
||
if (!filename) {
|
||
return NextResponse.json(
|
||
{ error: 'Filename is required' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
const image = await Image.findOne({ filename }).lean() as IImage | null;
|
||
|
||
if (!image) {
|
||
return NextResponse.json(
|
||
{ error: 'Image not found' },
|
||
{ status: 404 }
|
||
);
|
||
}
|
||
|
||
// Возвращаем изображение с правильными заголовками
|
||
const buffer = image.data instanceof Buffer ? image.data : Buffer.from(image.data);
|
||
|
||
// Специальная обработка для SVG файлов
|
||
let contentType = image.mimetype;
|
||
if (filename.endsWith('.svg') && contentType === 'image/svg+xml') {
|
||
contentType = 'image/svg+xml; charset=utf-8';
|
||
}
|
||
|
||
return new NextResponse(buffer as unknown as BodyInit, {
|
||
status: 200,
|
||
headers: {
|
||
'Content-Type': contentType,
|
||
'Content-Length': buffer.length.toString(),
|
||
'Cache-Control': 'public, max-age=31536000, immutable',
|
||
'Content-Disposition': `inline; filename="${image.originalName}"`,
|
||
'Access-Control-Allow-Origin': '*',
|
||
// Дополнительные заголовки для SVG
|
||
'X-Content-Type-Options': 'nosniff',
|
||
},
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('Image serving error:', error);
|
||
return NextResponse.json(
|
||
{ error: 'Internal server error' },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|
||
|
||
export async function DELETE(
|
||
request: NextRequest,
|
||
{ params }: { params: Promise<{ filename: string }> }
|
||
) {
|
||
try {
|
||
// Проверяем что это полная сборка (с БД)
|
||
if (IS_FRONTEND_ONLY_BUILD) {
|
||
return NextResponse.json(
|
||
{ error: 'Image deletion not available in frontend-only mode' },
|
||
{ status: 403 }
|
||
);
|
||
}
|
||
|
||
await connectMongoDB();
|
||
|
||
const { filename } = await params;
|
||
|
||
if (!filename) {
|
||
return NextResponse.json(
|
||
{ error: 'Filename is required' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
const deletedImage = await Image.findOneAndDelete({ filename });
|
||
|
||
if (!deletedImage) {
|
||
return NextResponse.json(
|
||
{ error: 'Image not found' },
|
||
{ status: 404 }
|
||
);
|
||
}
|
||
|
||
return NextResponse.json({
|
||
message: 'Image deleted successfully',
|
||
filename: deletedImage.filename
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('Image deletion error:', error);
|
||
return NextResponse.json(
|
||
{ error: 'Internal server error' },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|