45 lines
1.4 KiB
JavaScript
45 lines
1.4 KiB
JavaScript
import crypto from 'node:crypto'
|
|
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
|
|
export function safeImageExt(filename) {
|
|
const ext = path.extname(String(filename || '')).toLowerCase()
|
|
const allowed = new Set(['.png', '.jpg', '.jpeg', '.webp'])
|
|
return allowed.has(ext) ? ext : null
|
|
}
|
|
|
|
export function uploadError(message, statusCode = 400) {
|
|
const err = new Error(message)
|
|
err.statusCode = statusCode
|
|
return err
|
|
}
|
|
|
|
export async function persistMultipartImages(request, { maxFiles = 10 } = {}) {
|
|
if (!request.isMultipart()) {
|
|
throw uploadError('Ожидается multipart/form-data')
|
|
}
|
|
|
|
const uploadsDir = path.join(process.cwd(), 'uploads')
|
|
await fs.promises.mkdir(uploadsDir, { recursive: true })
|
|
|
|
const urls = []
|
|
const parts = request.parts()
|
|
for await (const part of parts) {
|
|
if (part.type !== 'file') continue
|
|
if (urls.length >= maxFiles) {
|
|
throw uploadError(`Можно загрузить не более ${maxFiles} файл(ов)`)
|
|
}
|
|
const ext = safeImageExt(part.filename)
|
|
if (!ext) {
|
|
throw uploadError('Разрешены только файлы: png, jpg, jpeg, webp')
|
|
}
|
|
|
|
const fileName = `${crypto.randomUUID()}${ext}`
|
|
const fullPath = path.join(uploadsDir, fileName)
|
|
await fs.promises.writeFile(fullPath, await part.toBuffer())
|
|
urls.push(`/uploads/${fileName}`)
|
|
}
|
|
|
|
return urls
|
|
}
|