From 32a83bca6d0b9d67760761d185c3cbf198f87338 Mon Sep 17 00:00:00 2001 From: Tyler Ketron Date: Mon, 24 Jul 2017 21:33:23 -0700 Subject: [PATCH 1/7] initial commit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 299362a..82d6e93 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # project_superchat Build a realtime multi-room chat application. Make it super. + +By Tyler Ketron. From c7baa8065e25a4b0ed253a0f3fba62a853963e93 Mon Sep 17 00:00:00 2001 From: Tyler Ketron Date: Mon, 24 Jul 2017 21:38:16 -0700 Subject: [PATCH 2/7] initialized npm --- .gitignore | 1 + index.js | 0 package.json | 27 +++++++++++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 .gitignore create mode 100644 index.js create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/index.js b/index.js new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json new file mode 100644 index 0000000..e3553a6 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "project_superchat", + "version": "1.0.0", + "description": "Build a realtime multi-room chat application. Make it super.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/tketron/project_superchat.git" + }, + "author": "Tyler Ketron", + "license": "ISC", + "bugs": { + "url": "https://github.com/tketron/project_superchat/issues" + }, + "homepage": "https://github.com/tketron/project_superchat#readme", + "dependencies": { + "body-parser": "^1.17.2", + "express": "^4.15.3", + "express-handlebars": "^3.0.0", + "redis": "^2.7.1", + "socket.io": "^2.0.3", + "socket.io-client": "^2.0.3" + } +} From 7cfeeae8c4478d19bcb3d98d6ffbc841aa64dda0 Mon Sep 17 00:00:00 2001 From: Tyler Ketron Date: Wed, 26 Jul 2017 21:20:04 -0700 Subject: [PATCH 3/7] implemented basic layout --- index.js | 36 +++++++++++++++++++++ views/.DS_Store | Bin 0 -> 6148 bytes views/index.handlebars | 59 ++++++++++++++++++++++++++++++++++ views/layouts/main.handlebars | 20 ++++++++++++ 4 files changed, 115 insertions(+) create mode 100644 views/.DS_Store create mode 100644 views/index.handlebars create mode 100644 views/layouts/main.handlebars diff --git a/index.js b/index.js index e69de29..4a00970 100644 --- a/index.js +++ b/index.js @@ -0,0 +1,36 @@ +const express = require('express'); +const app = express(); +const server = require('http').createServer(app); +const io = require('socket.io')(server); + +const expressHandlebars = require('express-handlebars'); +const bodyParser = require('body-parser'); +// const { +// setShortenedLink, +// getURL, +// getAllURLs, +// getAllCounts, +// incrementCount +// } = require('./link-shortener'); + +app.engine('handlebars', expressHandlebars({ defaultLayout: 'main' })); +app.set('view engine', 'handlebars'); + +app.use( + '/socket.io', + express.static(__dirname + '/node_modules/socket.io-client/dist/') +); +app.use(express.static(__dirname + '/public')); +app.use(bodyParser.urlencoded({ extended: true })); + +app.get('/', (req, res) => { + res.render('index'); +}); + +app.post('/', (req, res) => { + res.redirect('back'); +}); + +server.listen(3000, () => { + console.log('Listening on port 3000'); +}); diff --git a/views/.DS_Store b/views/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a8ad673309ed21a4e80fb82b5dc37c0641213bbc GIT binary patch literal 6148 zcmeHKOKL(v5Uh?uglt@9IakOH1~Dh_0t$g_L?MZR?B2?AU!ajm~>bTA68GcnoumB&ih-G!+N5k6p#Yv z3QTf4_x}G(zcT-yleCipQs7@HVAJJlx!@~RZymjy_u58Z)4k@K?#6Xc7@{2$qaAbO f?f5Z@vab1>=e=-93_9~cC+cUwb&*MdzgFM}b!8Rc literal 0 HcmV?d00001 diff --git a/views/index.handlebars b/views/index.handlebars new file mode 100644 index 0000000..b9b9a1f --- /dev/null +++ b/views/index.handlebars @@ -0,0 +1,59 @@ +
+
+
+ +

