Merge remote-tracking branch 'refs/remotes/origin/master' into develop

This commit is contained in:
Barış Soner Uşaklı
2018-01-22 15:21:20 -05:00
294 changed files with 878 additions and 482 deletions

View File

@@ -62,6 +62,9 @@ helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) {
sso: function (next) {
plugins.fireHook('filter:auth.list', { uid: uid, associations: [] }, next);
},
canEdit: function (next) {
privileges.users.canEdit(callerUID, uid, next);
},
canBanUser: function (next) {
privileges.users.canBanUser(callerUID, uid, next);
},
@@ -113,7 +116,7 @@ helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) {
userData.isAdminOrGlobalModerator = isAdmin || isGlobalModerator;
userData.isAdminOrGlobalModeratorOrModerator = isAdmin || isGlobalModerator || isModerator;
userData.isSelfOrAdminOrGlobalModerator = isSelf || isAdmin || isGlobalModerator;
userData.canEdit = isAdmin || (isGlobalModerator && !results.isTargetAdmin);
userData.canEdit = results.canEdit;
userData.canBan = results.canBanUser;
userData.canChangePassword = isAdmin || (isSelf && parseInt(meta.config['password:disableEdit'], 10) !== 1);
userData.isSelf = isSelf;

View File

@@ -48,6 +48,7 @@ dashboardController.get = function (req, res, next) {
version: nconf.get('version'),
notices: results.notices,
stats: results.stats,
canRestart: !!process.send,
});
},
], next);

View File

