You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
349 lines
9.6 KiB
JavaScript
349 lines
9.6 KiB
JavaScript
"use strict";
|
|
|
|
/* globals console, require */
|
|
|
|
var db = require('./database');
|
|
var async = require('async');
|
|
var winston = require('winston');
|
|
|
|
var Upgrade = {};
|
|
|
|
var minSchemaDate = Date.UTC(2016, 8, 7); // This value gets updated every new MAJOR version
|
|
var schemaDate;
|
|
var thisSchemaDate;
|
|
|
|
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
|
|
var latestSchema = Date.UTC(2016, 10, 22);
|
|
|
|
Upgrade.check = function (callback) {
|
|
db.get('schemaDate', function (err, value) {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
|
|
if (!value) {
|
|
db.set('schemaDate', latestSchema, function (err) {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
callback(null);
|
|
});
|
|
return;
|
|
}
|
|
|
|
var schema_ok = parseInt(value, 10) >= latestSchema;
|
|
callback(!schema_ok ? new Error('schema-out-of-date') : null);
|
|
});
|
|
};
|
|
|
|
Upgrade.update = function (schemaDate, callback) {
|
|
db.set('schemaDate', schemaDate, callback);
|
|
};
|
|
|
|
Upgrade.upgrade = function (callback) {
|
|
var updatesMade = false;
|
|
|
|
winston.info('Beginning database schema update');
|
|
|
|
async.series([
|
|
function (next) {
|
|
// Prepare for upgrade & check to make sure the upgrade is possible
|
|
db.get('schemaDate', function (err, value) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
|
|
if(!value) {
|
|
db.set('schemaDate', latestSchema, function () {
|
|
next();
|
|
});
|
|
schemaDate = latestSchema;
|
|
} else {
|
|
schemaDate = parseInt(value, 10);
|
|
}
|
|
|
|
if (schemaDate >= minSchemaDate) {
|
|
next();
|
|
} else {
|
|
next(new Error('upgrade-not-possible'));
|
|
}
|
|
});
|
|
},
|
|
function (next) {
|
|
thisSchemaDate = Date.UTC(2016, 8, 22);
|
|
|
|
if (schemaDate < thisSchemaDate) {
|
|
updatesMade = true;
|
|
winston.info('[2016/09/22] Setting category recent tids');
|
|
|
|
|
|
db.getSortedSetRange('categories:cid', 0, -1, function (err, cids) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
|
|
async.eachSeries(cids, function (cid, next) {
|
|
db.getSortedSetRevRange('cid:' + cid + ':pids', 0, 0, function (err, pid) {
|
|
if (err || !pid) {
|
|
return next(err);
|
|
}
|
|
db.getObjectFields('post:' + pid, ['tid', 'timestamp'], function (err, postData) {
|
|
if (err || !postData || !postData.tid) {
|
|
return next(err);
|
|
}
|
|
db.sortedSetAdd('cid:' + cid + ':recent_tids', postData.timestamp, postData.tid, next);
|
|
});
|
|
});
|
|
}, function (err) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
|
|
winston.info('[2016/09/22] Setting category recent tids - done');
|
|
Upgrade.update(thisSchemaDate, next);
|
|
});
|
|
});
|
|
} else {
|
|
winston.info('[2016/09/22] Setting category recent tids - skipped!');
|
|
next();
|
|
}
|
|
},
|
|
function (next) {
|
|
function upgradePosts(next) {
|
|
var batch = require('./batch');
|
|
|
|
batch.processSortedSet('posts:pid', function (ids, next) {
|
|
async.each(ids, function (id, next) {
|
|
console.log('processing pid ' + id);
|
|
async.waterfall([
|
|
function (next) {
|
|
db.rename('pid:' + id + ':users_favourited', 'pid:' + id + ':users_bookmarked', next);
|
|
},
|
|
function (next) {
|
|
db.getObjectField('post:' + id, 'reputation', next);
|
|
},
|
|
function (reputation, next) {
|
|
if (parseInt(reputation, 10)) {
|
|
db.setObjectField('post:' + id, 'bookmarks', reputation, next);
|
|
} else {
|
|
next();
|
|
}
|
|
},
|
|
function (next) {
|
|
db.deleteObjectField('post:' + id, 'reputation', next);
|
|
}
|
|
], next);
|
|
}, next);
|
|
}, {}, next);
|
|
}
|
|
|
|
function upgradeUsers(next) {
|
|
var batch = require('./batch');
|
|
|
|
batch.processSortedSet('users:joindate', function (ids, next) {
|
|
async.each(ids, function (id, next) {
|
|
console.log('processing uid ' + id);
|
|
db.rename('uid:' + id + ':favourites', 'uid:' + id + ':bookmarks', next);
|
|
}, next);
|
|
}, {}, next);
|
|
}
|
|
|
|
thisSchemaDate = Date.UTC(2016, 9, 8);
|
|
|
|
if (schemaDate < thisSchemaDate) {
|
|
updatesMade = true;
|
|
winston.info('[2016/10/8] favourite -> bookmark refactor');
|
|
async.series([upgradePosts, upgradeUsers], function (err) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
winston.info('[2016/08/05] favourite- bookmark refactor done!');
|
|
Upgrade.update(thisSchemaDate, next);
|
|
});
|
|
} else {
|
|
winston.info('[2016/10/8] favourite -> bookmark refactor - skipped!');
|
|
next();
|
|
}
|
|
},
|
|
function (next) {
|
|
thisSchemaDate = Date.UTC(2016, 9, 14);
|
|
|
|
if (schemaDate < thisSchemaDate) {
|
|
updatesMade = true;
|
|
winston.info('[2016/10/14] Creating sorted sets for post replies');
|
|
|
|
var posts = require('./posts');
|
|
var batch = require('./batch');
|
|
batch.processSortedSet('posts:pid', function (ids, next) {
|
|
posts.getPostsFields(ids, ['pid', 'toPid', 'timestamp'], function (err, data) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
|
|
async.eachSeries(data, function (postData, next) {
|
|
if (!parseInt(postData.toPid, 10)) {
|
|
return next(null);
|
|
}
|
|
console.log('processing pid: ' + postData.pid + ' toPid: ' + postData.toPid);
|
|
async.parallel([
|
|
async.apply(db.sortedSetAdd, 'pid:' + postData.toPid + ':replies', postData.timestamp, postData.pid),
|
|
async.apply(db.incrObjectField, 'post:' + postData.toPid, 'replies')
|
|
], next);
|
|
}, next);
|
|
});
|
|
}, function (err) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
|
|
winston.info('[2016/10/14] Creating sorted sets for post replies - done');
|
|
Upgrade.update(thisSchemaDate, next);
|
|
});
|
|
} else {
|
|
winston.info('[2016/10/14] Creating sorted sets for post replies - skipped!');
|
|
next();
|
|
}
|
|
},
|
|
function (next) {
|
|
thisSchemaDate = Date.UTC(2016, 10, 22);
|
|
|
|
if (schemaDate < thisSchemaDate) {
|
|
updatesMade = true;
|
|
winston.info('[2016/11/22] Update global and user language keys');
|
|
|
|
var user = require('./user');
|
|
var meta = require('./meta');
|
|
var batch = require('./batch');
|
|
var newLanguage;
|
|
var i = 0;
|
|
var j = 0;
|
|
async.parallel([
|
|
function (next) {
|
|
meta.configs.get('defaultLang', function (err, defaultLang) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
|
|
if (!defaultLang) {
|
|
return setImmediate(next);
|
|
}
|
|
|
|
newLanguage = defaultLang.replace('_', '-').replace('@', '-x-');
|
|
if (newLanguage !== defaultLang) {
|
|
meta.configs.set('defaultLang', newLanguage, next);
|
|
} else {
|
|
setImmediate(next);
|
|
}
|
|
});
|
|
},
|
|
function (next) {
|
|
batch.processSortedSet('users:joindate', function (ids, next) {
|
|
async.each(ids, function (uid, next) {
|
|
async.waterfall([
|
|
async.apply(db.getObjectField, 'user:' + uid + ':settings', 'userLang'),
|
|
function (language, next) {
|
|
++i;
|
|
if (!language) {
|
|
return setImmediate(next);
|
|
}
|
|
|
|
newLanguage = language.replace('_', '-').replace('@', '-x-');
|
|
if (newLanguage !== language) {
|
|
++j;
|
|
user.setSetting(uid, 'userLang', newLanguage, next);
|
|
} else {
|
|
setImmediate(next);
|
|
}
|
|
}
|
|
], next);
|
|
}, next);
|
|
}, next);
|
|
}
|
|
], function (err) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
|
|
winston.info('[2016/11/22] Update global and user language keys - done (' + i + ' processed, ' + j + ' updated)');
|
|
Upgrade.update(thisSchemaDate, next);
|
|
});
|
|
} else {
|
|
winston.info('[2016/11/22] Update global and user language keys - skipped!');
|
|
next();
|
|
}
|
|
},
|
|
function (next) {
|
|
thisSchemaDate = Date.UTC(2016, 10, 25);
|
|
|
|
if (schemaDate < thisSchemaDate) {
|
|
updatesMade = true;
|
|
winston.info('[2016/11/25] Creating sorted sets for pinned topcis');
|
|
|
|
var topics = require('./topics');
|
|
var batch = require('./batch');
|
|
batch.processSortedSet('topics:tid', function (ids, next) {
|
|
topics.getTopicsFields(ids, ['tid', 'cid', 'pinned', 'lastposttime'], function (err, data) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
|
|
data = data.filter(function (topicData) {
|
|
return parseInt(topicData.pinned, 10) === 1;
|
|
});
|
|
|
|
async.eachSeries(data, function (topicData, next) {
|
|
console.log('processing tid: ' + topicData.tid);
|
|
|
|
async.parallel([
|
|
async.apply(db.sortedSetAdd, 'cid:' + topicData.cid + ':tids:pinned', Date.now(), topicData.tid),
|
|
async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids', topicData.tid),
|
|
async.apply(db.sortedSetRemove, 'cid:' + topicData.cid + ':tids:posts', topicData.tid)
|
|
], next);
|
|
}, next);
|
|
});
|
|
}, function (err) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
|
|
winston.info('[2016/11/25] Creating sorted sets for pinned topics - done');
|
|
Upgrade.update(thisSchemaDate, next);
|
|
});
|
|
} else {
|
|
winston.info('[2016/11/25] Creating sorted sets for pinned topics - skipped!');
|
|
next();
|
|
}
|
|
},
|
|
// Add new schema updates here
|
|
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 24!!!
|
|
], function (err) {
|
|
if (!err) {
|
|
if(updatesMade) {
|
|
winston.info('[upgrade] Schema update complete!');
|
|
} else {
|
|
winston.info('[upgrade] Schema already up to date!');
|
|
}
|
|
} else {
|
|
switch(err.message) {
|
|
case 'upgrade-not-possible':
|
|
winston.error('[upgrade] NodeBB upgrade could not complete, as your database schema is too far out of date.');
|
|
winston.error('[upgrade] Please ensure that you did not skip any minor version upgrades.');
|
|
winston.error('[upgrade] (e.g. v0.1.x directly to v0.3.x)');
|
|
break;
|
|
|
|
default:
|
|
winston.error('[upgrade] Errors were encountered while updating the NodeBB schema: ' + err.message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (typeof callback === 'function') {
|
|
callback(err);
|
|
} else {
|
|
process.exit();
|
|
}
|
|
});
|
|
};
|
|
|
|
module.exports = Upgrade;
|