feat(server): remove old /admin/uploads, validate isResized on product endpoints
This commit is contained in:
+1
-1
@@ -42,7 +42,7 @@ await fastify.register(jwt, {
|
|||||||
await fastify.register(multipart, {
|
await fastify.register(multipart, {
|
||||||
limits: {
|
limits: {
|
||||||
files: 10,
|
files: 10,
|
||||||
/** Совпадает с лимитом одного файла для `POST /api/admin/uploads` (товары, галерея). */
|
/** Совпадает с лимитом одного файла для `POST /api/admin/gallery/upload` (галерея). */
|
||||||
fileSize: getProductImageMaxFileBytes(),
|
fileSize: getProductImageMaxFileBytes(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
import { upsertGalleryImagesByUrls } from '../../lib/gallery.js'
|
|
||||||
import { prisma } from '../../lib/prisma.js'
|
import { prisma } from '../../lib/prisma.js'
|
||||||
import {
|
|
||||||
formatFileTooLargeMessage,
|
|
||||||
getProductImageMaxFileBytes,
|
|
||||||
isMultipartFileTooLargeError,
|
|
||||||
} from '../../lib/upload-limits.js'
|
|
||||||
import { persistMultipartImages } from '../../lib/upload-images.js'
|
|
||||||
|
|
||||||
const CREATE_PRODUCT_SCHEMA = {
|
const CREATE_PRODUCT_SCHEMA = {
|
||||||
body: {
|
body: {
|
||||||
@@ -59,33 +52,6 @@ export async function registerAdminProductRoutes(fastify) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
fastify.post(
|
|
||||||
'/api/admin/uploads',
|
|
||||||
{ preHandler: [fastify.verifyAdmin] },
|
|
||||||
async (request, reply) => {
|
|
||||||
try {
|
|
||||||
const urls = await persistMultipartImages(request, {
|
|
||||||
maxFiles: 10,
|
|
||||||
maxFileBytes: getProductImageMaxFileBytes(),
|
|
||||||
eager: true,
|
|
||||||
})
|
|
||||||
await upsertGalleryImagesByUrls(urls)
|
|
||||||
return { urls }
|
|
||||||
} catch (error) {
|
|
||||||
let message = error instanceof Error ? error.message : 'Не удалось загрузить файлы'
|
|
||||||
let statusCode =
|
|
||||||
error && typeof error === 'object' && 'statusCode' in error && Number.isInteger(error.statusCode)
|
|
||||||
? Number(error.statusCode)
|
|
||||||
: 400
|
|
||||||
if (isMultipartFileTooLargeError(error)) {
|
|
||||||
message = formatFileTooLargeMessage(getProductImageMaxFileBytes())
|
|
||||||
statusCode = 413
|
|
||||||
}
|
|
||||||
return reply.code(statusCode).send({ error: message })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
fastify.post(
|
fastify.post(
|
||||||
'/api/admin/products',
|
'/api/admin/products',
|
||||||
{ preHandler: [fastify.verifyAdmin], schema: CREATE_PRODUCT_SCHEMA },
|
{ preHandler: [fastify.verifyAdmin], schema: CREATE_PRODUCT_SCHEMA },
|
||||||
@@ -122,6 +88,25 @@ export async function registerAdminProductRoutes(fastify) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(body.imageUrls) && body.imageUrls.length > 0) {
|
||||||
|
const urls = body.imageUrls.map((u) => String(u || '').trim()).filter(Boolean)
|
||||||
|
if (urls.length > 0) {
|
||||||
|
const galleryImages = await prisma.galleryImage.findMany({
|
||||||
|
where: { url: { in: urls } },
|
||||||
|
select: { url: true, isResized: true },
|
||||||
|
})
|
||||||
|
const galleryMap = new Map(galleryImages.map((g) => [g.url, g]))
|
||||||
|
const notFound = urls.filter((u) => !galleryMap.has(u))
|
||||||
|
const notResized = urls.filter((u) => galleryMap.get(u) && !galleryMap.get(u).isResized)
|
||||||
|
if (notFound.length > 0) {
|
||||||
|
return reply.code(400).send({ error: 'Некоторые изображения не найдены в галерее' })
|
||||||
|
}
|
||||||
|
if (notResized.length > 0) {
|
||||||
|
return reply.code(400).send({ error: 'Изображения должны быть обработаны (resize) перед прикреплением к товару' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const n = Number(body.quantity)
|
const n = Number(body.quantity)
|
||||||
if (!Number.isInteger(n) || n < 0 || n > 10) {
|
if (!Number.isInteger(n) || n < 0 || n > 10) {
|
||||||
reply.code(400).send({ error: 'Количество — целое число от 0 до 10' })
|
reply.code(400).send({ error: 'Количество — целое число от 0 до 10' })
|
||||||
@@ -228,6 +213,25 @@ export async function registerAdminProductRoutes(fastify) {
|
|||||||
data.categoryId = cid
|
data.categoryId = cid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (body.imageUrls !== undefined && Array.isArray(body.imageUrls)) {
|
||||||
|
const urls = body.imageUrls.map((u) => String(u || '').trim()).filter(Boolean)
|
||||||
|
if (urls.length > 0) {
|
||||||
|
const galleryImages = await prisma.galleryImage.findMany({
|
||||||
|
where: { url: { in: urls } },
|
||||||
|
select: { url: true, isResized: true },
|
||||||
|
})
|
||||||
|
const galleryMap = new Map(galleryImages.map((g) => [g.url, g]))
|
||||||
|
const notFound = urls.filter((u) => !galleryMap.has(u))
|
||||||
|
const notResized = urls.filter((u) => galleryMap.get(u) && !galleryMap.get(u).isResized)
|
||||||
|
if (notFound.length > 0) {
|
||||||
|
return reply.code(400).send({ error: 'Некоторые изображения не найдены в галерее' })
|
||||||
|
}
|
||||||
|
if (notResized.length > 0) {
|
||||||
|
return reply.code(400).send({ error: 'Изображения должны быть обработаны (resize) перед прикреплением к товару' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const imagesUpdate =
|
const imagesUpdate =
|
||||||
body.imageUrls !== undefined
|
body.imageUrls !== undefined
|
||||||
? {
|
? {
|
||||||
|
|||||||
Reference in New Issue
Block a user