diff --git a/controllers/auth.js b/controllers/auth.js index 422f260..430d216 100644 --- a/controllers/auth.js +++ b/controllers/auth.js @@ -1,23 +1,43 @@ var express = require('express'); +var bodyParser = require('body-parser'); // added +var mysql = require('promise-mysql'); // +var parse_middle = bodyParser.urlencoded({extended:false}); + module.exports = function(myReddit) { var authController = express.Router(); - + authController.get('/login', function(request, response) { - response.send("TO BE IMPLEMENTED"); + response.render("login-form"); // CHECK }); - - authController.post('/login', function(request, response) { - response.send("TO BE IMPLEMENTED"); + + authController.post('/login', parse_middle, function(req, res) { + var username = req.body.username; + var password = req.body.password; + + myReddit.checkUserLogin(username, password) + .then(user => { + return myReddit.createUserSession(user.id); + }) + .then(token => {console.log("here is the token : " + token); + res.cookie("SESSION", token);}) + .then(() => res.redirect(302, '/')) + .catch( e =>{ + res.status(401).send(e.message); + }) + }); - + authController.get('/signup', function(request, response) { - response.send("TO BE IMPLEMENTED"); + response.render("signup-form"); // CHECK }); - - authController.post('/signup', function(request, response) { - response.send("TO BE IMPLEMENTED"); + + authController.post('/signup', parse_middle, function(req,res){ + myReddit.createUser({ + username : req.body.username, + password : req.body.password + }).then(res.redirect(302, '/auth/login')); // CHECK }); - + return authController; -} \ No newline at end of file +} diff --git a/cookies.js b/cookies.js new file mode 100644 index 0000000..8337712 --- /dev/null +++ b/cookies.js @@ -0,0 +1 @@ +// diff --git a/index.js b/index.js index 048df31..a4db61d 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,25 @@ var express = require('express'); +// > npm install --save express var mysql = require('promise-mysql'); +// > npm install --save promise-mysql +// ++ > npm install --save bcrypt-as-promised +// ++ > npm install --save pug + +// Load express and create a new web server +// Load all the Express middlewares we will use and adds them to the pipeline with app.use +// Loads the RedditAPI, created a database connection and sets up the API +// Delegates anything under /static to the static middleware +// Delegates anything under /auth to a custom Express Router +// Sets up a few other request handlers for the homepage, subreddits, creating posts and voting. These functionalities could be further split up in their own modules +// Finally, makes the web server listen on process.env.PORT, which is set to 8080 on Cloud9. // Express middleware var bodyParser = require('body-parser'); // reads request bodies from POST requests +// > npm install --save body-parser var cookieParser = require('cookie-parser'); // parses cookie from Cookie request header into an object +// > npm install --save cookie-parser var morgan = require('morgan'); // logs every request on the console +// > npm install --save morgan var checkLoginToken = require('./lib/check-login-token.js'); // checks if cookie has a SESSION token and sets request.user var onlyLoggedIn = require('./lib/only-logged-in.js'); // only allows requests from logged in users @@ -18,6 +33,7 @@ var authController = require('./controllers/auth.js'); var RedditAPI = require('./lib/reddit.js'); var connection = mysql.createPool({ user: 'root', + password : 'root', database: 'reddit' }); var myReddit = new RedditAPI(connection); @@ -55,7 +71,7 @@ This custom middleware checks in the cookies if there is a SESSION token and val NOTE: This middleware is currently commented out! Uncomment it once you've implemented the RedditAPI method `getUserFromSession` */ -// app.use(checkLoginToken(myReddit)); +app.use(checkLoginToken(myReddit)); @@ -111,13 +127,26 @@ app.get('/subreddits', function(request, response) { 1. Get all subreddits with RedditAPI 2. Render some HTML that lists all the subreddits */ - + response.send("TO BE IMPLEMENTED"); }); // Subreddit homepage, similar to the regular home page but filtered by sub. app.get('/r/:subreddit', function(request, response) { - response.send("TO BE IMPLEMENTED"); + return myReddit.getSubredditByName(request.params.subreddit) + .then(subreddit => { + console.log(subreddit.subreddit_id); + if (!subreddit) { + throw new Error('404'); + } else { + return myReddit.getAllPosts(subreddit.subreddit_id); + } + }).then(function(posts) { + response.render('homepage', {posts: posts}); + }) + .catch(function(error) { + response.render('error', {error: error}); + }) }); // Sorted home page diff --git a/lib/reddit.js b/lib/reddit.js index 17ecb73..c8e37ee 100644 --- a/lib/reddit.js +++ b/lib/reddit.js @@ -83,7 +83,7 @@ class RedditAPI { }); } - getAllPosts() { + getAllPosts(subredditId) { /* strings delimited with ` are an ES2015 feature called "template strings". they are more powerful than what we are using them for here. one feature of @@ -93,41 +93,45 @@ class RedditAPI { therefore template strings make it very easy to write SQL queries that span multiple lines without having to manually split the string line by line. */ + var subreddit_string = ''; + if (subredditId){ + subreddit_string += '\n WHERE p.subredditId = 15 \n'; + } - return this.conn.query( - ` - SELECT - p.id AS posts_id, - p.title AS posts_title, - p.url AS posts_url, - p.createdAt AS posts_createdAt, - p.updatedAt AS posts_updatedAt, - - u.id AS users_id, - u.username AS users_username, - u.createdAt AS users_createdAt, - u.updatedAt AS users_updatedAt, - - s.id AS subreddits_id, - s.name AS subreddits_name, - s.description AS subreddits_description, - s.createdAt AS subreddits_createdAt, - s.updatedAt AS subreddits_updatedAt, - - COALESCE(SUM(v.voteDirection), 0) AS voteScore, - SUM(IF(v.voteDirection = 1, 1, 0)) AS numUpvotes, - SUM(IF(v.voteDirection = -1, 1, 0)) AS numDownvotes - - FROM posts p - JOIN users u ON p.userId = u.id - JOIN subreddits s ON p.subredditId = s.id - LEFT JOIN votes v ON p.id = v.postId - - GROUP BY p.id - ORDER BY p.createdAt DESC - LIMIT 25` - ) + var query1 = `SELECT + p.id AS posts_id, + p.title AS posts_title, + p.url AS posts_url, + p.createdAt AS posts_createdAt, + p.updatedAt AS posts_updatedAt, + + u.id AS users_id, + u.username AS users_username, + u.createdAt AS users_createdAt, + u.updatedAt AS users_updatedAt, + + s.id AS subreddits_id, + s.name AS subreddits_name, + s.description AS subreddits_description, + s.createdAt AS subreddits_createdAt, + s.updatedAt AS subreddits_updatedAt, + + COALESCE(SUM(v.voteDirection), 0) AS voteScore, + SUM(IF(v.voteDirection = 1, 1, 0)) AS numUpvotes, + SUM(IF(v.voteDirection = -1, 1, 0)) AS numDownvotes + + FROM posts p + JOIN users u ON p.userId = u.id + JOIN subreddits s ON p.subredditId = s.id + LEFT JOIN votes v ON p.id = v.postId `; + + var query2 = `GROUP BY p.id + ORDER BY p.createdAt DESC + LIMIT 25;` + + return this.conn.query(query1 + subreddit_string + query2) // HERE .then(function(posts) { + console.log(posts); return posts.map(transformPost) }); } @@ -141,28 +145,28 @@ class RedditAPI { p.title AS posts_title, p.url AS posts_url, p.createdAt AS posts_createdAt, - p.updatedAt AS posts_updatedAt, - + p.updatedAt AS posts_updatedAt, + u.id AS users_id, u.username AS users_username, u.createdAt AS users_createdAt, u.updatedAt AS users_updatedAt, - + s.id AS subreddits_id, s.name AS subreddits_name, s.description AS subreddits_description, s.createdAt AS subreddits_createdAt, s.updatedAt AS subreddits_updatedAt, - + COALESCE(SUM(v.voteDirection), 0) AS voteScore, SUM(IF(v.voteDirection = 1, 1, 0)) AS numUpvotes, SUM(IF(v.voteDirection = -1, 1, 0)) AS numDownvotes - + FROM posts p JOIN users u ON p.userId = u.id JOIN subreddits s ON p.subredditId = s.id LEFT JOIN votes v ON p.id = v.postId - + WHERE p.id = ?`, [postId] ) @@ -241,13 +245,13 @@ class RedditAPI { c.text as comments_text, c.createdAt as comments_createdAt, c.updatedAt as comments_updatedAt, - + u.id as users_id, u.username as users_username - + FROM comments c JOIN users u ON c.userId = u.id - + WHERE c.postId = ? ORDER BY c.createdAt DESC LIMIT 25`, @@ -269,9 +273,51 @@ class RedditAPI { }); }); } - + getSubredditByName(name){ // self introduced API + return this.conn.query(` + SELECT + subreddits.id as subreddit_id + FROM subreddits + WHERE subreddits.name = ?; + `, + [name] + ).then(subreddit => {return subreddit[0]}); + } checkUserLogin(username, password) { - return Promise.reject(new Error("TODO: You have to implement the RedditAPI.checkUserLogin function.")) + // if(username.length !=7){ + // return Promise.reject(new Error('not 7')); + // } + var user = {}; + var er = "username or password incorrect"; + return this.conn.query(` + SELECT + users.id as id, + users.username as username, + users.password as password + + FROM users + + WHERE users.username = ?`, + [username] + ) + .then(myTable => { + if (myTable.length == 0) { + throw new Error('404'); + } else { + user = myTable[0]; + return user; + } + }) + .then(u => bcrypt.compare(password, u.password)) + .then(correct => { + if(correct){ + return {id:user.id,username:user.username} + } + else{ + throw new Error(er); + //return Promise.reject(new Error("voteDirection must be one of -1, 0, 1")); + } + }); /* Here are the steps you should follow: @@ -286,8 +332,22 @@ class RedditAPI { } createUserSession(userId) { - return Promise.reject(new Error("TODO: You have to implement the RedditAPI.createUserSession function.")) + + // return Promise.reject(new Error("TODO: You have to implement the RedditAPI.createUserSession function.")) + + var the_token; + + return bcrypt.genSalt(10).then(token => { + the_token = token; + return token; + }).then(token => { + this.conn.query(` + INSERT INTO sessions (userId, token) VALUES (?,?)` + , + [userId, token]); + return the_token; + }); /* Here are the steps you should follow: @@ -297,9 +357,39 @@ class RedditAPI { */ } + // createUserSession(userId) { + // // return Promise.reject(new Error("TODO: You have to implement the RedditAPI.createUserSession function.")) + // var resToken = ""; + // return bcrypt.genSalt(10) + // .then(data2 =>{ + // var token = data2; + // //console.log("The Token:", token," the user id:", userId.id) + // resToken = token; + // return token; + // + // }) + // .then(token => this.conn.query(`INSERT INTO sessions (userId,token) VALUES (?,?)`,[userId.id,token])) + // .then(result => { + // console.log("query result", result) + // console.log(resToken, "the result token") + // return resToken; + // }) + // } + getUserFromSession(sessionId) { - return Promise.reject(new Error("TODO: You have to implement the RedditAPI.getUserFromSession function.")); + return this.conn.query(` + SELECT + u.id AS id, + u.username AS username, + u.createdAt AS createdAt, + u.updatedAt AS updatedAt + FROM users u join sessions s + ON u.id = s.userId + WHERE s.token = ?`, [sessionId]) + .then(result => { + return result[0]; + }); } } -module.exports = RedditAPI; \ No newline at end of file +module.exports = RedditAPI; diff --git a/package.json b/package.json index d0de764..f2c8752 100644 --- a/package.json +++ b/package.json @@ -14,12 +14,12 @@ "dependencies": { "bcrypt": "^1.0.2", "bcrypt-as-promised": "^1.1.0", - "body-parser": "^1.15.2", + "body-parser": "^1.17.2", "cookie-parser": "^1.4.3", - "express": "^4.14.0", - "morgan": "^1.7.0", + "express": "^4.15.3", + "morgan": "^1.8.2", "mysql": "^2.13.0", - "promise-mysql": "^3.0.1", - "pug": "^2.0.0-beta6" + "promise-mysql": "^3.0.2", + "pug": "^2.0.0-rc.2" } } diff --git a/views/layout.pug b/views/layout.pug index 25837cd..976a31b 100644 --- a/views/layout.pug +++ b/views/layout.pug @@ -17,4 +17,4 @@ html a(href="/auth/login") Login main block content - footer © 2017 blah \ No newline at end of file + footer © 2017 reddit.ja diff --git a/views/login-form.pug b/views/login-form.pug new file mode 100644 index 0000000..735a471 --- /dev/null +++ b/views/login-form.pug @@ -0,0 +1,17 @@ +//-