diff --git a/server/controllers/entryController.js b/server/controllers/entryController.js new file mode 100644 index 0000000..8bb34f4 --- /dev/null +++ b/server/controllers/entryController.js @@ -0,0 +1,36 @@ +import { query } from '../db/index'; +import validate from '../utils/validate'; + +class entryController { + /** + * Get all of a user's diary entries + * Requires auth token to be passed in authorization header + * @static + * @param {*} req - Client request object + * @param {*} res - Server response object + * @returns {object} token + * @memberof userController + */ + static getAllEntries(req, res) { + let { limit, page } = req.query; + // validate queries + limit = validate.isNumber(limit) ? limit : 20; + page = validate.isNumber(page) ? page : 0; + // get entries + query( + `SELECT entries.id, entries.title, entries.content, entries.created_on, entries.updated_on, + entries.is_favorite FROM entries INNER JOIN users ON entries.user_id=users.id WHERE users.email=$1 + LIMIT $2 OFFSET $3`, + [req.authorizedUser.email, limit, page * limit], + (err, result) => { + if (err) { + console.log(err); + return res.status(500).json({ error: { message: 'An error occurred on the server' } }); + } + return res.status(200).json({ entries: result.rows, meta: { limit, page } }); + }, + ); + } +} + +export default entryController; diff --git a/server/routes/index.js b/server/routes/index.js index 1b2b807..683a0a1 100644 --- a/server/routes/index.js +++ b/server/routes/index.js @@ -1,5 +1,7 @@ import express from 'express'; import userController from '../controllers/userController'; +import entryController from '../controllers/entryController'; +import verifyToken from '../utils/verifyToken'; import validate from '../utils/validate'; const router = express.Router(); @@ -17,4 +19,7 @@ router.post('/auth/login', validate.loginInputs, userController.loginUser); +/* GET all user entries */ +router.get('/entries', verifyToken, entryController.getAllEntries); + export default router; diff --git a/server/utils/validate.js b/server/utils/validate.js index 902994b..cd176bf 100644 --- a/server/utils/validate.js +++ b/server/utils/validate.js @@ -22,6 +22,7 @@ const validate = { .isString() .withMessage('Your password is invalid'), ], + isNumber: number => !Number.isNaN(Number(number)), }; export default validate; diff --git a/server/utils/verifyToken.js b/server/utils/verifyToken.js new file mode 100644 index 0000000..3246edd --- /dev/null +++ b/server/utils/verifyToken.js @@ -0,0 +1,24 @@ +import jwt from 'jsonwebtoken'; +import dotenv from 'dotenv'; + +dotenv.config(); + +const verifyToken = (req, res, next) => { + try { + if (!req.headers.authorization) { + return res + .status(401) + .json({ error: { message: 'Authorization failed. Please provide a token' } }); + } + const token = req.headers.authorization.split(' ')[1]; + const authorizedUser = jwt.verify(token, process.env.SECRET_KEY); + req.authorizedUser = authorizedUser; + next(); + } catch (error) { + res + .status(401) + .json({ error: { message: 'Authorization failed. Your token is invalid or expired' } }); + } +}; + +export default verifyToken; diff --git a/test/test.js b/test/test.js index ee92241..56ecbcd 100644 --- a/test/test.js +++ b/test/test.js @@ -93,7 +93,7 @@ describe('/POST /auth/login', () => { expect(res).to.have.status(200); expect(res.body).to.be.an('object'); expect(res.body).to.have.property('token'); - ({ token } = res.body.token); + token = res.body.token; done(); }); }); @@ -124,3 +124,45 @@ describe('/POST /auth/login', () => { }); }); }); + +describe('/GET entries', () => { + it('should return all user entries when passed a valid token', (done) => { + chai + .request(app) + // Set the Authorization header + .get('/api/v1/entries') + .set('Authorization', makeAuthHeader(token)) + .end((err, res) => { + expect(res).to.have.status(200); + expect(res.body).to.be.an('object'); + expect(res.body).to.have.property('entries'); + done(); + }); + }); + + it('should return 401 unauthorized error along with error object when passed an invalid or expired token', (done) => { + chai + .request(app) + .get('/api/v1/entries') + .set('Authorization', makeAuthHeader(sampleData.invalidToken)) + .end((err, res) => { + expect(res).to.have.status(401); + expect(res.body).to.be.an('object'); + expect(res.body).to.be.have.property('error'); + done(); + }); + }); + + it('should return 401 unauthorized error along with error object when passed no token', (done) => { + chai + .request(app) + .get('/api/v1/entries') + .set('Authorization', makeAuthHeader('')) + .end((err, res) => { + expect(res).to.have.status(401); + expect(res.body).to.be.an('object'); + expect(res.body).to.be.have.property('error'); + done(); + }); + }); +});