From 3775c8e50a3943d55272f6f4d6e4350127c5b483 Mon Sep 17 00:00:00 2001 From: Baris Soner Usakli Date: Mon, 2 Dec 2013 19:40:11 -0500 Subject: [PATCH] tons more changes --- src/admin/categories.js | 6 +- src/database/redis.js | 57 +++++++++- src/groups.js | 89 ++++++++-------- src/login.js | 88 +++++++++------ src/user.js | 230 ++++++++++++++++++++++------------------ 5 files changed, 287 insertions(+), 183 deletions(-) diff --git a/src/admin/categories.js b/src/admin/categories.js index 494a767e9c..333a22cf70 100644 --- a/src/admin/categories.js +++ b/src/admin/categories.js @@ -1,4 +1,4 @@ -var RDB = require('./../redis'), +var db = require('./../database'), utils = require('./../../public/src/utils'), categories = require('./../categories'); @@ -11,12 +11,12 @@ var RDB = require('./../redis'), var category = modified[cid]; for (var key in category) { - RDB.hset('category:' + cid, key, category[key]); + db.setObjectField('category:' + cid, key, category[key]); if (key == 'name') { // reset slugs if name is updated var slug = cid + '/' + utils.slugify(category[key]); - RDB.hset('category:' + cid, 'slug', slug); + db.setObjectField('category:' + cid, 'slug', slug); } } diff --git a/src/database/redis.js b/src/database/redis.js index 0f7fa840c4..9492470e0c 100644 --- a/src/database/redis.js +++ b/src/database/redis.js @@ -68,13 +68,26 @@ }); } + // key + + module.exists = function(key, callback) { + redisClient.exists(key, function(err, exists) { + callback(err, exists === 1); + }); + } + + module.delete = function(key, callback) { + redisClient.del(key, callback); + } + + //hashes module.setObject = function(key, data, callback) { redisClient.hmset(key, data, callback); } - module.setObjectField = function(key, field, callback) { - redisClient.hset(key, field, callback) + module.setObjectField = function(key, field, value, callback) { + redisClient.hset(key, field, value, callback) } module.getObject = function(key, callback) { @@ -107,6 +120,16 @@ }); } + module.getObjectValues = function(key, callback) { + redisClient.hvals(key, callback); + } + + module.isObjectField = function(key, field, callback) { + redisClient.hexists(key, field, function(err, exists) { + callback(err, exists === 1); + }); + } + module.deleteObjectField = function(key, field, callback) { redisClient.hdel(key, field, callback); } @@ -119,6 +142,9 @@ redisClient.hincrby(key, field, value, callback); } + + // sets + module.setAdd = function(key, value, callback) { redisClient.sadd(key, value, callback); } @@ -135,6 +161,12 @@ redisClient.smembers(key, callback); } + module.setCount = function(key, callback) { + redisClient.scard(key, callback); + } + + // sorted sets + module.sortedSetAdd = function(key, score, value, callback) { redisClient.zadd(key, score, value, callback); } @@ -143,9 +175,30 @@ redisClient.zrem(key, value, callback); } + module.getSortedSetRange = function(key, start, stop, callback) { + redisClient.zrange(set, start, stop, callback); + } + + module.getSortedSetRevRange = function(key, start, stop, callback) { + redisClient.zrevrange(set, start, stop, callback); + } + + module.sortedSetCount = function(key, min, max, callback) { + redisClient.zcount(key, min, max, callback); + } + // lists + module.listPrepend = function(key, value, callback) { + redisClient.lpush(key, value, callback); + } + module.listAppend = function(key, value, callback) { + redisClient.rpush(key, value, callback); + } + module.getListRange = function(key, start, stop, callback) { + redisClient.lrange(key, start, stop, callback); + } }(exports)); diff --git a/src/groups.js b/src/groups.js index 058b8fdd08..98faf0bcbb 100644 --- a/src/groups.js +++ b/src/groups.js @@ -2,11 +2,11 @@ "use strict"; var async = require('async'), - User = require('./user'), - RDB = RDB || require('./redis'); + user = require('./user'), + db = require('./database'); Groups.list = function(options, callback) { - RDB.hvals('group:gid', function (err, gids) { + db.getObjectValues('group:gid', function (err, gids) { if (gids.length > 0) { async.map(gids, function (gid, next) { Groups.get(gid, { @@ -31,17 +31,17 @@ Groups.get = function(gid, options, callback) { async.parallel({ base: function (next) { - RDB.hgetall('gid:' + gid, next); + db.getObject('gid:' + gid, next); }, users: function (next) { - RDB.smembers('gid:' + gid + ':members', function (err, uids) { + db.getSetMembers('gid:' + gid + ':members', function (err, uids) { if (options.expand) { if (err) { return next(err); } async.map(uids, function (uid, next) { - User.getUserData(uid, next); + user.getUserData(uid, next); }, function (err, users) { next(err, users); }); @@ -75,19 +75,19 @@ }; Groups.isDeleted = function(gid, callback) { - RDB.hget('gid:' + gid, 'deleted', function(err, deleted) { + db.getObjectField('gid:' + gid, 'deleted', function(err, deleted) { callback(err, deleted === '1'); }); }; Groups.getGidFromName = function(name, callback) { - RDB.hget('group:gid', name, callback); + db.getObjectField('group:gid', name, callback); }; Groups.isMember = function(uid, gid, callback) { Groups.isDeleted(gid, function(err, deleted) { if (!deleted) { - RDB.sismember('gid:' + gid + ':members', uid, callback); + db.isSetMember('gid:' + gid + ':members', uid, callback); } else { callback(err, false); } @@ -107,7 +107,7 @@ }; Groups.isEmpty = function(gid, callback) { - RDB.scard('gid:' + gid + ':members', function(err, numMembers) { + db.setCount('gid:' + gid + ':members', function(err, numMembers) { callback(err, numMembers === 0); }); }; @@ -125,7 +125,7 @@ Groups.exists = function(name, callback) { async.parallel({ exists: function(next) { - RDB.hexists('group:gid', name, next); + db.isObjectField('group:gid', name, next); }, deleted: function(next) { Groups.getGidFromName(name, function(err, gid) { @@ -144,19 +144,14 @@ Groups.exists(name, function (err, exists) { if (!exists) { - RDB.incr('next_gid', function (err, gid) { - RDB.multi() - .hset('group:gid', name, gid) - .hmset('gid:' + gid, { - gid: gid, - name: name, - description: description, - deleted: '0', - hidden: '0' - }) - .exec(function (err) { + db.incrObjectField('global', 'nextGid', function (err, gid) { + db.setObjectField('group:gid', name, gid, function(err) { + db.setObject('gid:' + gid, {}, function(err) { + Groups.get(gid, {}, callback); + }); + }); }); } else { callback(new Error('group-exists')); @@ -171,22 +166,24 @@ }; Groups.update = function(gid, values, callback) { - RDB.exists('gid:' + gid, function (err, exists) { + db.exists('gid:' + gid, function (err, exists) { console.log('exists?', gid, exists, values); if (!err && exists) { - RDB.hmset('gid:' + gid, values, callback); + db.setObject('gid:' + gid, values, callback); } else { - if (callback) callback(new Error('gid-not-found')); + if (callback) { + callback(new Error('gid-not-found')); + } } }); }; Groups.destroy = function(gid, callback) { - RDB.hset('gid:' + gid, 'deleted', '1', callback); + db.setObjectField('gid:' + gid, 'deleted', '1', callback); }; Groups.join = function(gid, uid, callback) { - RDB.sadd('gid:' + gid + ':members', uid, callback); + db.setAdd('gid:' + gid + ':members', uid, callback); }; Groups.joinByGroupName = function(groupName, uid, callback) { @@ -210,7 +207,7 @@ }; Groups.leave = function(gid, uid, callback) { - RDB.srem('gid:' + gid + ':members', uid, callback); + db.setRemove('gid:' + gid + ':members', uid, callback); }; Groups.leaveByGroupName = function(groupName, uid, callback) { @@ -225,30 +222,36 @@ Groups.prune = function(callback) { // Actually deletes groups (with the deleted flag) from the redis database - RDB.hvals('group:gid', function (err, gids) { - var multi = RDB.multi(), - groupsDeleted = 0; + db.getObjectValues('group:gid', function (err, gids) { + var groupsDeleted = 0; async.each(gids, function(gid, next) { Groups.get(gid, {}, function(err, groupObj) { - if (!err && groupObj.deleted === '1') { - multi.hdel('group:gid', groupObj.name); - multi.del('gid:' + gid); - groupsDeleted++; + if(err) { + return next(err); } - next(null); + if (groupObj.deleted === '1') { + + db.deleteObjectField('group:gid', groupObj.name, function(err) { + db.delete('gid:' + gid, function(err) { + groupsDeleted++; + next(null); + }); + }); + } else { + next(null); + } }); }, function(err) { - multi.exec(function(err) { - if (!err && process.env.NODE_ENV === 'development') { - winston.info('[groups.prune] Pruned ' + groupsDeleted + ' deleted groups from Redis'); - } - callback(err); - }); + if (!err && process.env.NODE_ENV === 'development') { + winston.info('[groups.prune] Pruned ' + groupsDeleted + ' deleted groups from Redis'); + } + + callback(err); }); }); }; - + }(module.exports)); diff --git a/src/login.js b/src/login.js index 51f3ed5472..d63355ad32 100644 --- a/src/login.js +++ b/src/login.js @@ -58,7 +58,11 @@ var user = require('./user.js'), } Login.loginViaTwitter = function(twid, handle, photos, callback) { - user.getUidByTwitterId(twid, function(uid) { + user.getUidByTwitterId(twid, function(err, uid) { + if(err) { + return callback(err); + } + if (uid !== null) { // Existing User callback(null, { @@ -67,32 +71,36 @@ var user = require('./user.js'), } else { // New User user.create(handle, undefined, undefined, function(err, uid) { - if (err !== null) { - callback(err); - } else { - // Save twitter-specific information to the user - user.setUserField(uid, 'twid', twid); - RDB.hset('twid:uid', twid, uid); - - // Save their photo, if present - if (photos && photos.length > 0) { - var photoUrl = photos[0].value; - photoUrl = path.dirname(photoUrl) + '/' + path.basename(photoUrl, path.extname(photoUrl)).slice(0, -6) + 'bigger' + path.extname(photoUrl); - user.setUserField(uid, 'uploadedpicture', photoUrl); - user.setUserField(uid, 'picture', photoUrl); - } + if(err) { + return callback(err); + } - callback(null, { - uid: uid - }); + // Save twitter-specific information to the user + user.setUserField(uid, 'twid', twid); + RDB.hset('twid:uid', twid, uid); + + // Save their photo, if present + if (photos && photos.length > 0) { + var photoUrl = photos[0].value; + photoUrl = path.dirname(photoUrl) + '/' + path.basename(photoUrl, path.extname(photoUrl)).slice(0, -6) + 'bigger' + path.extname(photoUrl); + user.setUserField(uid, 'uploadedpicture', photoUrl); + user.setUserField(uid, 'picture', photoUrl); } + + callback(null, { + uid: uid + }); }); } }); } Login.loginViaGoogle = function(gplusid, handle, email, callback) { - user.getUidByGoogleId(gplusid, function(uid) { + user.getUidByGoogleId(gplusid, function(err, uid) { + if(err) { + return callback(err); + } + if (uid !== null) { // Existing User callback(null, { @@ -109,21 +117,33 @@ var user = require('./user.js'), }); } - user.getUidByEmail(email, function(uid) { + user.getUidByEmail(email, function(err, uid) { + if(err) { + return callback(err); + } + if (!uid) { user.create(handle, undefined, email, function(err, uid) { - if (err !== null) { - callback(err); - } else success(uid); + if(err) { + return callback(err); + } + + success(uid); }); - } else success(uid); // Existing account -- merge + } else { + success(uid); // Existing account -- merge + } }); } }); } Login.loginViaFacebook = function(fbid, name, email, callback) { - user.getUidByFbid(fbid, function(uid) { + user.getUidByFbid(fbid, function(err, uid) { + if(err) { + return callback(err); + } + if (uid !== null) { // Existing User callback(null, { @@ -140,14 +160,22 @@ var user = require('./user.js'), }); } - user.getUidByEmail(email, function(uid) { + user.getUidByEmail(email, function(err, uid) { + if(err) { + return callback(err); + } + if (!uid) { user.create(name, undefined, email, function(err, uid) { - if (err !== null) { - callback(err); - } else success(uid); + if(err) { + return callback(err); + } + + success(uid); }); - } else success(uid); // Existing account -- merge + } else { + success(uid); // Existing account -- merge + } }); } }); diff --git a/src/user.js b/src/user.js index 92ba8ac42e..d932d235f5 100644 --- a/src/user.js +++ b/src/user.js @@ -13,7 +13,7 @@ var bcrypt = require('bcrypt'), db = require('./database'), meta = require('./meta'), emailjsServer = emailjs.server.connect(meta.config['email:smtp:host'] || '127.0.0.1'), - Groups = require('./groups'), + groups = require('./groups'), notifications = require('./notifications'), topics = require('./topics'); @@ -287,7 +287,7 @@ var bcrypt = require('bcrypt'), }; User.isEmailAvailable = function(email, callback) { - RDB.hexists('email:uid', email, function(err, exists) { + db.isObjectField('email:uid', email, function(err, exists) { callback(err, !exists); }); }; @@ -321,25 +321,25 @@ var bcrypt = require('bcrypt'), }; User.setUserField = function(uid, field, value, callback) { - RDB.hset('user:' + uid, field, value, callback); + db.setObjectField('user:' + uid, field, value, callback); }; User.setUserFields = function(uid, data, callback) { - RDB.hmset('user:' + uid, data, callback); + db.setObject('user:' + uid, data, callback); }; User.incrementUserFieldBy = function(uid, field, value, callback) { - RDB.hincrby('user:' + uid, field, value, callback); + db.incrObjectFieldBy('user:' + uid, field, value, callback); }; User.decrementUserFieldBy = function(uid, field, value, callback) { - RDB.hincrby('user:' + uid, field, -value, callback); + db.incrObjectFieldBy('user:' + uid, field, -value, callback); }; User.getUsers = function(set, start, stop, callback) { var data = []; - RDB.zrevrange(set, start, stop, function(err, uids) { + db.getSortedSetRevRange(set, start, stop, function(err, uids) { if (err) { return callback(err, null); } @@ -360,7 +360,6 @@ var bcrypt = require('bcrypt'), callback(err, data); }); }); - }; User.createGravatarURLFromEmail = function(email) { @@ -433,7 +432,7 @@ var bcrypt = require('bcrypt'), User.addPostIdToUser(uid, pid); User.incrementUserFieldBy(uid, 'postcount', 1, function(err, newpostcount) { - RDB.zadd('users:postcount', newpostcount, uid); + db.sortedSetAdd('users:postcount', newpostcount, uid); }); User.setUserField(uid, 'lastposttime', timestamp); @@ -442,15 +441,15 @@ var bcrypt = require('bcrypt'), }; User.addPostIdToUser = function(uid, pid) { - RDB.lpush('uid:' + uid + ':posts', pid); + db.listPrepend('uid:' + uid + ':posts', pid); }; User.addTopicIdToUser = function(uid, tid) { - RDB.lpush('uid:' + uid + ':topics', tid); + db.listPrepend('uid:' + uid + ':topics', tid); }; - User.getPostIds = function(uid, start, end, callback) { - RDB.lrange('uid:' + uid + ':posts', start, end, function(err, pids) { + User.getPostIds = function(uid, start, stop, callback) { + db.getListRange('uid:' + uid + ':posts', start, stop, function(err, pids) { if (!err) { if (pids && pids.length) { callback(pids); @@ -464,51 +463,12 @@ var bcrypt = require('bcrypt'), }); }; - User.sendConfirmationEmail = function(email) { - if (meta.config['email:smtp:host'] && meta.config['email:smtp:port'] && meta.config['email:from']) { - var confirm_code = utils.generateUUID(), - confirm_link = nconf.get('url') + 'confirm/' + confirm_code, - confirm_email = global.templates['emails/header'] + global.templates['emails/email_confirm'].parse({ - 'CONFIRM_LINK': confirm_link - }) + global.templates['emails/footer'], - confirm_email_plaintext = global.templates['emails/email_confirm_plaintext'].parse({ - 'CONFIRM_LINK': confirm_link - }); - - // Email confirmation code - var expiry_time = 60 * 60 * 2, // Expire after 2 hours - email_key = 'email:' + email + ':confirm', - confirm_key = 'confirm:' + confirm_code + ':email'; - - RDB.set(email_key, confirm_code); - RDB.expire(email_key, expiry_time); - RDB.set(confirm_key, email); - RDB.expire(confirm_key, expiry_time); - - // Send intro email w/ confirm code - var message = emailjs.message.create({ - text: confirm_email_plaintext, - from: meta.config['email:from'] || 'localhost@example.org', - to: email, - subject: '[NodeBB] Registration Email Verification', - attachment: [{ - data: confirm_email, - alternative: true - }] - }); - emailjsServer.send(message, function(err, success) { - if (err) { - console.log(err); - } - }); - } - }; User.follow = function(uid, followid, callback) { - RDB.sadd('following:' + uid, followid, function(err, data) { + db.setAdd('following:' + uid, followid, function(err, data) { if (!err) { - RDB.sadd('followers:' + followid, uid, function(err, data) { + db.setAdd('followers:' + followid, uid, function(err, data) { if (!err) { callback(true); } else { @@ -524,7 +484,7 @@ var bcrypt = require('bcrypt'), }; User.unfollow = function(uid, unfollowid, callback) { - RDB.srem('following:' + uid, unfollowid, function(err, data) { + db.setRemove('following:' + uid, unfollowid, function(err, data) { if (!err) { RDB.srem('followers:' + unfollowid, uid, function(err, data) { callback(data); @@ -536,7 +496,7 @@ var bcrypt = require('bcrypt'), }; User.getFollowing = function(uid, callback) { - RDB.smembers('following:' + uid, function(err, userIds) { + db.getSetMembers('following:' + uid, function(err, userIds) { if (!err) { User.getDataForUsers(userIds, callback); } else { @@ -546,7 +506,7 @@ var bcrypt = require('bcrypt'), }; User.getFollowers = function(uid, callback) { - RDB.smembers('followers:' + uid, function(err, userIds) { + db.getSetMembers('followers:' + uid, function(err, userIds) { if (!err) { User.getDataForUsers(userIds, callback); } else { @@ -556,7 +516,7 @@ var bcrypt = require('bcrypt'), }; User.getFollowingCount = function(uid, callback) { - RDB.smembers('following:' + uid, function(err, userIds) { + db.getSetMembers('following:' + uid, function(err, userIds) { if (err) { console.log(err); } else { @@ -569,7 +529,7 @@ var bcrypt = require('bcrypt'), }; User.getFollowerCount = function(uid, callback) { - RDB.smembers('followers:' + uid, function(err, userIds) { + db.getSetMembers('followers:' + uid, function(err, userIds) { if(err) { console.log(err); } else { @@ -608,7 +568,7 @@ var bcrypt = require('bcrypt'), User.sendPostNotificationToFollowers = function(uid, tid, pid) { User.getUserField(uid, 'username', function(err, username) { - RDB.smembers('followers:' + uid, function(err, followers) { + db.getSetMembers('followers:' + uid, function(err, followers) { topics.getTopicField(tid, 'slug', function(err, slug) { var message = '' + username + ' made a new post'; @@ -621,7 +581,7 @@ var bcrypt = require('bcrypt'), }; User.isFollowing = function(uid, theirid, callback) { - RDB.sismember('following:' + uid, theirid, function(err, data) { + db.isSetMember('following:' + uid, theirid, function(err, data) { if (!err) { callback(data === 1); } else { @@ -637,8 +597,10 @@ var bcrypt = require('bcrypt'), }; User.count = function(socket) { - RDB.get('usercount', function(err, count) { - RDB.handle(err); + db.getObjectField('global', 'usercount', function(err, count) { + if(err) { + return; + } socket.emit('user.count', { count: count ? count : 0 @@ -647,11 +609,11 @@ var bcrypt = require('bcrypt'), }; User.getUidByUsername = function(username, callback) { - RDB.hget('username:uid', username, callback); + db.getObjectField('username:uid', username, callback); }; User.getUidByUserslug = function(userslug, callback) { - RDB.hget('userslug:uid', userslug, callback); + db.getObjectField('userslug:uid', userslug, callback); }; User.getUsernamesByUids = function(uids, callback) { @@ -693,51 +655,53 @@ var bcrypt = require('bcrypt'), }; User.getUidByEmail = function(email, callback) { - RDB.hget('email:uid', email, function(err, data) { + db.getObjectField('email:uid', email, function(err, data) { if (err) { - RDB.handle(err); + return callback(err); } - callback(data); + callback(null, data); }); }; User.getUidByTwitterId = function(twid, callback) { - RDB.hget('twid:uid', twid, function(err, uid) { + db.getObjectField('twid:uid', twid, function(err, uid) { if (err) { - RDB.handle(err); + return callback(err); } - callback(uid); + callback(null, uid); }); }; User.getUidByGoogleId = function(gplusid, callback) { - RDB.hget('gplusid:uid', gplusid, function(err, uid) { + db.getObjectField('gplusid:uid', gplusid, function(err, uid) { if (err) { - RDB.handle(err); + return callback(err); } - callback(uid); + callback(null, uid); }); }; User.getUidByFbid = function(fbid, callback) { - RDB.hget('fbid:uid', fbid, function(err, uid) { + db.getObjectField('fbid:uid', fbid, function(err, uid) { if (err) { - RDB.handle(err); + return callback(err); } - callback(uid); + callback(null, uid); }); }; User.isModerator = function(uid, cid, callback) { - RDB.sismember('cid:' + cid + ':moderators', uid, function(err, exists) { - RDB.handle(err); + db.isSetMember('cid:' + cid + ':moderators', uid, function(err, exists) { + if(err) { + return calback(err); + } callback(err, !! exists); }); }; User.isAdministrator = function(uid, callback) { - Groups.getGidFromName('Administrators', function(err, gid) { - Groups.isMember(uid, gid, function(err, isAdmin) { + groups.getGidFromName('Administrators', function(err, gid) { + groups.isMember(uid, gid, function(err, isAdmin) { callback(err, !! isAdmin); }); }); @@ -750,15 +714,15 @@ var bcrypt = require('bcrypt'), callback = null; } - RDB.hget('reset:uid', code, function(err, uid) { + db.getObjectField('reset:uid', code, function(err, uid) { if (err) { - RDB.handle(err); + return callback(false); } if (uid !== null) { - RDB.hget('reset:expiry', code, function(err, expiry) { + db.getObjectField('reset:expiry', code, function(err, expiry) { if (err) { - RDB.handle(err); + return callback(false); } if (expiry >= +Date.now() / 1000 | 0) { @@ -771,8 +735,8 @@ var bcrypt = require('bcrypt'), } } else { // Expired, delete from db - RDB.hdel('reset:uid', code); - RDB.hdel('reset:expiry', code); + db.deleteObjectField('reset:uid', code); + db.deleteObjectField('reset:expiry', code); if (!callback) { socket.emit('user:reset.valid', { valid: false @@ -794,12 +758,12 @@ var bcrypt = require('bcrypt'), }); }, send: function(socket, email) { - User.getUidByEmail(email, function(uid) { + User.getUidByEmail(email, function(err, uid) { if (uid !== null) { // Generate a new reset code var reset_code = utils.generateUUID(); - RDB.hset('reset:uid', reset_code, uid); - RDB.hset('reset:expiry', reset_code, (60 * 60) + new Date() / 1000 | 0); // Active for one hour + db.setObjectField('reset:uid', reset_code, uid); + db.setobjectField('reset:expiry', reset_code, (60 * 60) + new Date() / 1000 | 0); // Active for one hour var reset_link = nconf.get('url') + 'reset/' + reset_code, reset_email = global.templates['emails/reset'].parse({ @@ -847,17 +811,17 @@ var bcrypt = require('bcrypt'), commit: function(socket, code, password) { this.validate(socket, code, function(validated) { if (validated) { - RDB.hget('reset:uid', code, function(err, uid) { + db.getObjectField('reset:uid', code, function(err, uid) { if (err) { - RDB.handle(err); + return; } User.hashPassword(password, function(err, hash) { User.setUserField(uid, 'password', hash); }); - RDB.hdel('reset:uid', code); - RDB.hdel('reset:expiry', code); + db.deleteObjectField('reset:uid', code); + db.deleteObjectField('reset:expiry', code); socket.emit('user:reset.commit', { status: 'ok' @@ -868,9 +832,48 @@ var bcrypt = require('bcrypt'), } }; + User.sendConfirmationEmail = function(email) { + if (meta.config['email:smtp:host'] && meta.config['email:smtp:port'] && meta.config['email:from']) { + var confirm_code = utils.generateUUID(), + confirm_link = nconf.get('url') + 'confirm/' + confirm_code, + confirm_email = global.templates['emails/header'] + global.templates['emails/email_confirm'].parse({ + 'CONFIRM_LINK': confirm_link + }) + global.templates['emails/footer'], + confirm_email_plaintext = global.templates['emails/email_confirm_plaintext'].parse({ + 'CONFIRM_LINK': confirm_link + }); + + // Email confirmation code + var expiry_time = Date.now() / 1000 + 60 * 60 * 2; + + db.setObjectField('email:confirm', email, confirm_code); + + db.setObjectField('confirm:email', confirm_code, email); + db.setObjectField('confirm:email', confirm_code + ':expire', expiry_time); + + // Send intro email w/ confirm code + var message = emailjs.message.create({ + text: confirm_email_plaintext, + from: meta.config['email:from'] || 'localhost@example.org', + to: email, + subject: '[NodeBB] Registration Email Verification', + attachment: [{ + data: confirm_email, + alternative: true + }] + }); + + emailjsServer.send(message, function(err, success) { + if (err) { + console.log(err); + } + }); + } + }; + User.email = { exists: function(socket, email, callback) { - User.getUidByEmail(email, function(exists) { + User.getUidByEmail(email, function(err, exists) { exists = !! exists; if (typeof callback !== 'function') { socket.emit('user.email.exists', { @@ -882,14 +885,30 @@ var bcrypt = require('bcrypt'), }); }, confirm: function(code, callback) { - RDB.get('confirm:' + code + ':email', function(err, email) { + db.getObjectFields('confirm:email', [code, code + ':expire'], function(err, data) { if (err) { - RDB.handle(err); + return callback({ + status:'error' + }); + } + + var email = data.email; + var expiry = data[code + ':expire']; + if (parseInt(expiry, 10) >= Date.now() / 1000) { + + db.deleteObjectField('confirm:email', code); + db.deleteObjectField('confirm:email', code + ':expire'); + + return callback({ + status: 'expired' + }); } if (email !== null) { - RDB.set('email:' + email + ':confirm', true); - RDB.del('confirm:' + code + ':email'); + db.setObjectField('email:confirm', email, true); + + db.deleteObjectField('confirm:email', code); + db.deleteObjectField('confirm:email', code + ':expire'); callback({ status: 'ok' }); @@ -908,7 +927,7 @@ var bcrypt = require('bcrypt'), async.parallel({ unread: function(next) { - RDB.zrevrange('uid:' + uid + ':notifications:unread', 0, 10, function(err, nids) { + db.getSortedSetRevRange('uid:' + uid + ':notifications:unread', 0, 10, function(err, nids) { // @todo handle err var unread = []; @@ -924,7 +943,7 @@ var bcrypt = require('bcrypt'), if (notif_data) { unread.push(notif_data); } else { - RDB.zrem('uid:' + uid + ':notifications:unread', nid); + db.sortedSetRemove('uid:' + uid + ':notifications:unread', nid); } next(); @@ -938,7 +957,7 @@ var bcrypt = require('bcrypt'), }); }, read: function(next) { - RDB.zrevrange('uid:' + uid + ':notifications:read', 0, 10, function(err, nids) { + db.getSortedSetRevRange('uid:' + uid + ':notifications:read', 0, 10, function(err, nids) { // @todo handle err var read = []; @@ -954,7 +973,7 @@ var bcrypt = require('bcrypt'), if (notif_data) { read.push(notif_data); } else { - RDB.zrem('uid:' + uid + ':notifications:read', nid); + db.sortedSetRemove('uid:' + uid + ':notifications:read', nid); } next(); @@ -986,6 +1005,7 @@ var bcrypt = require('bcrypt'), before = new Date(parseInt(before, 10)); } + // TODO : figure out how to do this with dbal RDB.multi() .zrevrangebyscore('uid:' + uid + ':notifications:read', before ? before.getTime(): now.getTime(), -Infinity, 'LIMIT', 0, limit) .zrevrangebyscore('uid:' + uid + ':notifications:unread', before ? before.getTime(): now.getTime(), -Infinity, 'LIMIT', 0, limit) @@ -1014,10 +1034,10 @@ var bcrypt = require('bcrypt'), }); }, getUnreadCount: function(uid, callback) { - RDB.zcount('uid:' + uid + ':notifications:unread', 0, 10, callback); + db.sortedSetCount('uid:' + uid + ':notifications:unread', 0, 10, callback); }, getUnreadByUniqueId: function(uid, uniqueId, callback) { - RDB.zrange('uid:' + uid + ':notifications:unread', 0, -1, function(err, nids) { + db.getSortedSetRange('uid:' + uid + ':notifications:unread', 0, -1, function(err, nids) { async.filter(nids, function(nid, next) { notifications.get(nid, uid, function(notifObj) { if (notifObj.uniqueId === uniqueId) {