Skip to content

Commit

Permalink
authorization for reviews regarding if user is author of review
Browse files Browse the repository at this point in the history
  • Loading branch information
fichimura committed Mar 19, 2024
1 parent 6813383 commit 8a6ddcc
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 102 deletions.
11 changes: 11 additions & 0 deletions middleware.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { audiovisualSchema, reviewSchema } = require('./JoiSchemas/JoiSchemas');
const ExpressError = require('./utils/expressError');
const Audiovisual = require('./models/audiovisuals');
const Review = require('./models/audiovisualReview');

module.exports.isSignedIn = (req, res, next) => {
if (!req.isAuthenticated()) {
Expand Down Expand Up @@ -46,4 +47,14 @@ module.exports.validateReview = (req, res, next) => {
} else {
next();
}
}

module.exports.isReviewAuthor = async (req, res, next) => {
const { audiovisual_id, review_id } = req.params;
const review = await Review.findById(review_id);
if (!review.author.equals(req.user._id)) {
req.flash('error', 'You do not have permission to do that');
return res.redirect(`/audiovisuals/${audiovisual_id}`);
}
next();
}
39 changes: 32 additions & 7 deletions routes/reviewRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,23 @@ const router = express.Router({ mergeParams: true });
const Audiovisual = require('../models/audiovisuals');
const Review = require('../models/audiovisualReview');
const catchAsync = require('../utils/catchAsync');
const { isSignedIn, validateReview } = require('../middleware');
const { isSignedIn, validateReview, isReviewAuthor } = require('../middleware');
const todayDate = new Date();
const todayDateFormatted = todayDate.getFullYear() + "-" + (todayDate.getMonth() + 1) + "-" + todayDate.getDate();

//REVIEWS ROUTES
router.get('/reviews', catchAsync(async (req, res) => {
const all_reviews = await Review.find({});
res.render('reviews/index', { all_reviews });
}));

router.get('/audiovisuals/:audiovisual_id/reviews', catchAsync(async (req, res) => {
const audiovisual = await Audiovisual.findById(req.params.audiovisual_id).populate('reviews').populate('author');
console.log(audiovisual);
const audiovisual = await Audiovisual.findById(req.params.audiovisual_id).
populate({
path: 'reviews',
populate: {
path: 'author'
}
}).populate('author');
if (!audiovisual) {
req.flash('error', 'Cannot find audiovisual');
return res.redirect('/audiovisuals');
Expand All @@ -35,7 +39,6 @@ router.get('/audiovisuals/:audiovisual_id/reviews/new', isSignedIn, catchAsync(a
router.get('/audiovisuals/:audiovisual_id/reviews/:review_id', catchAsync(async (req, res) => {
const audiovisual = await Audiovisual.findById(req.params.audiovisual_id);
const review = await Review.findById(req.params.review_id).populate('author');
console.log(review);
if (!audiovisual) {
req.flash('error', 'Cannot find audiovisual');
return res.redirect('/audiovisuals');
Expand All @@ -50,7 +53,7 @@ router.get('/audiovisuals/:audiovisual_id/reviews/:review_id', catchAsync(async
router.post('/audiovisuals/:audiovisual_id/reviews', isSignedIn, validateReview, catchAsync(async (req, res) => {
const audiovisual = await Audiovisual.findById(req.params.audiovisual_id);
const review = new Review(req.body.review);
review.author = res.locals.currentUser;
review.author = req.user._id;
if (!review.title) review.title = todayDateFormatted + " - " + audiovisual.title;
review.date_added = todayDateFormatted;
audiovisual.reviews.push(review);
Expand All @@ -60,7 +63,29 @@ router.post('/audiovisuals/:audiovisual_id/reviews', isSignedIn, validateReview,
res.redirect(`/audiovisuals/${audiovisual._id}`);
}));

router.delete('/audiovisuals/:audiovisual_id/reviews/:review_id', isSignedIn, catchAsync(async (req, res) => {
router.get('/audiovisuals/:audiovisual_id/reviews/:review_id/edit', isSignedIn, isReviewAuthor, catchAsync(async (req, res) => {
const audiovisual = await Audiovisual.findById(req.params.audiovisual_id);
const review = await Review.findById(req.params.review_id).populate('author');
if (!audiovisual) {
req.flash('error', 'Cannot find audiovisual');
return res.redirect('/audiovisuals');
}
if (!review) {
req.flash('error', 'Cannot find review');
return res.redirect('/audiovisuals');
}
res.render('reviews/edit', { audiovisual, review });
}));

router.put('/audiovisuals/:audiovisual_id/reviews/:review_id', isSignedIn, isReviewAuthor, validateReview, catchAsync(async (req, res) => {
const { audiovisual_id, review_id } = req.params;
const review = await Review.findByIdAndUpdate(review_id, { ...req.body.review });
console.log(review);
req.flash('success', 'Successfully updated audiovisual');
res.redirect(`/audiovisuals/${audiovisual_id}/reviews/${review._id}`);
}));

router.delete('/audiovisuals/:audiovisual_id/reviews/:review_id', isSignedIn, isReviewAuthor, catchAsync(async (req, res) => {
const { audiovisual_id, review_id } = req.params;
await Audiovisual.findByIdAndUpdate(audiovisual_id, { $pull: { reviews: review_id } });
await Review.findByIdAndDelete(req.params.review_id);
Expand Down
107 changes: 55 additions & 52 deletions views/audiovisuals/index.ejs
Original file line number Diff line number Diff line change
@@ -1,60 +1,63 @@
<% layout('layouts/boilerplate') %>

<h1>Meerkat Audiovisuals</h1>
<div class="d-flex flex-row justify-content-end">
<a class="btn btn-success" href="/audiovisuals/new">New audiovisual</a>
</div>
<% if(currentUser){ %>
<hr>
<% for(let audiovisual of all_audiovisuals) { %>
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title fw-bold">
<%= audiovisual.title %>
</h5>
<div lass="d-flex flex-row">
<p class="fw-bold">Description:</p>
<div class="d-flex flex-row justify-content-end">
<a class="btn btn-success" href="/audiovisuals/new">New audiovisual</a>
</div>
<% } %>

<% if(audiovisual.description) { %>
<p class="text-truncate">
<%= audiovisual.description %>
</p>
<% }else { %>
<div class="fw-light fst-italic">
No description informed
</div>
<% }%>
</div>
<div class="d-flex flex-row">
<p class="fw-bold">Director:</p>
<hr>
<% for(let audiovisual of all_audiovisuals) { %>
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title fw-bold">
<%= audiovisual.title %>
</h5>
<div lass="d-flex flex-row">
<p class="fw-bold">Description:</p>
<% if(audiovisual.director) { %>
<p class="card-text">
<%= audiovisual.director %>
</p>
<% }else { %>
<div class="fw-light fst-italic">
No director informed
</div>
<% }%>
</div>
<div class="d-flex flex-row">
<p class="fw-bold">Release year:</p>
<% if(audiovisual.description) { %>
<p class="text-truncate">
<%= audiovisual.description %>
</p>
<% }else { %>
<div class="fw-light fst-italic">
No description informed
</div>
<% }%>
</div>
<div class="d-flex flex-row">
<p class="fw-bold">Director:</p>
<% if(audiovisual.release_year) { %>
<p class="card-text">
<%= audiovisual.release_year %>
</p>
<% }else { %>
<div class="fw-light fst-italic">
No release year informed
</div>
<% }%>
</div>
<div>
<a class="btn btn-primary" href="/audiovisuals/<%= audiovisual._id%>">View
%></a>
<% if(audiovisual.director) { %>
<p class="card-text">
<%= audiovisual.director %>
</p>
<% }else { %>
<div class="fw-light fst-italic">
No director informed
</div>
<% }%>
</div>
<div class="d-flex flex-row">
<p class="fw-bold">Release year:</p>
<% if(audiovisual.release_year) { %>
<p class="card-text">
<%= audiovisual.release_year %>
</p>
<% }else { %>
<div class="fw-light fst-italic">
No release year informed
</div>
<% }%>
</div>
<div>
<a class="btn btn-primary" href="/audiovisuals/<%= audiovisual._id%>">View
%></a>
</div>
</div>
</div>
</div>
</div>
<% } %>
<% } %>
78 changes: 78 additions & 0 deletions views/reviews/edit.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<% layout('layouts/boilerplate') %>
<h2>Edit Review: <%= review.title %> (<%= audiovisual.title %>)
</h2>

<form action="/audiovisuals/<%= audiovisual._id %>/reviews/<%=review._id%>?_method=PUT" method="POST"
class="validate-form" novalidate>
<div class="mb-2">
<label for="where">Review title</label>
<input class="form-control" id="where" type=" text" name="review[title]" value="<%= review.title%>">
</div>

<div class="mb-2">
<div class="d-flex flex-row">
<label class="form-label" for="rating">Rating: </label>
<span class="fw-bold ms-2" id="rangeValue">
<%= review.rating %>
</span>
</div>
<input class="form-range" type="range" min="0" max="5" step="0.5" id="rating" name="review[rating]"
value="2.5" required>

<div class="invalid-feedback">You need to rate <%=audiovisual.title %> in a range of 0 to 5
</div>

<script>
let rangeInput = document.getElementById('rating');
let rangeValue = document.getElementById('rangeValue');
rangeInput.addEventListener('input', () => {
rangeValue.textContent = rangeInput.value;
});
</script>
</div>

<div class="mb-2">
<label for="where">Where have you seen it?</label>
<input class="form-control" id="where" type=" text" name="review[where]" value="<%= review.where%>"">
</div>
<div class=" mb-2">
<label for="when">When have you seen it?</label>
<input class="form-control" id="when" type="number" value="2000" max="2099" min="1920" name="review[when]"
value="<%= review.when%>"">
</div>

<div class=" mb-2 input-group">
<label class="input-group-text">Notes</label>
<textarea class=" form-control" id="notes" cols="40" rows="5" name="review[notes]"
required><%=review.notes %></textarea>

<div class="invalid-feedback">You need to provide some note about <%=audiovisual.title %>
</div>
</div>

<div class="mb-2 form-check form-switch">
<label class=" form-check-label" for="switch">Favorite</label>
<input class="form-check-input me-3" type="checkbox" role="switch" id="switch">
<!-- Hidden input field to store boolean value -->
<input type="hidden" id="switchValue" name="review[favorite]">
<script>
document.addEventListener('DOMContentLoaded', function () {
const switchElement = document.getElementById("switch");
const switchValueInput = document.getElementById("switchValue");
switchValueInput.value = switchElement.checked ? 'true' : 'false';
switchElement.addEventListener('change', function () {
switchValueInput.value = switchElement.checked ? 'true' : 'false';
});
});
</script>
</div>

<div class="d-flex flex-row justify-content-between">
<button class="btn btn-success mb-3 px-5">Submit</button>
<a href="/audiovisuals/<%=audiovisual._id%>/reviews" class="btn btn-danger mb-3 px-5">Cancel</a>
</div>
</form>
83 changes: 43 additions & 40 deletions views/reviews/showAllReviews.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,48 @@
<h2>All reviews of <%= audiovisual.title%>
</h2>

<div class="d-flex flex-row justify-content-end">
<a class="btn btn-success" href="/audiovisuals/<%=audiovisual._id%>/reviews/new">New review of <%=
audiovisual.title %></a>
</div>
<hr>
<% if(currentUser){ %>
<div class="d-flex flex-row justify-content-end">
<a class="btn btn-success" href="/audiovisuals/<%=audiovisual._id%>/reviews/new">New review of <%=
audiovisual.title %></a>
</div>
<% } %>
<hr>

<% for(let review of audiovisual.reviews) { %>
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title fw-bold">
<%= review.title %>
</h5>
<div class="d-flex flex-row">
<span class="fw-bold">Author:</span>
<% if(review.author){ %>
<%= review.author.username %>
<% }else {%>
<span class="fw-light fst-italic">Review with no author</span>
<%} %>
</div>
<div class="d-flex flex-row">
<span class="fw-bold">Rating:</span>
<%= review.rating %>
</div>
<div class="d-flex flex-row">
<span class="fw-bold">Date added:</span>
<%= review.date_added %>
</div>
<div class="d-flex flex-row">
<span class="fw-bold">Favorite:</span>
<% if(review.favorite) { %>
Yes
<% }else { %>
No
<% } %>
</div>
<% for(let review of audiovisual.reviews) { %>
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title fw-bold">
<%= review.title %>
</h5>
<div class="d-flex flex-row card-subtitle mb-2 text-muted">
<span class="fw-bold">Author:</span>
<% if(review.author){ %>
<%= review.author.username %>
<% }else {%>
<span class="fw-light fst-italic">Review with no author</span>
<%} %>
</div>
<div class="d-flex flex-row">
<span class="fw-bold">Rating:</span>
<%= review.rating %>
</div>
<div class="d-flex flex-row">
<span class="fw-bold">Date added:</span>
<%= review.date_added %>
</div>
<div class="d-flex flex-row">
<span class="fw-bold">Favorite:</span>
<% if(review.favorite) { %>
Yes
<% }else { %>
No
<% } %>
</div>
<a class="btn btn-primary mt-3" href="/audiovisuals/<%= audiovisual._id %>/reviews/<%= review._id%>">See
review</a>
</div>
</div>
<% } %>
<a class="btn btn-primary mt-3"
href="/audiovisuals/<%= audiovisual._id %>/reviews/<%= review._id%>">See
review</a>
</div>
</div>
<% } %>
Loading

0 comments on commit 8a6ddcc

Please sign in to comment.