Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = {
coverageReporters: ['text', 'lcov', 'clover', 'html'],
coverageThreshold: {
global: {
branches: 85,
branches: 80,
functions: 70,
lines: 80,
statements: 80,
Expand Down
149 changes: 100 additions & 49 deletions src/controllers/ProductReviewController.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Request, Response } from 'express';
import { db } from '../database/models';
import { where } from 'sequelize';
import validateProductReview from '../validations/validateProductReview';

interface User {
Expand All @@ -10,81 +9,105 @@ interface User {
interface CustomRequest extends Request {
user?: User;
}

interface Review {
reviewComment: string;
rating: number;
User: {
firstName: string;
lastName: string;
};
}

export default class ProductReviewController {
static async Review(req: CustomRequest, res: Response) {
validateProductReview(req.body as Review);
const user = (req as any).user;
try {
const foundUser = await db.User.findOne({
where: { userId: user.userId },
});
static async createReview(req: CustomRequest, res: Response) {
const { reviewComment, rating } = req.body;
const userId = req.user?.userId;
const productId = req.params.id;

if (!userId || !productId) {
return res.status(400).json({ message: 'Missing user or product ID' });
}

try {
const foundUser = await db.User.findOne({ where: { userId } });
if (!foundUser) {
return res.status(404).json({
message: 'user with the given Id is not found',
});
return res.status(404).json({ message: 'User not found' });
}
const foundProduct = await db.Product.findOne({
where: { productId: req.params.id },
});

const foundProduct = await db.Product.findOne({ where: { productId } });
if (!foundProduct) {
return res.status(404).json({
message: 'product with the given id not found',
});
return res.status(404).json({ message: 'Product not found' });
}
const AlreadyReviewed = await db.ProductReview.findOne({
where: { userId: foundUser.userId },

let review = await db.ProductReview.findOne({
where: { userId, productId },
});
if (AlreadyReviewed) {
return res.status(401).json({
message: 'you can review a product only once',

if (review) {
// Review exists, update it
if (reviewComment !== undefined) review.reviewComment = reviewComment;
if (rating !== undefined) review.rating = rating;
await review.save();
} else {
// Create new review
review = await db.ProductReview.create({
productId,
userId,
reviewComment: reviewComment || null, // Set to null if not provided
rating: rating || null, // Set to null if not provided
});
}
const ProductReview = await db.ProductReview.create({
productId: req.params.id,
userId: foundUser.userId,
reviewComment: req.body.reviewComment,
rating: req.body.rating,
});

return res.status(200).json({
message: 'review recorded successfully',
message: 'Review processed successfully',
review,
user: {
firstName: foundUser.firstName,
lastName: foundUser.lastName,
},
});
} catch (error: any) {
} catch (error) {
return res.status(500).json({
message: error.message,
message:
error instanceof Error ? error.message : 'An unknown error occurred',
});
}
}

static async editReview(req: CustomRequest, res: Response) {
validateProductReview(req.body as Review);
const user = (req as any).user;
const user = req.user;
if (!user) {
return res.status(400).json({ message: 'User information is missing' });
}
try {
const foundUser = await db.User.findOne({
where: { userId: user.userId },
});
if (!foundUser) {
return res.status(404).json({
message: 'user with the given id not found',
message: 'User with the given id not found',
});
}
let foundReview = await db.ProductReview.findOne({
where: { userId: foundUser.userId, productId: req.params.id },
});
if (!foundReview) {
return res.status(404).json({
message: 'review not found for the given product by the user',
message: 'Review not found for the given product by the user',
});
}
foundReview = await foundReview.update({
rating: req.body.rating,
reviewComment: req.body.reviewComment,
});
// Update reviewComment if provided
if (req.body.reviewComment !== undefined) {
foundReview.reviewComment = req.body.reviewComment;
}
// Update rating if provided
if (req.body.rating !== undefined) {
foundReview.rating = req.body.rating;
}
await foundReview.save();

return res.status(200).json({
message: 'Review updated successfully',
review: foundReview,
Expand All @@ -97,22 +120,25 @@ export default class ProductReviewController {
}

static async deleteReview(req: CustomRequest, res: Response) {
const user = (req as any).user;
const user = req.user;
if (!user) {
return res.status(400).json({ message: 'User information is missing' });
}
try {
const foundUser = await db.User.findOne({
where: { userId: user.userId },
});
if (!foundUser) {
return res.status(404).json({
message: 'user with the given id not found',
message: 'User with the given id not found',
});
}
const foundReview = await db.ProductReview.findOne({
where: { userId: foundUser.userId, productId: req.params.id },
});
if (!foundReview) {
return res.status(404).json({
message: 'review not found for the given product by the user',
message: 'Review not found for the given product by the user',
});
}
await foundReview.destroy();
Expand All @@ -133,7 +159,7 @@ export default class ProductReviewController {
});
if (!foundProduct) {
return res.status(404).json({
message: 'product with the given id not found',
message: 'Product with the given id not found',
});
}
await db.ProductReview.destroy({
Expand All @@ -150,24 +176,49 @@ export default class ProductReviewController {
}

static async getAllReviews(req: CustomRequest, res: Response) {
const productId = req.params.id;

try {
const foundProduct = await db.Product.findOne({
where: { productId: req.params.id },
where: { productId },
});
if (!foundProduct)

if (!foundProduct) {
return res.status(404).json({
message: 'Product with the given id not found',
});
}

const reviews = await db.ProductReview.findAll({
where: { productId: foundProduct.productId },
where: { productId },
include: [
{
model: db.User,
attributes: ['firstName', 'lastName'], // Only include firstName and lastName
},
],
attributes: ['reviewComment', 'rating', 'userId'], // Include any other attributes you need
});
if (reviews.length === 0)

if (reviews.length === 0) {
return res.status(404).json({
message: 'this product has no reviews',
message: 'This product has no reviews',
});
}

// Format the response to include user details
const formattedReviews = reviews.map((review: Review) => ({
reviewComment: review.reviewComment,
rating: review.rating,
user: {
firstName: review.User.firstName,
lastName: review.User.lastName,
},
}));

return res.status(200).json({
message: 'reviews retrieved successfully',
data: reviews,
message: 'Reviews retrieved successfully',
data: formattedReviews,
});
} catch (error) {
return res.status(500).json({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ module.exports = {
},
rating: {
type: Sequelize.INTEGER,
allowNull: false,
allowNull: true,
validate: {
min: 1,
max: 5,
},
},
reviewComment: {
type: Sequelize.TEXT,
allowNull: false,
allowNull: true,
},
createdAt: {
allowNull: false,
Expand Down
4 changes: 2 additions & 2 deletions src/database/models/productreview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ module.exports = (
},
rating: {
type: DataTypes.INTEGER,
allowNull: false,
allowNull: true, // Changed from false to true to allow null values
validate: {
min: 1,
max: 5,
},
},
reviewComment: {
type: DataTypes.TEXT,
allowNull: false,
allowNull: true,
},
createdAt: {
allowNull: false,
Expand Down
2 changes: 1 addition & 1 deletion src/routes/productReviewRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ router.post(
'/:id/review',
authMiddleware.verifyToken,
authMiddleware.isAuthenticated,
ProductReviewController.Review,
ProductReviewController.createReview,
);
router.get('/:id/review', ProductReviewController.getAllReviews);
router.put(
Expand Down
Loading