Merge remote-tracking branch 'origin/master' into user-blocking

v1.18.x
Julian Lam 7 years ago
commit 3951bb9532

@ -73,9 +73,9 @@
"nodebb-plugin-spam-be-gone": "0.5.3", "nodebb-plugin-spam-be-gone": "0.5.3",
"nodebb-rewards-essentials": "0.0.11", "nodebb-rewards-essentials": "0.0.11",
"nodebb-theme-lavender": "5.0.4", "nodebb-theme-lavender": "5.0.4",
"nodebb-theme-persona": "8.0.10", "nodebb-theme-persona": "8.0.11",
"nodebb-theme-slick": "1.2.1", "nodebb-theme-slick": "1.2.1",
"nodebb-theme-vanilla": "9.0.7", "nodebb-theme-vanilla": "9.0.8",
"nodebb-widget-essentials": "4.0.2", "nodebb-widget-essentials": "4.0.2",
"nodemailer": "4.4.1", "nodemailer": "4.4.1",
"passport": "^0.4.0", "passport": "^0.4.0",

@ -44,6 +44,8 @@
"alert.package-manager-unreachable": "<p>NodeBB could not reach the package manager, an upgrade is not suggested at this time.</p>", "alert.package-manager-unreachable": "<p>NodeBB could not reach the package manager, an upgrade is not suggested at this time.</p>",
"alert.incompatible": "<p>Your version of NodeBB (v%1) is only cleared to upgrade to v%2 of this plugin. Please update your NodeBB if you wish to install a newer version of this plugin.</p>", "alert.incompatible": "<p>Your version of NodeBB (v%1) is only cleared to upgrade to v%2 of this plugin. Please update your NodeBB if you wish to install a newer version of this plugin.</p>",
"alert.possibly-incompatible": "<div class=\"alert alert-warning\"><p><strong>No Compatibility Information Found</strong></p><p>This plugin did not specify a specific version for installation given your NodeBB version. Full compatibility cannot be guaranteed, and may cause your NodeBB to no longer start properly.</p></div><p>In the event that NodeBB cannot boot properly:</p><pre><code>$ ./nodebb reset plugin=\"%1\"</code></pre><p>Continue installation of latest version of this plugin?</p>", "alert.possibly-incompatible": "<div class=\"alert alert-warning\"><p><strong>No Compatibility Information Found</strong></p><p>This plugin did not specify a specific version for installation given your NodeBB version. Full compatibility cannot be guaranteed, and may cause your NodeBB to no longer start properly.</p></div><p>In the event that NodeBB cannot boot properly:</p><pre><code>$ ./nodebb reset plugin=\"%1\"</code></pre><p>Continue installation of latest version of this plugin?</p>",
"alert.reorder": "Plugins Re-ordered",
"alert.reorder-success": "Please rebuild and restart your NodeBB to fully complete the process.",
"license.title": "Plugin License Information", "license.title": "Plugin License Information",
"license.intro": "The plugin <strong>%1</strong> is licensed under the %2. Please read and understand the license terms prior to activating this plugin.", "license.intro": "The plugin <strong>%1</strong> is licensed under the %2. Please read and understand the license terms prior to activating this plugin.",

@ -150,5 +150,7 @@
"diffs.title": "Post Edit History", "diffs.title": "Post Edit History",
"diffs.description": "This post has <strong>%1</strong> revisions. Click one of the revisions below to see the post content at that point in time.", "diffs.description": "This post has <strong>%1</strong> revisions. Click one of the revisions below to see the post content at that point in time.",
"diffs.no-revisions-description": "This post has <strong>%1</strong> revisions." "diffs.no-revisions-description": "This post has <strong>%1</strong> revisions.",
"diffs.current-revision": "current revision",
"diffs.original-revision": "original revision"
} }