SUPER CHAT

+
+
+ +
+ +
+ + + + + + + + {{#each urls as |value key|}} + + + + + + {{/each}} + +
Only Chatroom
+ {{value}} + + localhost:3000/{{key}} + {{lookup ../counts key}}
+
+ +
+
+
+ + +
+ + +
+
+ +
+
+ + + + + diff --git a/views/layouts/main.handlebars b/views/layouts/main.handlebars new file mode 100644 index 0000000..2ba948b --- /dev/null +++ b/views/layouts/main.handlebars @@ -0,0 +1,20 @@ + + + + + SUPERCHAT + + + + + + + + + + + + + {{{body}}} + + From 5a7775deaaacbeec836d99654d33ad2519b10afc Mon Sep 17 00:00:00 2001 From: Tyler Ketron Date: Sun, 30 Jul 2017 12:05:54 -0700 Subject: [PATCH 4/7] implemented getting and storing messages in redis, and displaying on the index page using handlebars --- index.js | 24 ++++++++---- message-store.js | 83 ++++++++++++++++++++++++++++++++++++++++++ views/index.handlebars | 9 ++--- 3 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 message-store.js diff --git a/index.js b/index.js index 4a00970..88be330 100644 --- a/index.js +++ b/index.js @@ -5,13 +5,7 @@ const io = require('socket.io')(server); const expressHandlebars = require('express-handlebars'); const bodyParser = require('body-parser'); -// const { -// setShortenedLink, -// getURL, -// getAllURLs, -// getAllCounts, -// incrementCount -// } = require('./link-shortener'); +const { storeMessage, getMessages } = require('./message-store'); app.engine('handlebars', expressHandlebars({ defaultLayout: 'main' })); app.set('view engine', 'handlebars'); @@ -23,11 +17,25 @@ app.use( app.use(express.static(__dirname + '/public')); app.use(bodyParser.urlencoded({ extended: true })); +const roomName = 'BASIC'; +const userName = 'Tyler'; + app.get('/', (req, res) => { - res.render('index'); + getMessages(roomName).then(values => { + Promise.all(values) + .then(messages => { + console.log(messages); + res.render('index', { messages: messages }); + }) + .catch(err => { + console.log(err); + }); + }); }); app.post('/', (req, res) => { + let messageBody = req.body.message; + storeMessage(messageBody, userName, roomName); res.redirect('back'); }); diff --git a/message-store.js b/message-store.js new file mode 100644 index 0000000..28a30aa --- /dev/null +++ b/message-store.js @@ -0,0 +1,83 @@ +const redis = require('redis'); +const redisClient = redis.createClient(); +// +// var messageID = 1; + +const storeMessage = (messageBody, authorName, roomName) => { + let messageID = Date.now(); + let messageHashName = 'message:' + messageID; + let roomListName = 'room:' + roomName; + console.log( + 'Message hash name: ' + + messageHashName + + ', Message: ' + + messageBody + + ', Author: ' + + authorName + + ', Room: ' + + roomName + ); + redisClient.hmset( + messageHashName, + 'body', + messageBody, + 'author', + authorName, + 'room', + roomName + ); + redisClient.lpush(roomListName, messageHashName); + // messageId += 1; +}; + +const getMessageIDs = roomName => { + let roomListName = 'room:' + roomName; + return new Promise((resolve, reject) => { + redisClient.lrange(roomListName, 0, 20, (err, messageIDs) => { + if (err) { + reject(err); + } else { + // console.log(messageIDs); + resolve(messageIDs); + } + }); + }); +}; + +const getMessageByID = messageID => { + return new Promise((resolve, reject) => { + redisClient.hgetall(messageID, (err, messageObject) => { + if (err) { + reject(err); + } else { + // console.log(messageObject); + resolve(messageObject); + } + }); + }); +}; + +const getMessages = roomName => { + //array of promises containing message bodies + return new Promise((resolve, reject) => { + var messages = []; + getMessageIDs(roomName) + .then(messageIDsList => { + messageIDsList.forEach(messageID => { + var p = getMessageByID(messageID); + messages.push(p); + }); + // console.log(messages); + resolve(messages); + }) + .catch(error => { + // console.error(error); + reject(error); + }); + }); +}; + +module.exports = { + storeMessage, + getMessages +}; diff --git a/views/index.handlebars b/views/index.handlebars index b9b9a1f..15abfc0 100644 --- a/views/index.handlebars +++ b/views/index.handlebars @@ -16,15 +16,12 @@ - {{#each urls as |value key|}} + {{#each messages}} - {{value}} + {{this.author}}: + {{this.body}} - - localhost:3000/{{key}} - - {{lookup ../counts key}} {{/each}} From a781e1923c88da6b9448c9b4748a781991f8a492 Mon Sep 17 00:00:00 2001 From: Tyler Ketron Date: Mon, 31 Jul 2017 20:10:42 -0700 Subject: [PATCH 5/7] implemented web socket connection to update messages in real time --- helpers/handlebars-helpers.js | 15 +++++++++++++++ index.js | 13 +++++++++++-- views/index.handlebars | 22 +++++++++------------- 3 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 helpers/handlebars-helpers.js diff --git a/helpers/handlebars-helpers.js b/helpers/handlebars-helpers.js new file mode 100644 index 0000000..1c59158 --- /dev/null +++ b/helpers/handlebars-helpers.js @@ -0,0 +1,15 @@ +module.exports = { + chatTable: messages => { + var str = ''; + messages.forEach(message => { + str += + '' + + message.author + + ': ' + + message.body + + ''; + }); + + return str; + } +}; diff --git a/index.js b/index.js index 88be330..dd7d941 100644 --- a/index.js +++ b/index.js @@ -4,10 +4,14 @@ const server = require('http').createServer(app); const io = require('socket.io')(server); const expressHandlebars = require('express-handlebars'); +const hbsHelpers = require('./helpers/handlebars-helpers'); const bodyParser = require('body-parser'); const { storeMessage, getMessages } = require('./message-store'); -app.engine('handlebars', expressHandlebars({ defaultLayout: 'main' })); +app.engine( + 'handlebars', + expressHandlebars({ defaultLayout: 'main', helpers: hbsHelpers }) +); app.set('view engine', 'handlebars'); app.use( @@ -18,7 +22,7 @@ app.use(express.static(__dirname + '/public')); app.use(bodyParser.urlencoded({ extended: true })); const roomName = 'BASIC'; -const userName = 'Tyler'; +const userName = 'Anonymous'; app.get('/', (req, res) => { getMessages(roomName).then(values => { @@ -36,6 +40,11 @@ app.get('/', (req, res) => { app.post('/', (req, res) => { let messageBody = req.body.message; storeMessage(messageBody, userName, roomName); + io.sockets.emit('new message', { + body: messageBody, + author: userName, + room: roomName + }); res.redirect('back'); }); diff --git a/views/index.handlebars b/views/index.handlebars index 15abfc0..6bddc9b 100644 --- a/views/index.handlebars +++ b/views/index.handlebars @@ -15,15 +15,8 @@ Only Chatroom - - {{#each messages}} - - - {{this.author}}: - {{this.body}} - - - {{/each}} + + {{{chatTable messages}}} @@ -48,9 +41,12 @@ From 2ced3dec7fdaf619dcb94e36222d86924c663d93 Mon Sep 17 00:00:00 2001 From: Tyler Ketron Date: Mon, 31 Jul 2017 21:37:22 -0700 Subject: [PATCH 6/7] added login info and storing username as a cookie --- index.js | 50 +++++++++++++++++++++++++++++++----------- package.json | 1 + views/index.handlebars | 17 ++++++++++---- views/login.handlebars | 21 ++++++++++++++++++ 4 files changed, 72 insertions(+), 17 deletions(-) create mode 100644 views/login.handlebars diff --git a/index.js b/index.js index dd7d941..c9c3b3b 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ const io = require('socket.io')(server); const expressHandlebars = require('express-handlebars'); const hbsHelpers = require('./helpers/handlebars-helpers'); const bodyParser = require('body-parser'); +const cookieParser = require('cookie-parser'); const { storeMessage, getMessages } = require('./message-store'); app.engine( @@ -20,29 +21,52 @@ app.use( ); app.use(express.static(__dirname + '/public')); app.use(bodyParser.urlencoded({ extended: true })); +app.use(cookieParser()); const roomName = 'BASIC'; -const userName = 'Anonymous'; app.get('/', (req, res) => { - getMessages(roomName).then(values => { - Promise.all(values) - .then(messages => { - console.log(messages); - res.render('index', { messages: messages }); - }) - .catch(err => { - console.log(err); - }); - }); + if (req.cookies.username) { + getMessages(roomName).then(values => { + Promise.all(values) + .then(messages => { + console.log(messages); + res.render('index', { + messages: messages, + username: req.cookies.username + }); + }) + .catch(err => { + console.log(err); + }); + }); + } else { + res.redirect('/login'); + } +}); + +app.get('/login', (req, res) => { + res.render('login'); +}); + +app.post('/login', (req, res) => { + let username = req.body.username; + res.cookie('username', username); + res.redirect('/'); +}); + +app.get('/logout', (req, res) => { + res.clearCookie('username'); + res.redirect('/'); }); app.post('/', (req, res) => { let messageBody = req.body.message; - storeMessage(messageBody, userName, roomName); + let username = req.cookies.username; + storeMessage(messageBody, username, roomName); io.sockets.emit('new message', { body: messageBody, - author: userName, + author: username, room: roomName }); res.redirect('back'); diff --git a/package.json b/package.json index e3553a6..389b2d5 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "homepage": "https://github.com/tketron/project_superchat#readme", "dependencies": { "body-parser": "^1.17.2", + "cookie-parser": "^1.4.3", "express": "^4.15.3", "express-handlebars": "^3.0.0", "redis": "^2.7.1", diff --git a/views/index.handlebars b/views/index.handlebars index 6bddc9b..2d9b2b3 100644 --- a/views/index.handlebars +++ b/views/index.handlebars @@ -1,11 +1,20 @@ -
-
-
+
+ +
diff --git a/views/login.handlebars b/views/login.handlebars new file mode 100644 index 0000000..44410d8 --- /dev/null +++ b/views/login.handlebars @@ -0,0 +1,21 @@ +
+
+
+ +

SUPER CHAT

+
+
+ +
+ +
+
+
+ + +
+ + +
+
+
From a60a1b18635f565d71a9fc224cc1af101a17feef Mon Sep 17 00:00:00 2001 From: Tyler Ketron Date: Sat, 5 Aug 2017 16:52:24 -0700 Subject: [PATCH 7/7] allowed for creation of new rooms --- index.js | 63 ++++++++++++++++++++++++++---------- message-store.js | 23 +++++++++++--- views/index.handlebars | 46 ++++++++++++++++++++------- views/rooms.handlebars | 72 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 32 deletions(-) create mode 100644 views/rooms.handlebars diff --git a/index.js b/index.js index c9c3b3b..c7098f7 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,12 @@ const expressHandlebars = require('express-handlebars'); const hbsHelpers = require('./helpers/handlebars-helpers'); const bodyParser = require('body-parser'); const cookieParser = require('cookie-parser'); -const { storeMessage, getMessages } = require('./message-store'); +const { + storeMessage, + getMessages, + addRoom, + getRoomNames +} = require('./message-store'); app.engine( 'handlebars', @@ -27,11 +32,30 @@ const roomName = 'BASIC'; app.get('/', (req, res) => { if (req.cookies.username) { + res.redirect('/rooms'); + } else { + res.redirect('/login'); + } +}); + +app.get('/rooms', (req, res) => { + getRoomNames() + .then(rooms => { + res.render('rooms', { rooms: rooms, username: req.cookies.username }); + }) + .catch(err => console.log(err)); +}); + +app.get('/rooms/:room', (req, res) => { + let roomName = req.params.room; + getRoomNames().then(rooms => { getMessages(roomName).then(values => { Promise.all(values) .then(messages => { console.log(messages); res.render('index', { + rooms: rooms, + roomName: roomName, messages: messages, username: req.cookies.username }); @@ -40,9 +64,26 @@ app.get('/', (req, res) => { console.log(err); }); }); - } else { - res.redirect('/login'); - } + }); +}); + +app.post('/rooms', (req, res) => { + let newRoomName = req.body.roomName; + addRoom(newRoomName); + res.redirect('back'); +}); + +app.post('/rooms/:room', (req, res) => { + let messageBody = req.body.message; + let username = req.cookies.username; + let roomName = req.params.room; + storeMessage(messageBody, username, roomName); + io.sockets.emit('new message', { + body: messageBody, + author: username, + room: roomName + }); + res.redirect('back'); }); app.get('/login', (req, res) => { @@ -52,7 +93,7 @@ app.get('/login', (req, res) => { app.post('/login', (req, res) => { let username = req.body.username; res.cookie('username', username); - res.redirect('/'); + res.redirect('/rooms'); }); app.get('/logout', (req, res) => { @@ -60,18 +101,6 @@ app.get('/logout', (req, res) => { res.redirect('/'); }); -app.post('/', (req, res) => { - let messageBody = req.body.message; - let username = req.cookies.username; - storeMessage(messageBody, username, roomName); - io.sockets.emit('new message', { - body: messageBody, - author: username, - room: roomName - }); - res.redirect('back'); -}); - server.listen(3000, () => { console.log('Listening on port 3000'); }); diff --git a/message-store.js b/message-store.js index 28a30aa..3107f93 100644 --- a/message-store.js +++ b/message-store.js @@ -1,7 +1,5 @@ const redis = require('redis'); const redisClient = redis.createClient(); -// -// var messageID = 1; const storeMessage = (messageBody, authorName, roomName) => { let messageID = Date.now(); @@ -27,7 +25,6 @@ const storeMessage = (messageBody, authorName, roomName) => { roomName ); redisClient.lpush(roomListName, messageHashName); - // messageId += 1; }; const getMessageIDs = roomName => { @@ -77,7 +74,25 @@ const getMessages = roomName => { }); }; +const addRoom = roomName => { + redisClient.sadd('rooms', roomName); +}; + +const getRoomNames = () => { + return new Promise((resolve, reject) => { + redisClient.smembers('rooms', (err, roomNames) => { + if (err) { + reject(err); + } else { + resolve(roomNames); + } + }); + }); +}; + module.exports = { storeMessage, - getMessages + getMessages, + addRoom, + getRoomNames }; diff --git a/views/index.handlebars b/views/index.handlebars index 2d9b2b3..3442980 100644 --- a/views/index.handlebars +++ b/views/index.handlebars @@ -17,21 +17,45 @@
-
+
+ + + + + + + + + + + {{#each rooms}} + + + + {{/each}} + +
Chat Rooms
+ Create New Room +
+ {{this}} +
+
+ +
- + - + {{{chatTable messages}}}
Only Chatroom{{roomName}}
-
+
@@ -51,11 +75,11 @@ var socket = io.connect('http://localhost:3000'); socket.on('new message', function(message) { - var $newMessage = $('' + - message.author + - ': ' + - message.body + - '') - $('#chat-body').prepend($newMessage); - }); + var $newMessage = $('' + + message.author + + ': ' + + message.body + + ''); + $('#'+message.room).prepend($newMessage); + }); diff --git a/views/rooms.handlebars b/views/rooms.handlebars new file mode 100644 index 0000000..bd33e87 --- /dev/null +++ b/views/rooms.handlebars @@ -0,0 +1,72 @@ +
+ + +
+
+ +
+ + + + + + + + + + + {{#each rooms}} + + + + {{/each}} + +
Chat Rooms
+ Create New Room +
+ {{this}} +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+ + +
+ +