116 lines
3.8 KiB
TypeScript
116 lines
3.8 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
import prisma from '@/lib/prisma';
|
|
|
|
export async function POST(
|
|
req: NextRequest,
|
|
context: { params: Promise<{ id: string }> }
|
|
) {
|
|
const { id: paramId } = await context.params;
|
|
const userId = req.headers.get('x-user-id');
|
|
|
|
if (!userId) {
|
|
return NextResponse.json({ error: 'Utilisateur non identifié' }, { status: 401 });
|
|
}
|
|
|
|
try {
|
|
const { value, comment } = await req.json();
|
|
|
|
if (!value || value < 1 || value > 5) {
|
|
return NextResponse.json({ error: 'Valeur de note invalide (1-5)' }, { status: 400 });
|
|
}
|
|
|
|
// 1. Resolve actual Business UUID if paramId is a slug
|
|
const business = await prisma.business.findFirst({
|
|
where: {
|
|
OR: [
|
|
{ id: paramId },
|
|
{ slug: paramId }
|
|
]
|
|
},
|
|
select: { id: true }
|
|
});
|
|
|
|
if (!business) {
|
|
return NextResponse.json({ error: "Les données de démonstration ne peuvent pas recevoir d'avis. Veuillez créer votre propre entreprise pour tester." }, { status: 403 });
|
|
}
|
|
|
|
const businessId = business.id;
|
|
const ownerId = (business as any).ownerId;
|
|
|
|
// 2. Security: Don't allow owner to rate themselves
|
|
if (userId === ownerId) {
|
|
return NextResponse.json({ error: "Vous ne pouvez pas noter votre propre entreprise." }, { status: 403 });
|
|
}
|
|
|
|
// 3. Fetch existing rating to check rules
|
|
const existingRating = await prisma.rating.findUnique({
|
|
where: {
|
|
userId_businessId: {
|
|
userId,
|
|
businessId
|
|
}
|
|
}
|
|
});
|
|
|
|
if (existingRating) {
|
|
// Rule: Score can only be re-evaluated UPWARDS
|
|
if (value < existingRating.value) {
|
|
return NextResponse.json({
|
|
error: `La note ne peut être réévaluée qu'à la hausse. Votre note actuelle est de ${existingRating.value} étoiles.`
|
|
}, { status: 400 });
|
|
}
|
|
|
|
// Rule: Comment is IMMUTABLE once set
|
|
// We only update the value. If the comment was empty, we can set it once.
|
|
await prisma.rating.update({
|
|
where: { id: existingRating.id },
|
|
data: {
|
|
value,
|
|
comment: existingRating.comment ? undefined : comment, // Only set if it was null
|
|
status: 'PENDING' // Reset to pending for re-moderation
|
|
}
|
|
});
|
|
} else {
|
|
// 4. Create new rating
|
|
await prisma.rating.create({
|
|
data: {
|
|
value,
|
|
comment,
|
|
userId,
|
|
businessId,
|
|
status: 'PENDING'
|
|
}
|
|
});
|
|
}
|
|
|
|
// 3. Aggregate all ratings for this business
|
|
const stats = await prisma.rating.aggregate({
|
|
where: { businessId },
|
|
_avg: { value: true },
|
|
_count: { value: true }
|
|
});
|
|
|
|
const newRating = stats._avg.value || 0;
|
|
const newRatingCount = stats._count.value || 0;
|
|
|
|
// 4. Update the business
|
|
const updatedBusiness = await prisma.business.update({
|
|
where: { id: businessId },
|
|
data: {
|
|
rating: newRating,
|
|
ratingCount: newRatingCount
|
|
}
|
|
});
|
|
|
|
return NextResponse.json({
|
|
rating: updatedBusiness.rating,
|
|
ratingCount: updatedBusiness.ratingCount,
|
|
message: 'Vote enregistré avec succès'
|
|
});
|
|
|
|
} catch (error: any) {
|
|
console.error('Error rating business:', error);
|
|
return NextResponse.json({ error: 'Erreur serveur lors du vote' }, { status: 500 });
|
|
}
|
|
}
|