@@ -129,7 +129,7 @@ helpers.buildCategoryBreadcrumbs = function (cid, callback) {
return callback(err);
}
if (!meta.config.homePageRoute && meta.config.homePageCustom) {
if (meta.config.homePageRoute && meta.config.homePageRoute !== 'categories') {
breadcrumbs.unshift({
text: '[[global:header.categories]]',
url: nconf.get('relative_path') + '/categories',

View File

@@ -387,7 +387,7 @@ Flags.create = function (type, id, uid, reason, timestamp, callback) {
tasks.push(async.apply(Flags.update, flagId, uid, { state: 'open' }));
}
async.parallel(tasks, function (err) {
async.series(tasks, function (err) {
next(err, flagId);
});
},

View File

@@ -143,6 +143,11 @@ function build(targets, callback) {
target = target.toLowerCase().replace(/-/g, '');
if (!aliases[target]) {
winston.warn('[build] Unknown target: ' + target);
if (target.indexOf(',') !== -1) {
winston.warn('[build] Are you specifying multiple targets? Separate them with spaces:');
winston.warn('[build] e.g. `./nodebb build adminjs tpl`');
}
return false;
}

View File

@@ -12,6 +12,7 @@ var plugins = require('../plugins');
var cache = require('./cache');
var pubsub = require('../pubsub');
var utils = require('../utils');
var translator = require('../translator');
module.exports = function (Posts) {
pubsub.on('post:edit', function (pid) {
@@ -149,6 +150,7 @@ module.exports = function (Posts) {
topicData.tags = data.tags;
topicData.oldTitle = results.topic.title;
topicData.timestamp = results.topic.timestamp;
var renamed = translator.escape(validator.escape(String(title))) !== results.topic.title;
plugins.fireHook('action:topic.edit', { topic: topicData, uid: data.uid });
next(null, {
tid: tid,
@@ -158,7 +160,7 @@ module.exports = function (Posts) {
oldTitle: results.topic.title,
slug: topicData.slug,
isMainPost: true,
renamed: title !== results.topic.title,
renamed: renamed,
tags: tags,
});
},

View File

@@ -141,9 +141,13 @@ module.exports = function (privileges) {
}, next);
},
function (results, next) {
var canEdit = results.isAdmin || (results.isGlobalMod && !results.isTargetAdmin);
next(null, canEdit);
results.canEdit = results.isAdmin || (results.isGlobalMod && !results.isTargetAdmin);
results.callerUid = callerUid;
results.uid = uid;
plugins.fireHook('filter:user.canEdit', results, next);
},
function (data, next) {
next(null, data.canEdit);
},
], callback);
};

View File

@@ -15,7 +15,7 @@ module.exports = function (SocketUser) {
async.waterfall([
function (next) {
isAdminOrSelfAndPasswordMatch(socket.uid, data, next);
isPrivilegedOrSelfAndPasswordMatch(socket.uid, data, next);
},
function (next) {
SocketUser.updateProfile(socket, data, next);
@@ -29,7 +29,7 @@ module.exports = function (SocketUser) {
}
async.waterfall([
function (next) {
user.isAdminOrSelf(socket.uid, data.uid, next);
user.isAdminOrGlobalModOrSelf(socket.uid, data.uid, next);
},
function (next) {
user.updateCoverPicture(data, next);
@@ -43,7 +43,7 @@ module.exports = function (SocketUser) {
}
async.waterfall([
function (next) {
user.isAdminOrSelf(socket.uid, data.uid, next);
user.isAdminOrGlobalModOrSelf(socket.uid, data.uid, next);
},
function (next) {
user.uploadCroppedPicture(data, next);
@@ -58,7 +58,7 @@ module.exports = function (SocketUser) {
async.waterfall([
function (next) {
user.isAdminOrSelf(socket.uid, data.uid, next);
user.isAdminOrGlobalModOrSelf(socket.uid, data.uid, next);
},
function (next) {
user.removeCoverPicture(data, next);
@@ -66,11 +66,13 @@ module.exports = function (SocketUser) {
], callback);
};
function isAdminOrSelfAndPasswordMatch(uid, data, callback) {
function isPrivilegedOrSelfAndPasswordMatch(uid, data, callback) {
async.waterfall([
function (next) {
async.parallel({
isAdmin: async.apply(user.isAdministrator, uid),
isTargetAdmin: async.apply(user.isAdministrator, data.uid),
isGlobalMod: async.apply(user.isGlobalModerator, uid),
hasPassword: async.apply(user.hasPassword, data.uid),
passwordMatch: function (next) {
if (data.password) {
@@ -84,7 +86,11 @@ module.exports = function (SocketUser) {
function (results, next) {
var isSelf = parseInt(uid, 10) === parseInt(data.uid, 10);
if (!results.isAdmin && !isSelf) {
if (results.isTargetAdmin && !results.isAdmin) {
return next(new Error('[[error:no-privileges]]'));
}
if ((!results.isAdmin || !results.isGlobalMod) && !isSelf) {
return next(new Error('[[error:no-privileges]]'));
}

View File

@@ -253,16 +253,13 @@ module.exports = function (Topics) {
async.waterfall([
function (next) {
Topics.exists(tid, next);
},
function (exists, next) {
if (!exists) {
return next(new Error('[[error:no-topic]]'));
}
Topics.getTopicFields(tid, ['cid', 'lastposttime', 'pinned', 'deleted', 'postcount', 'upvotes', 'downvotes'], next);
Topics.getTopicData(tid, next);
},
function (topicData, next) {
topic = topicData;
if (!topic) {
return next(new Error('[[error:no-topic]]'));
}
if (parseInt(cid, 10) === parseInt(topic.cid, 10)) {
return next(new Error('[[error:cant-move-topic-to-same-category]]'));
}
@@ -273,11 +270,15 @@ module.exports = function (Topics) {
'cid:' + topicData.cid + ':tids:votes',
'cid:' + topicData.cid + ':tids:lastposttime',
'cid:' + topicData.cid + ':recent_tids',
'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids',
], tid, next);
},
function (next) {
db.sortedSetAdd('cid:' + cid + ':tids:lastposttime', topic.lastposttime, tid, next);
},
function (next) {
db.sortedSetAdd('cid:' + cid + ':uid:' + topic.uid + ':tids', topic.timestamp, tid, next);
},
function (next) {
if (parseInt(topic.pinned, 10)) {
db.sortedSetAdd('cid:' + cid + ':tids:pinned', Date.now(), tid, next);

View File

@@ -1,37 +1,43 @@
'use strict';
var db = require('../../database');
var meta = require('../../meta');
module.exports = {
name: 'Generate customHTML block from old customJS setting',
timestamp: Date.UTC(2017, 9, 12),
method: function (callback) {
var newHTML = meta.config.customJS;
var newJS = [];
// Forgive me for parsing HTML with regex...
var scriptMatch = /^<script\s?(?!async|deferred)?>([\s\S]+?)<\/script>/m;
var match = scriptMatch.exec(newHTML);
while (match) {
if (match[1]) {
// Append to newJS array
newJS.push(match[1].trim());
// Remove the match from the existing value
newHTML = ((match.index > 0 ? newHTML.slice(0, match.index) : '') + newHTML.slice(match.index + match[0].length)).trim();
db.getObjectField('config', 'customJS', function (err, newHTML) {
if (err) {
return callback(err);
}
match = scriptMatch.exec(newHTML);
}
var newJS = [];
// Combine newJS array
newJS = newJS.join('\n\n');
// Forgive me for parsing HTML with regex...
var scriptMatch = /^<script\s?(?!async|deferred)?>([\s\S]+?)<\/script>/m;
var match = scriptMatch.exec(newHTML);
// Write both values to config
meta.configs.setMultiple({
customHTML: newHTML,
customJS: newJS,
}, callback);
while (match) {
if (match[1]) {
// Append to newJS array
newJS.push(match[1].trim());
// Remove the match from the existing value
newHTML = ((match.index > 0 ? newHTML.slice(0, match.index) : '') + newHTML.slice(match.index + match[0].length)).trim();
}
match = scriptMatch.exec(newHTML);
}
// Combine newJS array
newJS = newJS.join('\n\n');
// Write both values to config
meta.configs.setMultiple({
customHTML: newHTML,
customJS: newJS,
}, callback);
});
},
};

View File

@@ -0,0 +1,52 @@
'use strict';
var async = require('async');
var batch = require('../../batch');
var db = require('../../database');
module.exports = {
name: 'Fix topics in categories per user if they were moved',
timestamp: Date.UTC(2018, 0, 22),
method: function (callback) {
var progress = this.progress;
batch.processSortedSet('topics:tid', function (tids, next) {
async.eachLimit(tids, 500, function (tid, _next) {
progress.incr();
var topicData;
async.waterfall([
function (next) {
db.getObjectFields('topic:' + tid, ['cid', 'tid', 'uid', 'oldCid', 'timestamp'], next);
},
function (_topicData, next) {
topicData = _topicData;
if (!topicData.cid || !topicData.oldCid) {
return _next();
}
db.isSortedSetMember('cid:' + topicData.oldCid + ':uid:' + topicData.uid, topicData.tid, next);
},
function (isMember, next) {
if (isMember) {
async.series([
function (next) {
db.sortedSetRemove('cid:' + topicData.oldCid + ':uid:' + topicData.uid + ':tids', tid, next);
},
function (next) {
db.sortedSetAdd('cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids', topicData.timestamp, tid, next);
},
], function (err) {
next(err);
});
} else {
next();
}
},
], _next);
}, next);
}, {
progress: progress,
batch: 500,
}, callback);
},
};

View File

@@ -119,7 +119,7 @@ UserReset.commit = function (code, password, callback) {
user.hashPassword(password, next);
},
function (hash, next) {
async.parallel([
async.series([
async.apply(user.setUserFields, uid, { password: hash, 'email:confirmed': 1 }),
async.apply(db.deleteObjectField, 'reset:uid', code),
async.apply(db.sortedSetRemove, 'reset:issueDate', code),
@@ -128,7 +128,10 @@ UserReset.commit = function (code, password, callback) {
async.apply(user.auth.resetLockout, uid),
async.apply(db.delete, 'uid:' + uid + ':confirm:email:sent'),
async.apply(db.sortedSetRemove, 'users:notvalidated', uid),
], next);
async.apply(UserReset.cleanByUid, uid),
], function (err) {
next(err);
});
},
], callback);
};

View File

@@ -101,13 +101,15 @@
<div class="panel-heading">[[admin/general/dashboard:control-panel]]</div>
<div class="panel-body text-center">
<p>
<div class="btn-group">
<button class="btn btn-warning reload">[[admin/general/dashboard:reload]]</button>
<button class="btn btn-danger restart">[[admin/general/dashboard:restart]]</button>
</div>
<button class="btn btn-block btn-warning reload"<!-- IF !canRestart --> disabled<!-- END -->>[[admin/general/dashboard:reload]]</button>
<button class="btn btn-block btn-danger restart"<!-- IF !canRestart --> disabled<!-- END -->>[[admin/general/dashboard:restart]]</button>
</p>
<p class="help-block">
<p class="<!-- IF canRestart -->help-block<!-- ELSE -->alert alert-warning<!-- END -->">
<!-- IF canRestart -->
[[admin/general/dashboard:restart-warning]]
<!-- ELSE -->
[[admin/general/dashboard:restart-disabled]]
<!-- END -->
</p>
<p>
<a href="{config.relative_path}/admin/settings/advanced" class="btn btn-info btn-block" data-placement="bottom" data-toggle="tooltip" title="[[admin/general/dashboard:maintenance-mode-title]]">[[admin/general/dashboard:maintenance-mode]]</a>