@ -3,7 +3,7 @@
"sorting.post-default": "默认帖子排序", "sorting.post-default": "默认帖子排序",
"sorting.oldest-to-newest": "从旧到新", "sorting.oldest-to-newest": "从旧到新",
"sorting.newest-to-oldest": "从新到旧", "sorting.newest-to-oldest": "从新到旧",
"sorting.most-votes": "最多投票", "sorting.most-votes": "最多赞同",
"sorting.most-posts": "最多回复", "sorting.most-posts": "最多回复",
"sorting.topic-default": "默认主题排序", "sorting.topic-default": "默认主题排序",
"length": "帖子长度", "length": "帖子长度",

@ -53,7 +53,7 @@
"topics": "主题", "topics": "主题",
"posts": "帖子", "posts": "帖子",
"best": "最佳", "best": "最佳",
"votes": "投票", "votes": "赞同",
"upvoters": "顶的人", "upvoters": "顶的人",
"upvoted": "顶", "upvoted": "顶",
"downvoters": "踩的人", "downvoters": "踩的人",

@ -118,7 +118,7 @@
"sort_by": "排序", "sort_by": "排序",
"oldest_to_newest": "从旧到新", "oldest_to_newest": "从旧到新",
"newest_to_oldest": "从新到旧", "newest_to_oldest": "从新到旧",
"most_votes": "最多投票", "most_votes": "最多赞同",
"most_posts": "最多回复", "most_posts": "最多回复",
"stale.title": "接受建议并创建新主题?", "stale.title": "接受建议并创建新主题?",
"stale.warning": "您回复的主题已经很古老了,是否发布新主题并引用此主题的内容?", "stale.warning": "您回复的主题已经很古老了,是否发布新主题并引用此主题的内容?",

@ -182,6 +182,19 @@ define('admin/extend/plugins', ['jqueryui', 'translator', 'benchpress'], functio
return app.alertError(err.message); return app.alertError(err.message);
} }
$('#order-active-plugins-modal').modal('hide'); $('#order-active-plugins-modal').modal('hide');
app.alert({
alert_id: 'plugin_reordered',
title: '[[admin/extend/plugins:alert.reorder]]',
message: '[[admin/extend/plugins:alert.reorder-success]]',
type: 'success',
timeout: 5000,
clickfn: function () {
require(['admin/modules/instance'], function (instance) {
instance.rebuildAndRestart();
});
},
});
}); });
}); });

