diff --git a/README.md b/README.md index 30a50e1..02bc15e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ If you want to deploy you'll also need: DEV_DATABASE_URL=postgres://postgres@localhost:5432/girlscode_library_app ``` -You may change this to 'postgres://:@localhost:5432/girlscode_library_app' +You may change this to 'postgres://username:password@localhost:5432/girlscode_library_app' if using different username/password than default. 3. Create the DB with `npx sequelize db:create` 4. Run the migrations with `npx sequelize db:migrate` diff --git a/src/migrations/20190120141524-review.js b/src/migrations/20190120141524-review.js new file mode 100644 index 0000000..ea72319 --- /dev/null +++ b/src/migrations/20190120141524-review.js @@ -0,0 +1,52 @@ +'use strict'; + +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.createTable('Reviews', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + BookId: { + allowNull: false, + type: Sequelize.INTEGER, + references: { + model: 'Books', + key: 'id' + } + }, + UserId: { + allowNull: false, + type: Sequelize.INTEGER, + references: { + model: 'Users', + key: 'id' + } + }, + Rating: { + allowNull: false, + type: Sequelize.INTEGER + }, + Text: { + defaultValue: false, + allowNull: false, + type: Sequelize.STRING + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: (queryInterface, Sequelize) => { + (queryInterface, Sequelize) => { + return queryInterface.dropTable('Reviews'); + } + } +}; diff --git a/src/models/review.js b/src/models/review.js new file mode 100644 index 0000000..99315a2 --- /dev/null +++ b/src/models/review.js @@ -0,0 +1,17 @@ +'use strict'; +module.exports = (sequelize, DataTypes) => { + const Review = sequelize.define('Review', { + BookId: DataTypes.INTEGER, + UserId: DataTypes.INTEGER, + Rating: DataTypes.INTEGER, + Text: DataTypes.STRING + }, {}); + Review.associate = function({Book, User}) { + Review.belongsTo(Book); + Review.belongsTo(User); + + }; + + + return Review; +}; diff --git a/src/models/user.js b/src/models/user.js index 77346fb..0678758 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -64,8 +64,10 @@ module.exports = (sequelize, DataTypes) => { beforeValidate: hashPassword } }); - User.associate = function({Loan}) { + User.associate = function({Loan, Review}) { User.hasMany(Loan); + User.hasMany(Review); }; + return User; }; diff --git a/src/routes/books.js b/src/routes/books.js index b699336..19bbfe3 100644 --- a/src/routes/books.js +++ b/src/routes/books.js @@ -1,11 +1,11 @@ import { Router } from 'express'; -import { Book } from '../models'; +import { Book, Review } from '../models'; import catchAsync from '../lib/catchAsync'; import { pick } from 'lodash'; import Sequelize from 'sequelize'; const router = Router(); - +const Op = Sequelize.Op; // Fields people are permitted to modify using the API. const permittedParams = ['title', 'author']; @@ -14,7 +14,6 @@ router.get('/', catchAsync(async (req, res) => { let books; if (req.query.q) { try { - const Op = Sequelize.Op; books = await Book.findAll({ where: { @@ -58,13 +57,21 @@ router.post('/', catchAsync(async (req, res) => { // Get a single book by ID. // TODO: Should render HTML, not return JSON. router.get('/:id', catchAsync(async (req, res) => { + let book; + let reviews; + let rating = 0; try { - const book = await Book.findByPk(req.params.id); - res.json(book); + book = await Book.findByPk(req.params.id); + reviews = await Review.findAll({where: {BookId: {[Op.eq]: book.id}}}); + if(reviews.length > 0) { + rating = reviews.reduce((a, review) => a + review.Rating,0) / reviews.length; + } + // res.json(book); } catch(e) { console.warn(e); res.status(400).send(e.toString()); } + res.render('books/show', {book: book, reviews: reviews, rating: rating}); })); // Update a book by ID. Supply fields in the same way as creating a book. diff --git a/src/routes/index.js b/src/routes/index.js index 4e962d1..ece69bd 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -4,6 +4,7 @@ import books from './books'; import users from './users'; import sessions from './sessions'; import loans from './loans'; +import review from './review'; import { Book, User } from '../models'; import catchAsync from '../lib/catchAsync'; @@ -14,6 +15,7 @@ router.use('/books', books); router.use('/users', users); router.use('/sessions', sessions); router.use('/loans', loans); +router.use('/review', review); router.get('/login', (req, res) => res.redirect('/sessions/new')); diff --git a/src/routes/review.js b/src/routes/review.js new file mode 100644 index 0000000..0a60429 --- /dev/null +++ b/src/routes/review.js @@ -0,0 +1,23 @@ +import { Router } from 'express'; +import { ensureLoggedIn } from 'connect-ensure-login'; + +import { Book, Review} from '../models'; +import catchAsync from '../lib/catchAsync'; + +const router = Router(); +const env = process.env.NODE_ENV || 'development'; + +router.post('/', + ensureLoggedIn(), + catchAsync(async (req, res) => { + const {BookId, Text, Rating} = req.body; + + const review = await req.user.createReview({BookId, Text, Rating}); + + + // const loan = await req.user.createLoan({BookId, dueDate}); + + res.redirect('/books/'+BookId); + }) +); +export default router; diff --git a/src/views/books/index.ejs b/src/views/books/index.ejs index 8b220ac..3a6afe9 100644 --- a/src/views/books/index.ejs +++ b/src/views/books/index.ejs @@ -4,7 +4,8 @@ <% books.forEach((book) => { %>

- <%- book.title %> by <%- book.author %>
+ <%- book.title %> by <%- book.author %> +
<% if (book.onLoan) { %> On loan <% } else { %> @@ -14,6 +15,7 @@ <% } %>

+

<%- book.id %>


<% }) %> diff --git a/src/views/books/show.ejs b/src/views/books/show.ejs new file mode 100644 index 0000000..7a2bfb7 --- /dev/null +++ b/src/views/books/show.ejs @@ -0,0 +1,25 @@ +

<%- book.title %>

+

<%- book.author %>

+

average rating: <%- rating %>

+ +<% reviews.forEach((review) => { %> +

Stars: <%- review.Rating %> <%- review.Text %>

+
+<% }) %> +
+
+ +

Rate this book

+ + +
+ +
+ +
+ +