Skip to content

Commit

Permalink
Finished section 9
Browse files Browse the repository at this point in the history
  • Loading branch information
takuyadev committed Nov 5, 2022
1 parent 2025183 commit 47c6e0e
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 1 deletion.
117 changes: 117 additions & 0 deletions controllers/reviews.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
const Courses = require('../model/Courses')
const Review = require('../model/Review')
const asyncHandler = require('../middleware/async');
const ErrorResponse = require('../utils/errorResponse');
const Bootcamp = require('../model/Bootcamp');


// @desc Get all reviews
// @route GET /api/v1/reviews
// @route GET /api/v1/bootcamps/:bootcampId/reviews
// @access Public
exports.getReviews = asyncHandler(async (req, res, next) => {

// If parameter is filled out
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 Create review
// @route POST /api/v1/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 not 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 found 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
})

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) => {

let review = await Review.findById(req.params.id)

if (!review) {
return next(new ErrorResponse(`No review found 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: {}
})
})
2 changes: 1 addition & 1 deletion middleware/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const errorHandler = (err, req, res, next) => {

// Mongoose bad ObjectId
if (err.name === 'CastError') {
const message = `Resource not found`;
const message = `Resource not found id of ${error.value}`;
error = new ErrorResponse(message, 404);
}

Expand Down
71 changes: 71 additions & 0 deletions model/Review.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
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 some text']
},
rating: {
type: Number,
min: 1,
max: 10,
required: [true, "Please add a review rating"]
},
bootcamp: {
type: mongoose.Schema.ObjectId,
// Reference to Schema, not database
ref: 'Bootcamp',
required: true
},
user: {
type: mongoose.Schema.ObjectId,
// Reference to Schema, not database
ref: 'User',
required: true
}
})

ReviewSchema.index({ bootcamp: 1, user: 1 }, { unique: true })

// static method to get avg rating and save
ReviewSchema.statics.getAverageRating = async function (bootcampId) {
const obj = await this.aggregate(
[
{
$match: { bootcamp: bootcampId }
},
{
$group: {
_id: '$bootcamp',
averageRating: { $avg: '$rating' }
}
}
]
)
try {
await this.model('Bootcamp').findByIdAndUpdate(bootcampId, {
averageRating: obj[0].averageRating
})
} catch (err) {
console.error(err)
}
}

// Call getAverageRating after save
ReviewSchema.post('save', async function () {
await this.constructor.getAverageRating(this.bootcamp)
})

// Call getAverageRating before remove
ReviewSchema.pre('remove', async function () {
await this.constructor.getAverageRating(this.bootcamp)
})


module.exports = mongoose.model('Review', ReviewSchema)
2 changes: 2 additions & 0 deletions routes/bootcamps.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ const advancedResults = require('../middleware/advancedResults')

// Include other resource routers
const courseRouter = require('./courses')
const reviewRouter = require('./reviews')

const router = express.Router()

const { protect, authorize } = require('../middleware/auth')

// Re-route into other resource routers
router.use('/:bootcampId/courses', courseRouter)
router.use('/:bootcampId/reviews', reviewRouter)

router.route('/:id/photo').put(protect, authorize('publisher', 'admin'), bootcampPhotoUpload)

Expand Down
21 changes: 21 additions & 0 deletions routes/reviews.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const express = require('express')
const { getReviews, getReview, addReview, updateReview, deleteReview } = require('../controllers/reviews')
const router = express.Router({ mergeParams: true });

const Review = require('../model/Review')
const advancedResults = require('../middleware/advancedResults')
const { protect, authorize } = require('../middleware/auth')

router.route('/')
.get(advancedResults(Review, {
path: 'bootcamp',
select: 'name description'
}), getReviews)
.post(protect, authorize('user', 'admin'), addReview)

router.route('/:id')
.get(getReview)
.put(protect, authorize("user", "admin"), updateReview)
.delete(protect, authorize("user", "admin"), deleteReview)

module.exports = router
4 changes: 4 additions & 0 deletions seeder.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dotenv.config({ path: './config/config.env' })
const Bootcamp = require('./model/Bootcamp')
const Courses = require('./model/Courses')
const User = require('./model/User')
const Review = require('./model/Review')

// Connect to database
mongoose.connect(process.env.MONGO_URI)
Expand All @@ -17,6 +18,7 @@ mongoose.connect(process.env.MONGO_URI)
const bootcamps = JSON.parse(fs.readFileSync(`${__dirname}/_data/bootcamps.json`, 'utf-8'));
const courses = JSON.parse(fs.readFileSync(`${__dirname}/_data/courses.json`, 'utf-8'));
const users = JSON.parse(fs.readFileSync(`${__dirname}/_data/users.json`, 'utf-8'));
const reviews = JSON.parse(fs.readFileSync(`${__dirname}/_data/reviews.json`, 'utf-8'));


// Import into DB
Expand All @@ -25,6 +27,7 @@ const importData = async () => {
await Bootcamp.create(bootcamps)
await Courses.create(courses)
await User.create(users)
await Review.create(reviews)
console.log('Data imported...'.green.inverse)
} catch (error) {
console.error(error)
Expand All @@ -37,6 +40,7 @@ const deleteData = async () => {
await Bootcamp.deleteMany()
await Courses.deleteMany()
await User.deleteMany()
await Review.deleteMany()
console.log('Data destroyed...'.red.inverse)
} catch (error) {
console.error(error)
Expand Down
2 changes: 2 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const bootcamps = require('./routes/bootcamps')
const courses = require('./routes/courses')
const auth = require('./routes/auth')
const users = require('./routes/users')
const reviews = require('./routes/reviews')
const app = express()

// Body Parser
Expand Down Expand Up @@ -48,6 +49,7 @@ app.use('/api/v1/bootcamps', bootcamps)
app.use('/api/v1/courses', courses)
app.use('/api/v1/auth', auth)
app.use('/api/v1/users', users)
app.use('/api/v1/reviews', reviews)

app.use(errorHandler)

Expand Down

0 comments on commit 47c6e0e

Please sign in to comment.