@ -15,6 +15,8 @@ define('forum/topic/diffs', ['forum/topic/images', 'benchpress', 'translator'],
return app.alertError(err.message); return app.alertError(err.message);
} }
timestamps.unshift(Date.now());
Benchpress.parse('partials/modals/post_history', { Benchpress.parse('partials/modals/post_history', {
diffs: timestamps.map(function (timestamp) { diffs: timestamps.map(function (timestamp) {
timestamp = parseInt(timestamp, 10); timestamp = parseInt(timestamp, 10);

@ -9,6 +9,7 @@ var meta = require('../../meta');
var plugins = require('../../plugins'); var plugins = require('../../plugins');
var privileges = require('../../privileges'); var privileges = require('../../privileges');
var categories = require('../../categories'); var categories = require('../../categories');
var notifications = require('../../notifications');
var db = require('../../database'); var db = require('../../database');
var helpers = require('../helpers'); var helpers = require('../helpers');
var accountHelpers = require('./helpers'); var accountHelpers = require('./helpers');
@ -180,15 +181,6 @@ settingsController.get = function (req, res, callback) {
}; };
function getNotificationSettings(userData, callback) { function getNotificationSettings(userData, callback) {
var types = [
'notificationType_upvote',
'notificationType_new-topic',
'notificationType_new-reply',
'notificationType_follow',
'notificationType_new-chat',
'notificationType_group-invite',
];
var privilegedTypes = []; var privilegedTypes = [];
async.waterfall([ async.waterfall([
@ -206,8 +198,7 @@ function getNotificationSettings(userData, callback) {
privilegedTypes.push('notificationType_new-user-flag'); privilegedTypes.push('notificationType_new-user-flag');
} }
plugins.fireHook('filter:user.notificationTypes', { plugins.fireHook('filter:user.notificationTypes', {
userData: userData, types: notifications.baseTypes.slice(),
types: types,
privilegedTypes: privilegedTypes, privilegedTypes: privilegedTypes,
}, next); }, next);
}, },

@ -4,7 +4,7 @@ var async = require('async');
var meta = require('../../meta'); var meta = require('../../meta');
var emailer = require('../../emailer'); var emailer = require('../../emailer');
var plugins = require('../../plugins'); var notifications = require('../../notifications');
var settingsController = module.exports; var settingsController = module.exports;
@ -45,32 +45,12 @@ function renderEmail(req, res, next) {
} }
function renderUser(req, res, next) { function renderUser(req, res, next) {
var types = [
'notificationType_upvote',
'notificationType_new-topic',
'notificationType_new-reply',
'notificationType_follow',
'notificationType_new-chat',
'notificationType_group-invite',
];
var privilegedTypes = [
'notificationType_new-register',
'notificationType_post-queue',
'notificationType_new-post-flag',
'notificationType_new-user-flag',
];
async.waterfall([ async.waterfall([
function (next) { function (next) {
plugins.fireHook('filter:user.notificationTypes', { notifications.getAllNotificationTypes(next);
userData: {},
types: types,
privilegedTypes: privilegedTypes,
}, next);
}, },
function (results) { function (notificationTypes) {
var notificationSettings = results.types.concat(results.privilegedTypes).map(function (type) { var notificationSettings = notificationTypes.map(function (type) {
return { return {
name: type, name: type,
label: '[[notifications:' + type + ']]', label: '[[notifications:' + type + ']]',

@ -11,6 +11,7 @@ var _ = require('lodash');
var plugins = require('../plugins'); var plugins = require('../plugins');
var file = require('../file'); var file = require('../file');
var db = require('../database');
var viewsPath = nconf.get('views_dir'); var viewsPath = nconf.get('views_dir');
@ -44,20 +45,22 @@ function processImports(paths, templatePath, source, callback) {
} }
Templates.processImports = processImports; Templates.processImports = processImports;
function getTemplateDirs(callback) { function getTemplateDirs(activePlugins, callback) {
var pluginTemplates = _.values(plugins.pluginsData) var pluginTemplates = activePlugins.map(function (id) {
.filter(function (pluginData) { if (id.startsWith('nodebb-theme-')) {
return !pluginData.id.startsWith('nodebb-theme-'); return nconf.get('theme_templates_path');
}) }
.map(function (pluginData) { if (!plugins.pluginsData[id]) {
return path.join(__dirname, '../../node_modules/', pluginData.id, pluginData.templates || 'templates'); return '';
}); }
return path.join(__dirname, '../../node_modules/', id, plugins.pluginsData[id].templates || 'templates');
}).filter(Boolean);
var themeConfig = require(nconf.get('theme_config')); var themeConfig = require(nconf.get('theme_config'));
var theme = themeConfig.baseTheme; var theme = themeConfig.baseTheme;
var themePath; var themePath;
var themeTemplates = [nconf.get('theme_templates_path')]; var themeTemplates = [];
while (theme) { while (theme) {
themePath = path.join(nconf.get('themes_path'), theme); themePath = path.join(nconf.get('themes_path'), theme);
themeConfig = require(path.join(themePath, 'theme.json')); themeConfig = require(path.join(themePath, 'theme.json'));
@ -118,6 +121,9 @@ function compile(callback) {
function (next) { function (next) {
mkdirp(viewsPath, function (err) { next(err); }); mkdirp(viewsPath, function (err) { next(err); });
}, },
function (next) {
db.getSortedSetRange('plugins:active', 0, -1, next);
},
getTemplateDirs, getTemplateDirs,
getTemplateFiles, getTemplateFiles,
function (files, next) { function (files, next) {

@ -17,6 +17,36 @@ var emailer = require('./emailer');
var Notifications = module.exports; var Notifications = module.exports;
Notifications.baseTypes = [
'notificationType_upvote',
'notificationType_new-topic',
'notificationType_new-reply',
'notificationType_follow',
'notificationType_new-chat',
'notificationType_group-invite',
];
Notifications.privilegedTypes = [
'notificationType_new-register',
'notificationType_post-queue',
'notificationType_new-post-flag',
'notificationType_new-user-flag',
];
Notifications.getAllNotificationTypes = function (callback) {
async.waterfall([
function (next) {
plugins.fireHook('filter:user.notificationTypes', {
types: Notifications.baseTypes.slice(),
privilegedTypes: Notifications.privilegedTypes.slice(),
}, next);
},
function (results, next) {
next(null, results.types.concat(results.privilegedTypes));
},
], callback);
};
Notifications.startJobs = function () { Notifications.startJobs = function () {
winston.verbose('[notifications.init] Registering jobs.'); winston.verbose('[notifications.init] Registering jobs.');
new cron('*/30 * * * *', Notifications.prune, null, true); new cron('*/30 * * * *', Notifications.prune, null, true);

@ -27,7 +27,7 @@ Diffs.get = function (pid, since, callback) {
function (timestamps, next) { function (timestamps, next) {
// Pass those made after `since`, and create keys // Pass those made after `since`, and create keys
const keys = timestamps.filter(function (timestamp) { const keys = timestamps.filter(function (timestamp) {
return (parseInt(timestamp, 10) || 0) > since; return (parseInt(timestamp, 10) || 0) >= since;
}).map(function (timestamp) { }).map(function (timestamp) {
return 'diff:' + pid + '.' + timestamp; return 'diff:' + pid + '.' + timestamp;
}); });

@ -59,7 +59,7 @@ function postReply(socket, data, callback) {
next(null, postData); next(null, postData);
websockets.in('uid_' + socket.uid).emit('event:new_post', result); socket.emit('event:new_post', result);
user.updateOnlineUsers(socket.uid); user.updateOnlineUsers(socket.uid);

@ -9,7 +9,13 @@ module.exports = {
name: 'Delete accidentally long-lived sessions', name: 'Delete accidentally long-lived sessions',
timestamp: Date.UTC(2017, 3, 16), timestamp: Date.UTC(2017, 3, 16),
method: function (callback) { method: function (callback) {
var configJSON = require('../../../config.json'); var configJSON;
try {
configJSON = require('../../../config.json') || { [process.env.database]: true };
} catch (err) {
configJSON = { [process.env.database]: true };
}
var isRedisSessionStore = configJSON.hasOwnProperty('redis'); var isRedisSessionStore = configJSON.hasOwnProperty('redis');
var progress = this.progress; var progress = this.progress;

@ -8,7 +8,12 @@ module.exports = {
name: 'Change the schema of simple keys so they don\'t use value field (mongodb only)', name: 'Change the schema of simple keys so they don\'t use value field (mongodb only)',
timestamp: Date.UTC(2017, 11, 18), timestamp: Date.UTC(2017, 11, 18),
method: function (callback) { method: function (callback) {
var configJSON = require('../../../config.json'); var configJSON;
try {
configJSON = require('../../../config.json') || { [process.env.database]: true, database: process.env.database };
} catch (err) {
configJSON = { [process.env.database]: true, database: process.env.database };
}
var isMongo = configJSON.hasOwnProperty('mongo') && configJSON.database === 'mongo'; var isMongo = configJSON.hasOwnProperty('mongo') && configJSON.database === 'mongo';
var progress = this.progress; var progress = this.progress;
if (!isMongo) { if (!isMongo) {

@ -6,6 +6,7 @@ var async = require('async');
var meta = require('../meta'); var meta = require('../meta');
var db = require('../database'); var db = require('../database');
var plugins = require('../plugins'); var plugins = require('../plugins');
var notifications = require('../notifications');
module.exports = function (User) { module.exports = function (User) {
User.getSettings = function (uid, callback) { User.getSettings = function (uid, callback) {
@ -81,12 +82,14 @@ module.exports = function (User) {
settings.delayImageLoading = parseInt(getSetting(settings, 'delayImageLoading', 1), 10) === 1; settings.delayImageLoading = parseInt(getSetting(settings, 'delayImageLoading', 1), 10) === 1;
settings.bootswatchSkin = settings.bootswatchSkin || meta.config.bootswatchSkin || 'default'; settings.bootswatchSkin = settings.bootswatchSkin || meta.config.bootswatchSkin || 'default';
settings.scrollToMyPost = parseInt(getSetting(settings, 'scrollToMyPost', 1), 10) === 1; settings.scrollToMyPost = parseInt(getSetting(settings, 'scrollToMyPost', 1), 10) === 1;
settings.notificationType_upvote = getSetting(settings, 'notificationType_upvote', 'notification');
settings['notificationType_new-topic'] = getSetting(settings, 'notificationType_new-topic', 'notification'); notifications.getAllNotificationTypes(next);
settings['notificationType_new-reply'] = getSetting(settings, 'notificationType_new-reply', 'notification'); },
settings.notificationType_follow = getSetting(settings, 'notificationType_follow', 'notification'); function (notificationTypes, next) {
settings['notificationType_new-chat'] = getSetting(settings, 'notificationType_new-chat', 'notification'); notificationTypes.forEach(function (notificationType) {
settings['notificationType_group-invite'] = getSetting(settings, 'notificationType_group-invite', 'notification'); settings[notificationType] = getSetting(settings, notificationType, 'notification');
});
next(null, settings); next(null, settings);
}, },
], callback); ], callback);
@ -139,26 +142,20 @@ module.exports = function (User) {
upvoteNotifFreq: data.upvoteNotifFreq, upvoteNotifFreq: data.upvoteNotifFreq,
}; };
var notificationTypes = [
'notificationType_upvote', 'notificationType_new-topic', 'notificationType_new-reply',
'notificationType_follow', 'notificationType_new-chat', 'notificationType_group-invite',
'notificationType_new-register', 'notificationType_post-queue', 'notificationType_new-post-flag',
'notificationType_new-user-flag',
];
notificationTypes.forEach(function (notificationType) {
if (data[notificationType]) {
settings[notificationType] = data[notificationType];
}
});
if (data.bootswatchSkin) { if (data.bootswatchSkin) {
settings.bootswatchSkin = data.bootswatchSkin; settings.bootswatchSkin = data.bootswatchSkin;
} }
async.waterfall([ async.waterfall([
function (next) { function (next) {
notifications.getAllNotificationTypes(next);
},
function (notificationTypes, next) {
notificationTypes.forEach(function (notificationType) {
if (data[notificationType]) {
settings[notificationType] = data[notificationType];
}
});
plugins.fireHook('filter:user.saveSettings', { settings: settings, data: data }, next); plugins.fireHook('filter:user.saveSettings', { settings: settings, data: data }, next);
}, },
function (result, next) { function (result, next) {

@ -1,6 +1,6 @@
<script> <script>
window.addEventListener('load', function () { window.addEventListener('load', function () {
define('/assets/templates/500.js', function () { define(config.relative_path + '/assets/templates/500.js', function () {
function compiled(helpers, context, get, iter, helper) { function compiled(helpers, context, get, iter, helper) {
return '<div class="alert alert-danger">\n\t<strong>[[global:500.title]]</strong>\n\t<p>[[global:500.message]]</p>\n\t<p>' + return '<div class="alert alert-danger">\n\t<strong>[[global:500.title]]</strong>\n\t<p>[[global:500.message]]</p>\n\t<p>' +
helpers.__escape(get(context && context['path'])) + '</p>\n\t' + helpers.__escape(get(context && context['path'])) + '</p>\n\t' +

@ -1080,14 +1080,12 @@ describe('Topic\'s', function () {
}); });
it('should mark topic notifications read', function (done) { it('should mark topic notifications read', function (done) {
var socketPosts = require('../src/socket.io/posts');
async.waterfall([ async.waterfall([
function (next) { function (next) {
socketTopics.follow({ uid: adminUid }, tid, next); socketTopics.follow({ uid: adminUid }, tid, next);
}, },
function (next) { function (next) {
socketPosts.reply({ uid: uid }, { content: 'some content', tid: tid }, next); topics.reply({ uid: uid, timestamp: Date.now(), content: 'some content', tid: tid }, next);
}, },
function (data, next) { function (data, next) {
setTimeout(next, 2500); setTimeout(next, 2500);

Loading…
Cancel
Save