test commit

This commit is contained in:
Kirill
2026-05-19 11:25:23 +05:00
parent f8867f6457
commit 5adbe9baa7
81 changed files with 6549 additions and 3108 deletions
+58 -66
View File
@@ -1,39 +1,35 @@
import { publicReviewAuthorDisplay } from '../../lib/review-display.js'
import { prisma } from '../../lib/prisma.js'
import { publicReviewAuthorDisplay } from '../../lib/review-display.js'
import { persistMultipartImages } from '../../lib/upload-images.js'
import {
formatFileTooLargeMessage,
getOtherUploadMaxFileBytes,
isMultipartFileTooLargeError,
} from '../../lib/upload-limits.js'
import { persistMultipartImages } from '../../lib/upload-images.js'
export async function registerPublicReviewRoutes(fastify) {
fastify.post(
'/api/reviews/upload-image',
{ preHandler: [fastify.authenticate] },
async (request, reply) => {
try {
const urls = await persistMultipartImages(request, {
maxFiles: 1,
maxFileBytes: getOtherUploadMaxFileBytes(),
subdir: 'reviews',
})
if (urls.length !== 1) return reply.code(400).send({ error: 'Нужно прикрепить 1 изображение' })
return { url: urls[0] }
} 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(getOtherUploadMaxFileBytes())
statusCode = 413
}
return reply.code(statusCode).send({ error: message })
fastify.post('/api/reviews/upload-image', { preHandler: [fastify.authenticate] }, async (request, reply) => {
try {
const urls = await persistMultipartImages(request, {
maxFiles: 1,
maxFileBytes: getOtherUploadMaxFileBytes(),
subdir: 'reviews',
})
if (urls.length !== 1) return reply.code(400).send({ error: 'Нужно прикрепить 1 изображение' })
return { url: urls[0] }
} 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(getOtherUploadMaxFileBytes())
statusCode = 413
}
},
)
return reply.code(statusCode).send({ error: message })
}
})
fastify.get('/api/reviews/latest', async (request, reply) => {
const limitRaw = request.query?.limit
@@ -102,46 +98,42 @@ export async function registerPublicReviewRoutes(fastify) {
return { items, total, page, pageSize }
})
fastify.post(
'/api/products/:id/reviews',
{ preHandler: [fastify.authenticate] },
async (request, reply) => {
const userId = request.user.sub
const { id: productId } = request.params
fastify.post('/api/products/:id/reviews', { preHandler: [fastify.authenticate] }, async (request, reply) => {
const userId = request.user.sub
const { id: productId } = request.params
const product = await prisma.product.findFirst({ where: { id: productId, published: true } })
if (!product) return reply.code(404).send({ error: 'Товар не найден' })
const product = await prisma.product.findFirst({ where: { id: productId, published: true } })
if (!product) return reply.code(404).send({ error: 'Товар не найден' })
const rating = Number(request.body?.rating)
if (!Number.isFinite(rating) || rating < 1 || rating > 5) {
return reply.code(400).send({ error: 'rating должен быть от 1 до 5' })
}
const textRaw = request.body?.text
const text = textRaw === null || textRaw === undefined ? null : String(textRaw).trim()
if (text !== null && text.length > 1000) return reply.code(400).send({ error: 'Отзыв слишком длинный' })
const imageUrlRaw = request.body?.imageUrl
const imageUrl = imageUrlRaw === null || imageUrlRaw === undefined ? null : String(imageUrlRaw).trim()
if (imageUrl !== null && imageUrl.length > 300) return reply.code(400).send({ error: 'Ссылка на фото слишком длинная' })
if (imageUrl !== null && imageUrl.length > 0 && !imageUrl.startsWith('/uploads/')) {
return reply.code(400).send({ error: 'Некорректная ссылка на изображение' })
}
const rating = Number(request.body?.rating)
if (!Number.isFinite(rating) || rating < 1 || rating > 5) {
return reply.code(400).send({ error: 'rating должен быть от 1 до 5' })
}
const textRaw = request.body?.text
const text = textRaw === null || textRaw === undefined ? null : String(textRaw).trim()
if (text !== null && text.length > 1000) return reply.code(400).send({ error: 'Отзыв слишком длинный' })
const imageUrlRaw = request.body?.imageUrl
const imageUrl = imageUrlRaw === null || imageUrlRaw === undefined ? null : String(imageUrlRaw).trim()
if (imageUrl !== null && imageUrl.length > 300)
return reply.code(400).send({ error: 'Ссылка на фото слишком длинная' })
if (imageUrl !== null && imageUrl.length > 0 && !imageUrl.startsWith('/uploads/')) {
return reply.code(400).send({ error: 'Некорректная ссылка на изображение' })
}
try {
const created = await prisma.review.create({
data: {
productId,
userId,
rating: Math.floor(rating),
text: text && text.length ? text : null,
imageUrl: imageUrl && imageUrl.length ? imageUrl : null,
status: 'pending',
},
})
return reply.code(201).send({ item: created })
} catch {
return reply.code(409).send({ error: 'Вы уже оставляли отзыв на этот товар' })
}
},
)
try {
const created = await prisma.review.create({
data: {
productId,
userId,
rating: Math.floor(rating),
text: text && text.length ? text : null,
imageUrl: imageUrl && imageUrl.length ? imageUrl : null,
status: 'pending',
},
})
return reply.code(201).send({ item: created })
} catch {
return reply.code(409).send({ error: 'Вы уже оставляли отзыв на этот товар' })
}
})
}