diff --git a/src/upgrade.js b/src/upgrade.js index 79ffa6b5ee..b8461f7be9 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -2,17 +2,18 @@ /* globals console, require */ -var db = require('./database'), - async = require('async'), - winston = require('winston'), +var db = require('./database'); +var async = require('async'); +var winston = require('winston'); - Upgrade = {}, +var Upgrade = {}; - minSchemaDate = Date.UTC(2015, 10, 6), // This value gets updated every new MAJOR version - schemaDate, thisSchemaDate, +var minSchemaDate = Date.UTC(2015, 10, 6); // This value gets updated every new MAJOR version +var schemaDate +var thisSchemaDate; - // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema - latestSchema = Date.UTC(2016, 10, 22); +// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema +var latestSchema = Date.UTC(2016, 10, 22); Upgrade.check = function (callback) { db.get('schemaDate', function (err, value) { @@ -68,752 +69,6 @@ Upgrade.upgrade = function (callback) { } }); }, - function (next) { - thisSchemaDate = Date.UTC(2015, 11, 15); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2015/12/15] Upgrading chats'); - - db.getObjectFields('global', ['nextMid', 'nextChatRoomId'], function (err, globalData) { - if (err) { - return next(err); - } - - var rooms = {}; - var roomId = globalData.nextChatRoomId || 1; - var currentMid = 1; - - async.whilst(function () { - return currentMid <= globalData.nextMid; - }, function (next) { - db.getObject('message:' + currentMid, function (err, message) { - function addMessageToUids(roomId, callback) { - async.parallel([ - function (next) { - db.sortedSetAdd('uid:' + message.fromuid + ':chat:room:' + roomId + ':mids', msgTime, currentMid, next); - }, - function (next) { - db.sortedSetAdd('uid:' + message.touid + ':chat:room:' + roomId + ':mids', msgTime, currentMid, next); - } - ], callback); - } - - if (err || !message) { - winston.info('skipping chat message ', currentMid); - currentMid ++; - return next(err); - } - - var pairID = [parseInt(message.fromuid, 10), parseInt(message.touid, 10)].sort().join(':'); - var msgTime = parseInt(message.timestamp, 10); - - if (rooms[pairID]) { - winston.info('adding message ' + currentMid + ' to existing roomID ' + roomId); - addMessageToUids(rooms[pairID], function (err) { - if (err) { - return next(err); - } - currentMid ++; - next(); - }); - } else { - winston.info('adding message ' + currentMid + ' to new roomID ' + roomId); - async.parallel([ - function (next) { - db.sortedSetAdd('uid:' + message.fromuid + ':chat:rooms', msgTime, roomId, next); - }, - function (next) { - db.sortedSetAdd('uid:' + message.touid + ':chat:rooms', msgTime, roomId, next); - }, - function (next) { - db.sortedSetAdd('chat:room:' + roomId + ':uids', [msgTime, msgTime + 1], [message.fromuid, message.touid], next); - }, - function (next) { - addMessageToUids(roomId, next); - } - ], function (err) { - if (err) { - return next(err); - } - rooms[pairID] = roomId; - roomId ++; - currentMid ++; - db.setObjectField('global', 'nextChatRoomId', roomId, next); - }); - } - }); - }, function (err) { - if (err) { - return next(err); - } - - winston.info('[2015/12/15] Chats upgrade done!'); - Upgrade.update(thisSchemaDate, next); - }); - }); - } else { - winston.info('[2015/12/15] Chats upgrade skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2015, 11, 23); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2015/12/23] Upgrading chat room hashes'); - - db.getObjectField('global', 'nextChatRoomId', function (err, nextChatRoomId) { - if (err) { - return next(err); - } - var currentChatRoomId = 1; - async.whilst(function () { - return currentChatRoomId <= nextChatRoomId; - }, function (next) { - db.getSortedSetRange('chat:room:' + currentChatRoomId + ':uids', 0, 0, function (err, uids) { - if (err) { - return next(err); - } - if (!Array.isArray(uids) || !uids.length || !uids[0]) { - ++ currentChatRoomId; - return next(); - } - - db.setObject('chat:room:' + currentChatRoomId, {owner: uids[0], roomId: currentChatRoomId}, function (err) { - if (err) { - return next(err); - } - ++ currentChatRoomId; - next(); - }); - }); - }, function (err) { - if (err) { - return next(err); - } - - winston.info('[2015/12/23] Chats room hashes upgrade done!'); - Upgrade.update(thisSchemaDate, next); - }); - }); - } else { - winston.info('[2015/12/23] Chats room hashes upgrade skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 0, 11); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2015/12/23] Adding theme to active plugins sorted set'); - - async.waterfall([ - async.apply(db.getObjectField, 'config', 'theme:id'), - async.apply(db.sortedSetAdd, 'plugins:active', 0) - ], function (err) { - if (err) { - return next(err); - } - - winston.info('[2015/12/23] Adding theme to active plugins sorted set done!'); - Upgrade.update(thisSchemaDate, next); - }); - } else { - winston.info('[2015/12/23] Adding theme to active plugins sorted set skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 0, 14); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/01/14] Creating user best post sorted sets'); - - var batch = require('./batch'); - - batch.processSortedSet('posts:pid', function (ids, next) { - async.eachSeries(ids, function (id, next) { - db.getObjectFields('post:' + id, ['pid', 'uid', 'votes'], function (err, postData) { - if (err) { - return next(err); - } - if (!postData || !parseInt(postData.votes, 10) || !parseInt(postData.uid, 10)) { - return next(); - } - winston.info('processing pid: ' + postData.pid + ' uid: ' + postData.uid + ' votes: ' + postData.votes); - db.sortedSetAdd('uid:' + postData.uid + ':posts:votes', postData.votes, postData.pid, next); - }); - }, next); - }, {}, function (err) { - if (err) { - return next(err); - } - winston.info('[2016/01/14] Creating user best post sorted sets done!'); - Upgrade.update(thisSchemaDate, next); - }); - } else { - winston.info('[2016/01/14] Creating user best post sorted sets skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 0, 20); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/01/20] Creating users:notvalidated'); - - var batch = require('./batch'); - var now = Date.now(); - batch.processSortedSet('users:joindate', function (ids, next) { - async.eachSeries(ids, function (id, next) { - db.getObjectFields('user:' + id, ['uid', 'email:confirmed'], function (err, userData) { - if (err) { - return next(err); - } - if (!userData || !parseInt(userData.uid, 10) || parseInt(userData['email:confirmed'], 10) === 1) { - return next(); - } - winston.info('processing uid: ' + userData.uid + ' email:confirmed: ' + userData['email:confirmed']); - db.sortedSetAdd('users:notvalidated', now, userData.uid, next); - }); - }, next); - }, {}, function (err) { - if (err) { - return next(err); - } - winston.info('[2016/01/20] Creating users:notvalidated done!'); - Upgrade.update(thisSchemaDate, next); - }); - } else { - winston.info('[2016/01/20] Creating users:notvalidated skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 0, 23); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/01/23] Creating Global moderators group'); - - var groups = require('./groups'); - async.waterfall([ - function (next) { - groups.exists('Global Moderators', next); - }, - function (exists, next) { - if (exists) { - return next(null, null); - } - groups.create({ - name: 'Global Moderators', - userTitle: 'Global Moderator', - description: 'Forum wide moderators', - hidden: 0, - private: 1, - disableJoinRequests: 1 - }, next); - }, - function (groupData, next) { - groups.show('Global Moderators', next); - } - ], function (err) { - if (err) { - return next(err); - } - - winston.info('[2016/01/23] Creating Global moderators group done!'); - Upgrade.update(thisSchemaDate, next); - }); - } else { - winston.info('[2016/01/23] Creating Global moderators group skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 1, 25); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/02/25] Social: Post Sharing'); - - var social = require('./social'); - async.parallel([ - function (next) { - social.setActivePostSharingNetworks(['facebook', 'google', 'twitter'], next); - }, - function (next) { - db.deleteObjectField('config', 'disableSocialButtons', next); - } - ], function (err) { - if (err) { - return next(err); - } - - winston.info('[2016/02/25] Social: Post Sharing done!'); - Upgrade.update(thisSchemaDate, next); - }); - } else { - winston.info('[2016/02/25] Social: Post Sharing skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 3, 14); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/04/14] Group title from settings to user profile'); - - var user = require('./user'); - var batch = require('./batch'); - var count = 0; - batch.processSortedSet('users:joindate', function (uids, next) { - winston.info('upgraded ' + count + ' users'); - user.getMultipleUserSettings(uids, function (err, settings) { - if (err) { - return next(err); - } - count += uids.length; - settings = settings.filter(function (setting) { - return setting && setting.groupTitle; - }); - - async.each(settings, function (setting, next) { - db.setObjectField('user:' + setting.uid, 'groupTitle', setting.groupTitle, next); - }, next); - }); - }, {}, function (err) { - if (err) { - return next(err); - } - - winston.info('[2016/04/14] Group title from settings to user profile done'); - Upgrade.update(thisSchemaDate, next); - }); - } else { - winston.info('[2016/04/14] Group title from settings to user profile skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 3, 18); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/04/19] Users post count per tid'); - - var batch = require('./batch'); - var topics = require('./topics'); - var count = 0; - batch.processSortedSet('topics:tid', function (tids, next) { - winston.info('upgraded ' + count + ' topics'); - count += tids.length; - async.each(tids, function (tid, next) { - db.delete('tid:' + tid + ':posters', function (err) { - if (err) { - return next(err); - } - topics.getPids(tid, function (err, pids) { - if (err) { - return next(err); - } - - if (!pids.length) { - return next(); - } - - async.eachSeries(pids, function (pid, next) { - db.getObjectField('post:' + pid, 'uid', function (err, uid) { - if (err) { - return next(err); - } - if (!parseInt(uid, 10)) { - return next(); - } - db.sortedSetIncrBy('tid:' + tid + ':posters', 1, uid, next); - }); - }, next); - }); - }); - }, next); - }, {}, function (err) { - if (err) { - return next(err); - } - - winston.info('[2016/04/19] Users post count per tid done'); - Upgrade.update(thisSchemaDate, next); - }); - } else { - winston.info('[2016/04/19] Users post count per tid skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 3, 29); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/04/29] Dismiss flags from deleted topics'); - - var posts = require('./posts'), - topics = require('./topics'); - - var pids, tids; - - async.waterfall([ - async.apply(db.getSortedSetRange, 'posts:flagged', 0, -1), - function (_pids, next) { - pids = _pids; - posts.getPostsFields(pids, ['tid'], next); - }, - function (_tids, next) { - tids = _tids.map(function (a) { - return a.tid; - }); - - topics.getTopicsFields(tids, ['deleted'], next); - }, - function (state, next) { - var toDismiss = state.map(function (a, idx) { - return parseInt(a.deleted, 10) === 1 ? pids[idx] : null; - }).filter(Boolean); - - winston.info('[2016/04/29] ' + toDismiss.length + ' dismissable flags found'); - async.each(toDismiss, posts.dismissFlag, next); - } - ], function (err) { - if (err) { - return next(err); - } - - winston.info('[2016/04/29] Dismiss flags from deleted topics done'); - Upgrade.update(thisSchemaDate, next); - }); - } else { - winston.info('[2016/04/29] Dismiss flags from deleted topics skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 4, 28); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/05/28] Giving topics:read privs to any group that was previously allowed to Find & Access Category'); - - var groupsAPI = require('./groups'); - var privilegesAPI = require('./privileges'); - - db.getSortedSetRange('categories:cid', 0, -1, function (err, cids) { - if (err) { - return next(err); - } - - async.eachSeries(cids, function (cid, next) { - privilegesAPI.categories.list(cid, function (err, data) { - if (err) { - return next(err); - } - - var groups = data.groups; - var users = data.users; - - async.waterfall([ - function (next) { - async.eachSeries(groups, function (group, next) { - if (group.privileges['groups:read']) { - return groupsAPI.join('cid:' + cid + ':privileges:groups:topics:read', group.name, function (err) { - if (!err) { - winston.info('cid:' + cid + ':privileges:groups:topics:read granted to gid: ' + group.name); - } - - return next(err); - }); - } - - next(null); - }, next); - }, - function (next) { - async.eachSeries(users, function (user, next) { - if (user.privileges.read) { - return groupsAPI.join('cid:' + cid + ':privileges:topics:read', user.uid, function (err) { - if (!err) { - winston.info('cid:' + cid + ':privileges:topics:read granted to uid: ' + user.uid); - } - - return next(err); - }); - } - - next(null); - }, next); - } - ], function (err) { - if (!err) { - winston.info('-- cid ' + cid + ' upgraded'); - } - - next(err); - }); - }); - }, function (err) { - if (err) { - return next(err); - } - - winston.info('[2016/05/28] Giving topics:read privs to any group that was previously allowed to Find & Access Category - done'); - Upgrade.update(thisSchemaDate, next); - }); - }); - } else { - winston.info('[2016/05/28] Giving topics:read privs to any group that was previously allowed to Find & Access Category - skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 5, 13); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/06/13] Store upvotes/downvotes separately'); - - var batch = require('./batch'); - var posts = require('./posts'); - var count = 0; - batch.processSortedSet('posts:pid', function (pids, next) { - winston.info('upgraded ' + count + ' posts'); - count += pids.length; - async.each(pids, function (pid, next) { - async.parallel({ - upvotes: function (next) { - db.setCount('pid:' + pid + ':upvote', next); - }, - downvotes: function (next) { - db.setCount('pid:' + pid + ':downvote', next); - } - }, function (err, results) { - if (err) { - return next(err); - } - var data = {}; - - if (parseInt(results.upvotes, 10) > 0) { - data.upvotes = results.upvotes; - } - if (parseInt(results.downvotes, 10) > 0) { - data.downvotes = results.downvotes; - } - - if (Object.keys(data).length) { - posts.setPostFields(pid, data, next); - } else { - next(); - } - }, next); - }, next); - }, {}, function (err) { - if (err) { - return next(err); - } - - winston.info('[2016/06/13] Store upvotes/downvotes separately done'); - Upgrade.update(thisSchemaDate, next); - }); - } else { - winston.info('[2016/06/13] Store upvotes/downvotes separately skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 6, 12); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/07/12] Giving upload privileges'); - var privilegesAPI = require('./privileges'); - var meta = require('./meta'); - - db.getSortedSetRange('categories:cid', 0, -1, function (err, cids) { - if (err) { - return next(err); - } - - async.eachSeries(cids, function (cid, next) { - privilegesAPI.categories.list(cid, function (err, data) { - if (err) { - return next(err); - } - async.eachSeries(data.groups, function (group, next) { - if (group.name === 'guests' && parseInt(meta.config.allowGuestUploads, 10) !== 1) { - return next(); - } - if (group.privileges['groups:read']) { - privilegesAPI.categories.give(['upload:post:image'], cid, group.name, next); - } else { - next(); - } - }, next); - }); - }, function (err) { - if (err) { - return next(err); - } - - winston.info('[2016/07/12] Upload privileges done'); - Upgrade.update(thisSchemaDate, next); - }); - }); - } else { - winston.info('[2016/07/12] Upload privileges skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 7, 5); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/08/05] Removing best posts with negative scores'); - var batch = require('./batch'); - batch.processSortedSet('users:joindate', function (ids, next) { - async.each(ids, function (id, next) { - console.log('processing uid ' + id); - db.sortedSetsRemoveRangeByScore(['uid:' + id + ':posts:votes'], '-inf', 0, next); - }, next); - }, {}, function (err) { - if (err) { - return next(err); - } - winston.info('[2016/08/05] Removing best posts with negative scores done!'); - Upgrade.update(thisSchemaDate, next); - }); - - } else { - winston.info('[2016/08/05] Removing best posts with negative scores skipped!'); - next(); - } - }, - function (next) { - thisSchemaDate = Date.UTC(2016, 8, 7); - - if (schemaDate < thisSchemaDate) { - updatesMade = true; - winston.info('[2016/08/07] Granting edit/delete/delete topic on existing categories'); - - var groupsAPI = require('./groups'); - var privilegesAPI = require('./privileges'); - - db.getSortedSetRange('categories:cid', 0, -1, function (err, cids) { - if (err) { - return next(err); - } - - async.eachSeries(cids, function (cid, next) { - privilegesAPI.categories.list(cid, function (err, data) { - if (err) { - return next(err); - } - - var groups = data.groups; - var users = data.users; - - async.waterfall([ - function (next) { - async.eachSeries(groups, function (group, next) { - if (group.privileges['groups:topics:reply']) { - return async.parallel([ - async.apply(groupsAPI.join, 'cid:' + cid + ':privileges:groups:posts:edit', group.name), - async.apply(groupsAPI.join, 'cid:' + cid + ':privileges:groups:posts:delete', group.name) - ], function (err) { - if (!err) { - winston.info('cid:' + cid + ':privileges:groups:posts:edit, cid:' + cid + ':privileges:groups:posts:delete granted to gid: ' + group.name); - } - - return next(err); - }); - } - - next(null); - }, next); - }, - function (next) { - async.eachSeries(groups, function (group, next) { - if (group.privileges['groups:topics:create']) { - return groupsAPI.join('cid:' + cid + ':privileges:groups:topics:delete', group.name, function (err) { - if (!err) { - winston.info('cid:' + cid + ':privileges:groups:topics:delete granted to gid: ' + group.name); - } - - return next(err); - }); - } - - next(null); - }, next); - }, - function (next) { - async.eachSeries(users, function (user, next) { - if (user.privileges['topics:reply']) { - return async.parallel([ - async.apply(groupsAPI.join, 'cid:' + cid + ':privileges:posts:edit', user.uid), - async.apply(groupsAPI.join, 'cid:' + cid + ':privileges:posts:delete', user.uid) - ], function (err) { - if (!err) { - winston.info('cid:' + cid + ':privileges:posts:edit, cid:' + cid + ':privileges:posts:delete granted to uid: ' + user.uid); - } - - return next(err); - }); - } - - next(null); - }, next); - }, - function (next) { - async.eachSeries(users, function (user, next) { - if (user.privileges['topics:create']) { - return groupsAPI.join('cid:' + cid + ':privileges:topics:delete', user.uid, function (err) { - if (!err) { - winston.info('cid:' + cid + ':privileges:topics:delete granted to uid: ' + user.uid); - } - - return next(err); - }); - } - - next(null); - }, next); - } - ], function (err) { - if (!err) { - winston.info('-- cid ' + cid + ' upgraded'); - } - - next(err); - }); - }); - }, function (err) { - if (err) { - return next(err); - } - - winston.info('[2016/08/07] Granting edit/delete/delete topic on existing categories - done'); - Upgrade.update(thisSchemaDate, next); - }); - }); - } else { - winston.info('[2016/08/07] Granting edit/delete/delete topic on existing categories - skipped!'); - next(); - } - }, function (next) { thisSchemaDate = Date.UTC(2016, 8, 22);