-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added reviews and security middlewares
- Loading branch information
1 parent
43a9ef7
commit e1e63b1
Showing
12 changed files
with
476 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
const ErrorResponse = require('../utils/errorResponse'); | ||
const asyncHandler = require('../middleware/async'); | ||
const Review = require('../models/Review'); | ||
const Bootcamp = require('../models/Bootcamp'); | ||
|
||
// @desc Get reviews | ||
// @route GET /api/v1/reviews | ||
// @route GET /api/v1/bootcamps/:bootcampId/reviews | ||
// @access Public | ||
exports.getReviews = asyncHandler(async (req, res, next) => { | ||
if (req.params.bootcampId) { | ||
const reviews = await Review.find({ bootcamp: req.params.bootcampId }); | ||
|
||
return res.status(200).json({ | ||
success: true, | ||
count: reviews.length, | ||
data: reviews, | ||
}); | ||
} else { | ||
res.status(200).json(res.advancedResults); | ||
} | ||
}); | ||
|
||
// @desc Get single review | ||
// @route GET /api/v1/reviews/:id | ||
// @access Public | ||
exports.getReview = asyncHandler(async (req, res, next) => { | ||
const review = await Review.findById(req.params.id).populate({ | ||
path: 'bootcamp', | ||
select: 'name description', | ||
}); | ||
|
||
if (!review) { | ||
return next( | ||
new ErrorResponse(`No review found with the id of ${req.params.id}`, 404) | ||
); | ||
} | ||
|
||
res.status(200).json({ | ||
success: true, | ||
data: review, | ||
}); | ||
}); | ||
|
||
// @desc Add review | ||
// @route POST /api/v1/bootcamps/:bootcampId/reviews | ||
// @access Private | ||
exports.addReview = asyncHandler(async (req, res, next) => { | ||
req.body.bootcamp = req.params.bootcampId; | ||
|
||
req.body.user = req.user.id; | ||
|
||
const bootcamp = await Bootcamp.findById(req.params.bootcampId); | ||
|
||
if (!bootcamp) { | ||
return next( | ||
new ErrorResponse( | ||
`No bootcamp with the id of ${req.params.bootcampId}`, | ||
404 | ||
) | ||
); | ||
} | ||
|
||
const review = await Review.create(req.body); | ||
|
||
res.status(201).json({ | ||
success: true, | ||
data: review, | ||
}); | ||
}); | ||
|
||
// @desc Update review | ||
// @route PUT /api/v1/reviews/:id | ||
// @access Private | ||
exports.updateReview = asyncHandler(async (req, res, next) => { | ||
let review = await Review.findById(req.params.id); | ||
|
||
if (!review) { | ||
return next( | ||
new ErrorResponse(`No review with the id of ${req.params.id}`, 404) | ||
); | ||
} | ||
|
||
// Make sure review belongs to user or user is admin | ||
if (review.user.toString() !== req.user.id && req.user.role !== 'admin') { | ||
return next(new ErrorResponse(`Not authorized to update review`, 401)); | ||
} | ||
|
||
review = await Review.findByIdAndUpdate(req.params.id, req.body, { | ||
new: true, | ||
runValidators: true, | ||
}); | ||
|
||
review.save(); | ||
|
||
res.status(200).json({ | ||
success: true, | ||
data: review, | ||
}); | ||
}); | ||
|
||
// @desc Delete review | ||
// @route DELETE /api/v1/reviews/:id | ||
// @access Private | ||
exports.deleteReview = asyncHandler(async (req, res, next) => { | ||
const review = await Review.findById(req.params.id); | ||
|
||
if (!review) { | ||
return next( | ||
new ErrorResponse(`No review with the id of ${req.params.id}`, 404) | ||
); | ||
} | ||
|
||
// Make sure review belongs to user or user is admin | ||
if (review.user.toString() !== req.user.id && req.user.role !== 'admin') { | ||
return next(new ErrorResponse(`Not authorized to update review`, 401)); | ||
} | ||
|
||
await review.remove(); | ||
|
||
res.status(200).json({ | ||
success: true, | ||
data: {}, | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
const mongoose = require('mongoose'); | ||
|
||
const ReviewSchema = new mongoose.Schema({ | ||
title: { | ||
type: String, | ||
trim: true, | ||
required: [true, 'Please add a title for the review'], | ||
maxlength: 100, | ||
}, | ||
text: { | ||
type: String, | ||
required: [true, 'Please add a some text'], | ||
}, | ||
rating: { | ||
type: Number, | ||
min: 1, | ||
max: 10, | ||
required: [true, 'Please add a rating between 1 to 10'], | ||
}, | ||
createdAt: { | ||
type: Date, | ||
default: Date.now, | ||
}, | ||
bootcamp: { | ||
type: mongoose.Schema.ObjectId, | ||
ref: 'Bootcamp', | ||
required: true, | ||
}, | ||
user: { | ||
type: mongoose.Schema.ObjectId, | ||
ref: 'User', | ||
required: true, | ||
}, | ||
}); | ||
|
||
// Prevent user from submitting more than one review per bootcamp | ||
ReviewSchema.index({ bootcamp: 1, user: 1 }, { unique: true }); | ||
|
||
// Static method to get avg rating for bootcamp and save | ||
ReviewSchema.statics.getAverageReview = async function (bootcampId) { | ||
// console.log('Calculating avg Review...'.blue); | ||
|
||
const obj = await this.aggregate([ | ||
{ | ||
$match: { bootcamp: bootcampId }, | ||
}, | ||
{ | ||
$group: { | ||
_id: '$bootcamp', | ||
averageRating: { $avg: '$rating' }, | ||
}, | ||
}, | ||
]); | ||
|
||
// console.log(obj); | ||
try { | ||
await this.model('Bootcamp').findByIdAndUpdate(bootcampId, { | ||
averageRating: obj[0].averageRating, | ||
}); | ||
} catch (err) { | ||
console.error(err); | ||
} | ||
}; | ||
|
||
// Call getAverageReview after save | ||
ReviewSchema.post('save', function () { | ||
this.constructor.getAverageReview(this.bootcamp); | ||
}); | ||
|
||
// Call getAverageReview before remove | ||
ReviewSchema.pre('remove', function () { | ||
this.constructor.getAverageReview(this.bootcamp); | ||
}); | ||
|
||
module.exports = mongoose.model('Review', ReviewSchema); |
Oops, something went wrong.