refactor upgrade scripts to use individual files in src/upgrades/ as source of schema changes
parent
62e0f5f883
commit
5b8c9503c3
@ -1,443 +1,74 @@
|
||||
"use strict";
|
||||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
/* globals console, require */
|
||||
|
||||
var db = require('./database');
|
||||
var async = require('async');
|
||||
var winston = require('winston');
|
||||
var path = require('path');
|
||||
|
||||
var Upgrade = {};
|
||||
var utils = require('../public/src/utils');
|
||||
|
||||
var minSchemaDate = Date.UTC(2016, 8, 7); // This value gets updated every new MAJOR version
|
||||
var schemaDate;
|
||||
var thisSchemaDate;
|
||||
var Upgrade = {};
|
||||
|
||||
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
|
||||
var latestSchema = Date.UTC(2016, 11, 7);
|
||||
Upgrade.run = function (callback) {
|
||||
process.stdout.write('\nParsing upgrade scripts... ');
|
||||
|
||||
Upgrade.check = function (callback) {
|
||||
db.get('schemaDate', function (err, value) {
|
||||
utils.walk(path.join(__dirname, './upgrades'), function (err, files) {
|
||||
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.process(files, callback);
|
||||
});
|
||||
};
|
||||
|
||||
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 topics');
|
||||
|
||||
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();
|
||||
}
|
||||
},
|
||||
function (next) {
|
||||
thisSchemaDate = Date.UTC(2016, 11, 7);
|
||||
Upgrade.runSingle = function (query, callback) {
|
||||
process.stdout.write('\nParsing upgrade scripts... ');
|
||||
|
||||
if (schemaDate < thisSchemaDate) {
|
||||
updatesMade = true;
|
||||
winston.info('[2016/12/07] Migrating flags to new schema (#5232)');
|
||||
|
||||
var batch = require('./batch');
|
||||
var posts = require('./posts');
|
||||
var flags = require('./flags');
|
||||
var migrated = 0;
|
||||
|
||||
batch.processSortedSet('posts:pid', function (ids, next) {
|
||||
posts.getPostsByPids(ids, 1, function (err, posts) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
async.waterfall([
|
||||
async.apply(utils.walk, path.join(__dirname, './upgrades')),
|
||||
function (files, next) {
|
||||
next(null, files.filter(function (file) {
|
||||
return file.search(new RegExp(query)) !== -1;
|
||||
}));
|
||||
}
|
||||
], function (err, files) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
posts = posts.filter(function (post) {
|
||||
return post.hasOwnProperty('flags');
|
||||
});
|
||||
|
||||
async.each(posts, function (post, next) {
|
||||
async.parallel({
|
||||
uids: async.apply(db.getSortedSetRangeWithScores, 'pid:' + post.pid + ':flag:uids', 0, -1),
|
||||
reasons: async.apply(db.getSortedSetRange, 'pid:' + post.pid + ':flag:uid:reason', 0, -1)
|
||||
}, function (err, data) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
Upgrade.process(files, callback);
|
||||
});
|
||||
};
|
||||
|
||||
// Adding in another check here in case a post was improperly dismissed (flag count > 1 but no flags in db)
|
||||
if (!data.uids.length || !data.reasons.length) {
|
||||
return setImmediate(next);
|
||||
}
|
||||
Upgrade.process = function (files, callback) {
|
||||
process.stdout.write('OK'.green + String(' ' + files.length).cyan + ' script(s) found\n'.cyan);
|
||||
|
||||
// Just take the first entry
|
||||
var datetime = data.uids[0].score;
|
||||
var reason = data.reasons[0].split(':')[1];
|
||||
var flagObj;
|
||||
// Do I need to sort the files here? we'll see.
|
||||
// sort();
|
||||
|
||||
async.waterfall([
|
||||
async.apply(flags.create, 'post', post.pid, data.uids[0].value, reason, datetime),
|
||||
function (_flagObj, next) {
|
||||
flagObj = _flagObj;
|
||||
if (post['flag:state'] || post['flag:assignee']) {
|
||||
flags.update(flagObj.flagId, 1, {
|
||||
state: post['flag:state'],
|
||||
assignee: post['flag:assignee'],
|
||||
datetime: datetime
|
||||
}, next);
|
||||
} else {
|
||||
setImmediate(next);
|
||||
}
|
||||
},
|
||||
function (next) {
|
||||
if (post.hasOwnProperty('flag:notes') && post['flag:notes'].length) {
|
||||
try {
|
||||
var history = JSON.parse(post['flag:history']);
|
||||
history = history.filter(function (event) {
|
||||
return event.type === 'notes';
|
||||
})[0];
|
||||
async.eachSeries(files, function (file, next) {
|
||||
var scriptExport = require(file);
|
||||
var date = new Date(scriptExport.timestamp);
|
||||
|
||||
flags.appendNote(flagObj.flagId, history.uid, post['flag:notes'], history.timestamp, next);
|
||||
} catch (e) {
|
||||
next(e);
|
||||
}
|
||||
} else {
|
||||
setImmediate(next);
|
||||
}
|
||||
}
|
||||
], function (err) {
|
||||
if (err && err.message === '[[error:already-flagged]]') {
|
||||
// Already flagged, no need to parse, but not an error
|
||||
next();
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}, next);
|
||||
});
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
process.stdout.write(' → '.white + String('[' + [date.getFullYear(), date.getMonth() + 1, date.getDate() + 1].join('/') + '] ').gray + String(scriptExport.name).reset + '... ');
|
||||
|
||||
winston.info('[2016/12/07] Migrating flags to new schema (#5232) - done');
|
||||
Upgrade.update(thisSchemaDate, next);
|
||||
});
|
||||
} else {
|
||||
winston.info('[2016/12/07] Migrating flags to new schema (#5232) - 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!');
|
||||
// Do the upgrade...
|
||||
scriptExport.method(function (err) {
|
||||
if (err) {
|
||||
process.stdout.write('error\n'.red);
|
||||
return next(err);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
process.stdout.write('OK\n'.green);
|
||||
next();
|
||||
});
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback(err);
|
||||
} else {
|
||||
process.exit();
|
||||
}
|
||||
process.stdout.write('Upgrade complete!\n\n'.green);
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Upgrade;
|
||||
module.exports = Upgrade;
|
@ -0,0 +1,33 @@
|
||||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var db = require('../database');
|
||||
|
||||
var async = require('async');
|
||||
var winston = require('winston');
|
||||
|
||||
module.exports = {
|
||||
name: 'Category recent tids',
|
||||
timestamp: Date.UTC(2016, 8, 22),
|
||||
method: function (callback) {
|
||||
db.getSortedSetRange('categories:cid', 0, -1, function (err, cids) {
|
||||
if (err) {
|
||||
return callback(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);
|
||||
});
|
||||
});
|
||||
}, callback);
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,52 @@
|
||||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var db = require('../database');
|
||||
|
||||
var async = require('async');
|
||||
var winston = require('winston');
|
||||
|
||||
module.exports = {
|
||||
name: 'Favourites to Bookmarks',
|
||||
timestamp: Date.UTC(2016, 9, 8),
|
||||
method: function (callback) {
|
||||
function upgradePosts(next) {
|
||||
var batch = require('../batch');
|
||||
|
||||
batch.processSortedSet('posts:pid', function (ids, next) {
|
||||
async.each(ids, function (id, next) {
|
||||
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) {
|
||||
db.rename('uid:' + id + ':favourites', 'uid:' + id + ':bookmarks', next);
|
||||
}, next);
|
||||
}, {}, next);
|
||||
}
|
||||
|
||||
async.series([upgradePosts, upgradeUsers], callback);
|
||||
}
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var db = require('../database');
|
||||
|
||||
var async = require('async');
|
||||
var winston = require('winston');
|
||||
|
||||
module.exports = {
|
||||
name: 'Sorted sets for post replies',
|
||||
timestamp: Date.UTC(2016, 9, 14),
|
||||
method: function (callback) {
|
||||
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);
|
||||
}
|
||||
winston.verbose('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);
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
};
|
@ -0,0 +1,63 @@
|
||||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var db = require('../database');
|
||||
|
||||
var async = require('async');
|
||||
var winston = require('winston');
|
||||
|
||||
module.exports = {
|
||||
name: 'Update global and user language keys',
|
||||
timestamp: Date.UTC(2016, 10, 22),
|
||||
method: function (callback) {
|
||||
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);
|
||||
}
|
||||
], callback);
|
||||
}
|
||||
};
|
@ -0,0 +1,37 @@
|
||||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var db = require('../database');
|
||||
|
||||
var async = require('async');
|
||||
var winston = require('winston');
|
||||
|
||||
module.exports = {
|
||||
name: 'Sorted set for pinned topics',
|
||||
timestamp: Date.UTC(2016, 10, 25),
|
||||
method: function (callback) {
|
||||
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) {
|
||||
winston.verbose('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);
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
};
|
@ -0,0 +1,89 @@
|
||||
/* jslint node: true */
|
||||
'use strict';
|
||||
|
||||
var db = require('../database');
|
||||
|
||||
var async = require('async');
|
||||
|
||||
module.exports = {
|
||||
name: 'Migrating flags to new schema',
|
||||
timestamp: Date.UTC(2016, 11, 7),
|
||||
method: function (callback) {
|
||||
var batch = require('../batch');
|
||||
var posts = require('../posts');
|
||||
var flags = require('../flags');
|
||||
var migrated = 0;
|
||||
|
||||
batch.processSortedSet('posts:pid', function (ids, next) {
|
||||
posts.getPostsByPids(ids, 1, function (err, posts) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
posts = posts.filter(function (post) {
|
||||
return post.hasOwnProperty('flags');
|
||||
});
|
||||
|
||||
async.each(posts, function (post, next) {
|
||||
async.parallel({
|
||||
uids: async.apply(db.getSortedSetRangeWithScores, 'pid:' + post.pid + ':flag:uids', 0, -1),
|
||||
reasons: async.apply(db.getSortedSetRange, 'pid:' + post.pid + ':flag:uid:reason', 0, -1)
|
||||
}, function (err, data) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
// Adding in another check here in case a post was improperly dismissed (flag count > 1 but no flags in db)
|
||||
if (!data.uids.length || !data.reasons.length) {
|
||||
return setImmediate(next);
|
||||
}
|
||||
|
||||
// Just take the first entry
|
||||
var datetime = data.uids[0].score;
|
||||
var reason = data.reasons[0].split(':')[1];
|
||||
var flagObj;
|
||||
|
||||
async.waterfall([
|
||||
async.apply(flags.create, 'post', post.pid, data.uids[0].value, reason, datetime),
|
||||
function (_flagObj, next) {
|
||||
flagObj = _flagObj;
|
||||
if (post['flag:state'] || post['flag:assignee']) {
|
||||
flags.update(flagObj.flagId, 1, {
|
||||
state: post['flag:state'],
|
||||
assignee: post['flag:assignee'],
|
||||
datetime: datetime
|
||||
}, next);
|
||||
} else {
|
||||
setImmediate(next);
|
||||
}
|
||||
},
|
||||
function (next) {
|
||||
if (post.hasOwnProperty('flag:notes') && post['flag:notes'].length) {
|
||||
try {
|
||||
var history = JSON.parse(post['flag:history']);
|
||||
history = history.filter(function (event) {
|
||||
return event.type === 'notes';
|
||||
})[0];
|
||||
|
||||
flags.appendNote(flagObj.flagId, history.uid, post['flag:notes'], history.timestamp, next);
|
||||
} catch (e) {
|
||||
next(e);
|
||||
}
|
||||
} else {
|
||||
setImmediate(next);
|
||||
}
|
||||
}
|
||||
], function (err) {
|
||||
if (err && err.message === '[[error:already-flagged]]') {
|
||||
// Already flagged, no need to parse, but not an error
|
||||
next();
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}, next);
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue