163 lines
4.7 KiB
TypeScript
163 lines
4.7 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
|
|
|
|
const s3Client = new S3Client({
|
|
region: 'ru-1',
|
|
endpoint: 'https://s3.twcstorage.ru',
|
|
credentials: {
|
|
accessKeyId: 'I6XD2OR7YO2ZN6L6Z629',
|
|
secretAccessKey: '9xCOoafisG0aB9lJNvdLO1UuK73fBvMcpHMdijrJ'
|
|
},
|
|
forcePathStyle: true
|
|
})
|
|
|
|
const BUCKET_NAME = '617774af-sfera'
|
|
|
|
// Разрешенные типы изображений
|
|
const ALLOWED_IMAGE_TYPES = [
|
|
'image/jpeg',
|
|
'image/jpg',
|
|
'image/png',
|
|
'image/webp',
|
|
'image/gif'
|
|
]
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const formData = await request.formData()
|
|
const file = formData.get('file') as File
|
|
const userId = formData.get('userId') as string
|
|
const type = formData.get('type') as string // 'service' или 'supply'
|
|
|
|
if (!file || !userId || !type) {
|
|
return NextResponse.json(
|
|
{ error: 'File, userId and type are required' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Проверяем тип (services или supplies)
|
|
if (!['service', 'supply'].includes(type)) {
|
|
return NextResponse.json(
|
|
{ error: 'Type must be either "service" or "supply"' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Проверяем, что файл не пустой
|
|
if (file.size === 0) {
|
|
return NextResponse.json(
|
|
{ error: 'File is empty' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Проверяем имя файла
|
|
if (!file.name || file.name.trim().length === 0) {
|
|
return NextResponse.json(
|
|
{ error: 'Invalid file name' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Проверяем тип файла
|
|
if (!ALLOWED_IMAGE_TYPES.includes(file.type)) {
|
|
return NextResponse.json(
|
|
{ error: `File type ${file.type} is not allowed. Only images are supported.` },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Ограничиваем размер файла (5MB для изображений)
|
|
if (file.size > 5 * 1024 * 1024) {
|
|
return NextResponse.json(
|
|
{ error: 'File size must be less than 5MB' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// Генерируем уникальное имя файла
|
|
const timestamp = Date.now()
|
|
// Более безопасная очистка имени файла
|
|
const safeFileName = file.name
|
|
.replace(/[^\w\s.-]/g, '_') // Заменяем недопустимые символы
|
|
.replace(/\s+/g, '_') // Заменяем пробелы на подчеркивания
|
|
.replace(/_{2,}/g, '_') // Убираем множественные подчеркивания
|
|
.toLowerCase() // Приводим к нижнему регистру
|
|
|
|
const folder = type === 'service' ? 'services' : 'supplies'
|
|
const key = `${folder}/${userId}/${timestamp}-${safeFileName}`
|
|
|
|
// Конвертируем файл в Buffer
|
|
const buffer = Buffer.from(await file.arrayBuffer())
|
|
|
|
// Очищаем метаданные от недопустимых символов
|
|
const cleanOriginalName = file.name.replace(/[^\w\s.-]/g, '_')
|
|
const cleanUserId = userId.replace(/[^\w-]/g, '')
|
|
const cleanType = type.replace(/[^\w]/g, '')
|
|
|
|
// Загружаем в S3
|
|
const command = new PutObjectCommand({
|
|
Bucket: BUCKET_NAME,
|
|
Key: key,
|
|
Body: buffer,
|
|
ContentType: file.type,
|
|
ACL: 'public-read',
|
|
Metadata: {
|
|
originalname: cleanOriginalName,
|
|
uploadedby: cleanUserId,
|
|
type: cleanType
|
|
}
|
|
})
|
|
|
|
await s3Client.send(command)
|
|
|
|
// Возвращаем URL файла и метаданные
|
|
const url = `https://s3.twcstorage.ru/${BUCKET_NAME}/${key}`
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
url,
|
|
key,
|
|
originalName: file.name,
|
|
size: file.size,
|
|
type: file.type
|
|
})
|
|
|
|
} catch (error) {
|
|
console.error('Error uploading service image:', error)
|
|
return NextResponse.json(
|
|
{ error: 'Failed to upload image' },
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
}
|
|
|
|
export async function DELETE(request: NextRequest) {
|
|
try {
|
|
const { key } = await request.json()
|
|
|
|
if (!key) {
|
|
return NextResponse.json(
|
|
{ error: 'Key is required' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
// TODO: Добавить удаление из S3
|
|
// const command = new DeleteObjectCommand({
|
|
// Bucket: BUCKET_NAME,
|
|
// Key: key
|
|
// })
|
|
// await s3Client.send(command)
|
|
|
|
return NextResponse.json({ success: true })
|
|
|
|
} catch (error) {
|
|
console.error('Error deleting service image:', error)
|
|
return NextResponse.json(
|
|
{ error: 'Failed to delete image' },
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
}
|