Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

private message listing support (partially complete)

  • Loading branch information...
commit 7d3c4323237cb7ac7d83bf0721321bb8cd74ea48 1 parent 1c0caa9
@ednapiranha ednapiranha authored
View
13 app.js
@@ -35,10 +35,19 @@ io.sockets.on('connection', function(socket) {
});
});
+var isLoggedIn = function(req, res, next) {
+ if (req.session.email) {
+ next();
+ } else {
+ err.status = 403;
+ next(new Error('not allowed!'));
+ }
+}
+
// routes
require('./routes')(client, noodle, nconf, app, io);
-require('./routes/message')(client, nconf, app, io);
-require('./routes/auth')(client, nconf, app, io);
+require('./routes/message')(client, nconf, app, io, isLoggedIn);
+require('./routes/auth')(client, nconf, app, io, isLoggedIn);
app.get('/404', function(req, res, next){
next();
View
21 lib/noodle-redis.js
@@ -6,7 +6,7 @@ var MEDIA_OBJECT_MATCHER = /<object\s.+><\/object>/i;
var MEDIA_VIDEO_MATCHER = /<video\s.+>.+<\/video>/i;
var MEDIA_AUDIO_MATCHER = /<audio\s.+>.+<\/audio>/i;
var MEDIA_IMAGE_MATCHER = /(\.jpg)|(\.jpeg)|(\.png)|(\.gif)/i;
-var PRIVATE_MESSAGE_MATCH = /private-message/i;
+var PRIVATE_MESSAGE_MATCH = /private-/i;
var PROFILE_MESSAGE_MATCH = /profile-/i;
var ME_MATCH = /^(\/me\s)/i;
var SLASH_MATCHER = /^(\/)\w?/i;
@@ -69,6 +69,21 @@ exports.setRecentMessage = function(client, req, io, callback) {
client.lpush('channelMessages:' + channel, jsonMessage);
client.ltrim('channelMessages:' + channel, 0, RECENT_MESSAGE_LIMIT);
+ // If this is a private message, add to the respective notification lists
+ if (channel.match(PRIVATE_MESSAGE_MATCH)) {
+ var channelArray = channel.split('private-')[1].split('-');
+ var userIdx = channelArray.indexOf(req.session.emailHash);
+
+ if (userIdx > -1) {
+ channelArray.splice(userIdx, 1);
+
+ if (channelArray.length === 1) {
+ client.lpush('notifications:' + channelArray, jsonMessage);
+ client.ltrim('notifications:' + channelArray, 0, RECENT_MESSAGE_LIMIT);
+ }
+ }
+ }
+
// Add if this is a media item
if (message.message.match(MEDIA_IFRAME_MATCHER) ||
message.message.match(MEDIA_OBJECT_MATCHER) ||
@@ -107,7 +122,9 @@ exports.getRecentMessages = function(client, channel, callback) {
* Returns: the notification list if successful, error otherwise
*/
exports.getRecentNotifications = function(client, req, callback) {
- scaffold.getDataByList(client, 'notifications', req.session.email, RECENT_MESSAGE_LIMIT, function(err, messageList) {
+ scaffold.getDataByList(client, 'notifications', auth.setEmailHash(req.session.email),
+ RECENT_MESSAGE_LIMIT, function(err, messageList) {
+
if (err) {
return callback(err);
}
View
3  package.json
@@ -16,7 +16,8 @@
"socket.io": "0.9.6",
"hiredis": "0.1.14",
"redis": "0.7.2",
- "nconf": "git://github.com/flatiron/nconf.git"
+ "nconf": "git://github.com/flatiron/nconf.git",
+ "rss": "*"
},
"devDependencies": {
"mocha": "1.2.2",
View
25 public/javascripts/main.js
@@ -6,7 +6,6 @@ $(function() {
var currentChannel = $('body').data('channel');
var myEmailHash = $('body').data('email-hash');
var initiatingChats = [];
- var messagesUnread = 0;
var userList = [];
var myUserList = [];
var userCount = 0;
@@ -22,7 +21,6 @@ $(function() {
var clearUnreadMessages = function() {
document.title = '#' + currentChannel;
- messagesUnread = 0;
};
var updateMedia = function(data) {
@@ -30,11 +28,11 @@ $(function() {
var message = $.trim(data.message);
// Update the media
- if(mediaIframeMatcher.exec(message) !== null ||
- mediaObjectMatcher.exec(message) !== null ||
- mediaVideoMatcher.exec(message) !== null ||
- mediaAudioMatcher.exec(message) !== null ||
- (mediaImageMatcher.exec(message) !== null &&
+ if(message.match(mediaIframeMatcher) ||
+ message.match(mediaObjectMatcher) ||
+ message.match(mediaVideoMatcher) ||
+ message.match(mediaAudioMatcher) ||
+ (message.match(mediaImageMatcher) &&
message.indexOf('class="emoti"') === -1)) {
var mediaItem = $('<li class="font' + data.font + '" data-created="' +
data.created +'"></li>');
@@ -109,8 +107,7 @@ $(function() {
if (myPost) {
clearUnreadMessages();
} else {
- messagesUnread += 1;
- document.title = '(' + messagesUnread + ') #' + $('body').data('channel');
+ document.title = ' * #' + $('body').data('channel');
}
myPost = false;
checkVersion();
@@ -119,7 +116,7 @@ $(function() {
// if the user just landed on this page, get the recent messages
$.get('/about/' + $('body').data('channel') + '/recent', function(data) {
var messages = data.messages;
- for (var i=0; i < messages.generic.length; i++) {
+ for (var i=0; i < messages.generic.length; i ++) {
updateMessage(messages.generic[i]);
}
@@ -130,6 +127,14 @@ $(function() {
keepListSane();
});
+ // if the user just landed on this page, get the recent notifications
+ $.get('/notifications/recent', function(data) {
+ var messages = data.messages;
+ for (var i=0; i < messages.generic.length; i ++) {
+ updateMessage(messages.generic[i]);
+ }
+ });
+
$('#login').click(function() {
navigator.id.getVerifiedEmail(function(assertion) {
if (assertion) {
View
12 public/stylesheets/style.css
@@ -234,7 +234,7 @@ ol li iframe, ol li audio, ol li video, ol li object {
margin: 10px;
}
-body[data-options="mediaOff"] #messages {
+body[data-options="mediaOff"] #messages, .wrapper.long #messages {
width: 1319px;
}
@@ -541,7 +541,7 @@ body.error .arrow {
#profile {
width: 979px;
}
- body[data-options="mediaOff"] #messages {
+ body[data-options="mediaOff"] #messages, .wrapper.long #messages {
width: 1005px;
}
form input {
@@ -566,7 +566,7 @@ body.error .arrow {
#media {
width: 480px;
}
- body[data-options="mediaOff"] #messages {
+ body[data-options="mediaOff"] #messages, .wrapper.long #messages {
width: 831px;
}
form input {
@@ -603,7 +603,7 @@ body.error .arrow {
#profile {
width: 625px;
}
- body[data-options="mediaOff"] #messages {
+ body[data-options="mediaOff"] #messages, .wrapper.long #messages {
width: 642px;
}
form input {
@@ -643,7 +643,7 @@ body.error .arrow {
ol li p img {
max-width: 100%;
}
- body[data-options="mediaOff"] #messages {
+ body[data-options="mediaOff"] #messages, .wrapper.long #messages {
width: 350px;
}
form input {
@@ -669,7 +669,7 @@ body.error .arrow {
.wrapper {
width: 300px;
}
- #messages, body[data-options="mediaOff"] #messages {
+ #messages, body[data-options="mediaOff"] #messages, .wrapper.long #messages {
width: 300px;
}
#profile {
View
6 routes/auth.js
@@ -4,7 +4,7 @@ var auth = require('../lib/authenticate');
var messageMaker = require('../lib/message-maker');
var noodleRedis = require('../lib/noodle-redis');
-module.exports = function(client, nconf, app, io) {
+module.exports = function(client, nconf, app, io, isLoggedIn) {
// Login
app.post('/about/:channel/login', function(req, res) {
auth.verify(req, nconf, function(error, email) {
@@ -39,11 +39,9 @@ module.exports = function(client, nconf, app, io) {
});
// Logout
- app.get("/about/:channel/logout", function(req, res) {
+ app.get("/about/:channel/logout", isLoggedIn, function(req, res) {
var channel = escape(req.params.channel);
- console.log(channel)
req.session.reset();
- console.log('got here')
res.redirect('/');
});
};
View
4 routes/index.js
@@ -28,7 +28,7 @@ module.exports = function(client, noodle, nconf, app, io) {
var privateParts = channel.split('-');
// rearrange by sort if someone tries to change the hash order
- channel = [privateParts[1], privateParts[2]].sort().join('-');
+ channel = 'private-' + [privateParts[1], privateParts[2]].sort().join('-');
if (req.session.emailHash !== privateParts[1] && req.session.emailHash !== privateParts[2]) {
res.send(403);
@@ -98,7 +98,7 @@ module.exports = function(client, noodle, nconf, app, io) {
if (req.session.email) {
emailHash = crypto.createHash('md5').update(req.session.email).digest("hex");
var userHashes = [emailHash, userHash.nickname].sort().join('-');
- formLink = userHashes;
+ formLink = 'private-' + userHashes;
if (emailHash === userHash.nickname) {
placeholder = 'Write a public message';
View
86 routes/message.js
@@ -4,8 +4,9 @@ var auth = require('../lib/authenticate');
var content = require('../lib/web-remix');
var messageMaker = require('../lib/message-maker');
var noodleRedis = require('../lib/noodle-redis');
+var RSS = require('rss');
-module.exports = function(client, nconf, app, io) {
+module.exports = function(client, nconf, app, io, isLoggedIn) {
// Get recent messages
app.get('/about/:channel/recent', function(req, res) {
var channel = escape(req.params.channel);
@@ -17,25 +18,88 @@ module.exports = function(client, nconf, app, io) {
var channelMessages = {};
channelMessages.generic = messages || {};
+ channelMessages.media = {};
- noodleRedis.getRecentMedia(client, channel, function(err, media) {
- channelMessages.media = media || {};
+ io.sockets.in(channel).emit('userlist', []);
- noodleRedis.getUserlist(client, channel, function(userErr, userList) {
- io.sockets.in(channel).emit('userlist', userList);
+ res.json({
+ 'messages': channelMessages,
+ 'connected_clients': io.sockets.clients(channel).length,
+ 'user_list': []
+ });
+ });
+ });
+
+ app.get('/notifications', function(req, res) {
+ var channel = 'notifications-' + req.session.emailHash;
+
+ auth.getUserHash(req, req.session.email, 'notifications', true, function(err, userHash) {
+ res.render('notifications', {
+ title: 'Noodle Talk Notifications',
+ channel: channel,
+ nickname: userHash.nickname,
+ avatar: userHash.avatar
+ });
+ });
+ });
+
+ // Get the recent notifications
+ app.get('/notifications/recent', isLoggedIn, function(req, res) {
+ var channel = 'notifications-' + req.session.emailHash;
+
+ noodleRedis.getRecentNotifications(client, req, function(err, messages) {
+ if (err) {
+ res.send(403);
+ }
+
+ var channelMessages = {};
- res.json({
- 'messages': channelMessages,
- 'connected_clients': io.sockets.clients(channel).length,
- 'user_list': userList
- });
+ channelMessages.generic = messages || {};
+ channelMessages.media = {};
+
+ res.json({
+ 'messages': channelMessages,
+ 'connected_clients': io.sockets.clients(channel).length,
+ 'user_list': []
+ });
+ });
+ });
+
+ // Get the private RSS feed
+ app.get('/notifications/rss/:rsskey', function(req, res) {
+ var rssKey = escape(req.params.rsskey);
+
+ noodleRedis.getRecentNotifications(client, req, function(err, messages) {
+ if (err) {
+ res.send(403);
+ }
+
+ var feed = new RSS({
+ title: 'Noodletalk Notifications',
+ description: 'Private message notifications',
+ feed_url: 'https://noodletalk.org/notifications/' + rssKey + '/rss.xml',
+ site_url: 'https://noodletalk.org',
+ image_url: 'https://noodletalk.org/logo.png',
+ author: 'Edna Piranha'
+ });
+
+ messages.forEach(function(message, counter) {
+ feed.item({
+ title: 'New message from ' + message.avatar,
+ description: message.message.slice(0, 100),
+ url: 'https://noodletalk.org/notifications',
+ date: message.created
});
});
+
+ res.header('Content-Type', 'text/rss');
+
+ res.xml(feed.xml());
});
});
// Add new message
- app.post('/about/:channel/message', function(req, res) {
+ app.post('/about/:channel/message', isLoggedIn, function(req, res) {
noodleRedis.setRecentMessage(client, req, io, function(err, message) {
try {
var channel = escape(req.params.channel);
View
9 settings.js
@@ -28,12 +28,17 @@ module.exports = function(app, configurations, express) {
duration: 24 * 60 * 60 * 1000 * 21, // 3 weeks
}));
app.use(app.router);
- app.use(function(req, res, next){
+ app.use(function(req, res, next) {
+ res.status(403);
+ res.render('403', { url: req.url, layout: 'error_layout.jade' });
+ return;
+ });
+ app.use(function(req, res, next) {
res.status(404);
res.render('404', { url: req.url, layout: 'error_layout.jade' });
return;
});
- app.use(function(err, req, res, next){
+ app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('500', { error: err, layout: 'error_layout.jade' });
});
View
1  views/index.jade
@@ -3,6 +3,7 @@
#header
a(href='/')
h1 Noodle Talk
+
if session.email
#message
form(method='post', action='/about/#{channel}/message', autocomplete='off', class='font#{session.userFont}')
View
17 views/notifications.jade
@@ -0,0 +1,17 @@
+.wrapper.long
+ block header
+ #header
+ a(href='/')
+ h1 Noodle Talk
+
+ #profile
+
+ img(src='#{avatar}')
+
+ h2= session.emailHash
+
+ #messages
+ ol
+
+ #media
+ ol
View
1  views/profile.jade
@@ -3,6 +3,7 @@
#header
a(href='/')
h1 Noodle Talk
+
if session.email
#message
form(method='post', action='/about/#{formLink}/message', autocomplete='off', class='font#{session.userFont}')
Please sign in to comment.
Something went wrong with that request. Please try again.