From 84e855c3f37d19158df911d59c53684be5758ce3 Mon Sep 17 00:00:00 2001 From: hmalik88 Date: Wed, 25 Nov 2020 17:58:46 -0500 Subject: [PATCH] . --- app.js | 5 ++- controllers/follower.js | 6 ++-- controllers/tweet.js | 39 +++++++++++++++++----- controllers/user.js | 31 +++++++++++++---- migrations/202011031728-CreateUserTable.js | 6 +--- models/User.js | 6 +--- package.json | 1 + routes/index.js | 11 +++--- validators/followerValidations.js | 9 +++-- validators/userValidations.js | 7 ++-- 10 files changed, 84 insertions(+), 37 deletions(-) diff --git a/app.js b/app.js index 2abcaa1..1039f71 100644 --- a/app.js +++ b/app.js @@ -5,7 +5,10 @@ const { create } = require('lodash'); const logger = require('morgan'); const app = express(); const indexRouter = require('./routes/index'); +const cors = require('cors'); +app.disable('etag'); +app.use(cors()); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); @@ -19,7 +22,7 @@ app.use(function (req, res, next) { }) app.use(function (err, req, res, next) { - res.status(err.status || 500).send({error: err.message}); + res.status(err.status || 500).send({errors: err}); }) diff --git a/controllers/follower.js b/controllers/follower.js index aa388e2..e3a5acb 100644 --- a/controllers/follower.js +++ b/controllers/follower.js @@ -14,7 +14,8 @@ exports.create_following = async function(req, res, next) { else { const token = req.header('x-authentication-token'); const userId = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET).id; - const following = await models.Follower.create({user_id: req.params.id, follower_id: userId}); + const followed = await models.User.findOne({where: {userName: req.params.username}}); + const following = await models.Follower.create({user_id: followed.id, follower_id: userId}); res.status(200).send({following: following}); } } @@ -27,9 +28,10 @@ exports.delete_following = async function(req, res, next) { else { const token = req.header('x-authentication-token'); const userId = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET).id; + const followed = await models.User.findOne({where: {userName: req.params.username}}); const deletedFollowing = await models.Follower.destroy({ where: { - user_id: req.params.id, + user_id: followed.id, follower_id: userId } }); diff --git a/controllers/tweet.js b/controllers/tweet.js index b0f4e74..3b3a4fd 100644 --- a/controllers/tweet.js +++ b/controllers/tweet.js @@ -3,6 +3,7 @@ const { validateTweet } = require('../validators/tweetValidations'); const { isEmpty } = require('lodash'); const { validateToken } = require('../validators/userValidations'); const jwt = require('jsonwebtoken'); +const User = require('../models/User'); //we want to validate the token sent in the header // then we want to grab the user's tweets through the association we setup @@ -29,17 +30,15 @@ exports.create_tweet = async function(req, res, next) { // then we want to fetch all he tweets of the users that our user is following exports.show_timeline = async function(req, res, next) { - let errors = await validateToken({}, req); + const errors = await validateToken({}, req); if (!isEmpty(errors)) next(errors); else { const token = req.header('x-authentication-token'); const userId = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET).id; - const userTweets = await models.Tweet.findAll({where: {user_id: userId}}); const userFriends = await models.Follower.findAll({where: {follower_id: userId}}); const userIds = userFriends.map(friend => friend.user_id); const friendTweets = await models.Tweet.findAll({where: {user_id: userIds}}); - const timeline = [...userTweets, ...friendTweets]; - res.status(200).send({timeline: timeline}); + res.status(200).send({timeline: friendTweets}); } } @@ -47,12 +46,36 @@ exports.show_timeline = async function(req, res, next) { // grab all the tweets where there is a true property of isTweeth exports.show_tweeths = async function(req, res, next) { - let errors = await validateToken({}, req); + const errors = await validateToken({}, req); if (!isEmpty(errors)) next(errors); else { - const token = req.header('x-authentication-token'); - const userId = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET).id; - const userTweeths = await models.Tweet.findAll({where: {user_id: userId, isTweeth: true}}); + const username = req.params.username; + const user = await models.User.findOne({where: {userName: username}}); + const userTweeths = await models.Tweet.findAll({where: {user_id: user.id, isTweeth: true}}); res.status(200).send({tweeths: userTweeths}); } +} + +exports.show_tweets = async function(req, res, next) { + const errors = await validateToken({}, req); + if (!isEmpty(errors)) next(errors); + else { + const username = req.params.username; + const user = await models.User.findOne({where: {userName: username}}); + const userTweets = await models.Tweet.findAll({where: {user_id: user.id, isTweeth: false}}); + res.status(200).send({tweets: userTweets}); + } +} + +exports.show_likes = async function(req, res, next) { + const errors = await validateToken({}, req); + if (!isEmpty(errors)) next(errors); + else { + const username = req.params.username; + const user = await models.User.findOne({where: {userName: username}}); + const likes = await models.Like.findAll({where: {user_id: user.id}}); + const tweetIds = likes.map(like => like.tweet_id); + const likedTweets = await models.Tweet.findAll({where: {id: tweetIds}}); + res.status(200).send({likes: likedTweets}); + } } \ No newline at end of file diff --git a/controllers/user.js b/controllers/user.js index 2bc00c3..2521c83 100644 --- a/controllers/user.js +++ b/controllers/user.js @@ -1,6 +1,6 @@ const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); -const { validateSignup, validateLogin } = require('../validators/userValidations'); +const { validateSignup, validateLogin, validateToken } = require('../validators/userValidations'); const { isEmpty } = require('lodash'); const models = require('../models'); @@ -15,14 +15,12 @@ exports.signup = async function(req, res, next) { const newUser = await models.User.create({ email: req.body.email, password: generateHash(req.body.password), - firstName: req.body.firstName, - lastName: req.body.lastName, + name: req.body.name, ethAddress: req.body.ethAddress, userName: req.body.userName - }); const jwtToken = jwt.sign({id: newUser.id}, process.env.ACCESS_TOKEN_SECRET); - res.status(200).send({ token: jwtToken }); + res.status(200).send({ token: jwtToken, userName: newUser.userName }); } } @@ -32,6 +30,27 @@ exports.login = async function(req, res, next) { else { const user = await models.User.findOne({where: {email: req.body.email}}); const jwtToken = jwt.sign({id: user.id}, process.env.ACCESS_TOKEN_SECRET); - res.status(200).send({ token: jwtToken }); + res.status(200).send({ token: jwtToken, userName: user.userName }); + } +} + +exports.show_user = async function (req, res, next) { + const errors = await validateToken({}, req); + if (!isEmpty(errors)) next(errors); + else { + const token = req.header('x-authentication-token') + const userId = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET).id; + const { username } = req.params; + const userInfo = {}; + const user = await models.User.findOne({where: {userName: username}}); + userInfo['joined-date'] = user.createdAt; + userInfo['name'] = user.name; + const followers = await models.Follower.findAll({where: {user_id: user.id}}); + userInfo['followers'] = followers.length; + const following = await models.Follower.findAll({where: {follower_id: user.id}}); + userInfo['following'] = following.length; + const isFollowed = !!followers.filter(follower => follower.follower_id == userId).length; + userInfo['isFollowed'] = isFollowed; + res.status(200).send(userInfo); } } \ No newline at end of file diff --git a/migrations/202011031728-CreateUserTable.js b/migrations/202011031728-CreateUserTable.js index 44a266e..78c675e 100644 --- a/migrations/202011031728-CreateUserTable.js +++ b/migrations/202011031728-CreateUserTable.js @@ -16,11 +16,7 @@ module.exports = { allowNull: false, type: Sequelize.DATE }, - firstName: { - allowNull: false, - type: Sequelize.STRING - }, - lastName: { + name: { allowNull: false, type: Sequelize.STRING }, diff --git a/models/User.js b/models/User.js index 9e56347..bb2d55c 100644 --- a/models/User.js +++ b/models/User.js @@ -13,14 +13,10 @@ module.exports = (sequelize, DataTypes, Deferrable) => { allowNull: false, unique: true }, - firstName: { + name: { type: DataTypes.STRING, allowNull: false }, - lastName: { - type: DataTypes.STRING, - allowNull: true - }, password: { type: DataTypes.STRING, allowNull: false diff --git a/package.json b/package.json index 924c970..496422b 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "bcrypt": "^5.0.0", "chai": "^4.2.0", "chai-http": "^4.3.0", + "cors": "^2.8.5", "dotenv": "^8.2.0", "express": "^4.17.1", "http-errors": "^1.8.0", diff --git a/routes/index.js b/routes/index.js index 4b55efe..7f68b77 100644 --- a/routes/index.js +++ b/routes/index.js @@ -10,19 +10,22 @@ const follower = require('../controllers/follower'); router.post('/signup', user.signup); router.post('/login', user.login); +router.get('/users/:username', user.show_user) // follow routes -router.post('/follow/:id', follower.create_following); -router.delete('/follow/:id', follower.delete_following); +router.post('/follow/:username', follower.create_following); +router.delete('/follow/:username', follower.delete_following); // tweet routes router.post('/tweets', tweet.create_tweet); -router.get('/users/:id/timeline', tweet.show_timeline); -router.get('/users/:id/tweeths', tweet.show_tweeths); +router.get('/timeline', tweet.show_timeline); +router.get('/users/:username/tweeths', tweet.show_tweeths); +router.get('/users/:username/tweets', tweet.show_tweets); +router.get('/users/:username/likes', tweet.show_likes); // like routes diff --git a/validators/followerValidations.js b/validators/followerValidations.js index 7f4a1a2..7db1e7c 100644 --- a/validators/followerValidations.js +++ b/validators/followerValidations.js @@ -6,15 +6,18 @@ const jwt = require('jsonwebtoken'); // make sure the follower_id matches up with the id in the JWT exports.validateFollowing = async function(errors, req) { - if (req.params.id == null) { + if (req.params.username == null) { errors["status"] = 400; errors["message"] = "id params must be present." return errors; } const token = req.header('x-authentication-token'); const userId = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET).id; - const users = await models.User.findAll({where: {id: [userId, req.params.id]}}); - if (users == null || users.length !== 2) { + const followed = await models.User.findOne({where: {userName: req.params.username}}); + const follower = await models.User.findOne({where: {id: userId}}); + const users = [followed, follower]; + const invalidUsers = users.some(user => !user); + if (invalidUsers) { errors["status"] = 400; errors["message"] = "Both follower and followee must be valid users." return errors; diff --git a/validators/userValidations.js b/validators/userValidations.js index 51cf8b9..c255204 100644 --- a/validators/userValidations.js +++ b/validators/userValidations.js @@ -51,7 +51,7 @@ exports.validateSignup = async function(errors, req) { errors["messages"] = []; if (emailFound) errors["messages"].push("Email is already in use. Please login or use another email to signup."); if (userNameFound) errors["messages"].push("Username is already in use. Please use another username to signup."); - if (ethAddFound) errors["messages"].push("Ethereum address is already in use. Please use another address to signup."); + if (ethAddFound) errors["messages"].push("Ethereum address is already in use. Please use another ethereum address to signup."); } return errors; } @@ -60,7 +60,7 @@ exports.validateLogin = async function(errors, req) { const user = await models.User.findOne({where: {email: req.body.email}}); if (user == null) { errors["status"] = 400; - errors["message"] = "No such user found for this email. Please use a valid email."; + errors["message"] = "Please use a valid email."; } else { if (!bcrypt.compareSync(req.body.password, user.password)) { errors["status"] = 401; @@ -88,4 +88,5 @@ exports.validateToken = async function(errors, req) { } } return errors; -} \ No newline at end of file +} +