From 5d28dbb0a4220bee91f4b39c86c299ceb90ffd2c Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 12 Sep 2016 19:10:35 -0400 Subject: [PATCH 01/60] closes #5027 --- src/meta/tags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meta/tags.js b/src/meta/tags.js index 7f00b0c012..15b2135b21 100644 --- a/src/meta/tags.js +++ b/src/meta/tags.js @@ -14,7 +14,7 @@ module.exports = function(Meta) { tags: function(next) { var defaultTags = [{ name: 'viewport', - content: 'width=device-width, initial-scale=1.0, user-scalable=no' + content: 'width=device-width, initial-scale=1.0' }, { name: 'content-type', content: 'text/html; charset=UTF-8', From becacdefb055800104c14b4fe3fbc88509ab8ff3 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 13 Sep 2016 14:23:45 +0300 Subject: [PATCH 02/60] new hooks to customize registration queue with custom data --- src/controllers/admin/users.js | 7 ++++++- src/user/approval.js | 14 +++++++++++--- src/views/admin/manage/registration.tpl | 8 ++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/controllers/admin/users.js b/src/controllers/admin/users.js index bbfa71df95..6be5af1e73 100644 --- a/src/controllers/admin/users.js +++ b/src/controllers/admin/users.js @@ -6,7 +6,7 @@ var meta = require('../../meta'); var db = require('../../database'); var pagination = require('../../pagination'); var events = require('../../events'); - +var plugins = require('../../plugins'); var usersController = {}; @@ -87,6 +87,7 @@ usersController.registrationQueue = function(req, res, next) { var start = (page - 1) * 20; var stop = start + itemsPerPage - 1; var invitations; + async.parallel({ registrationQueueCount: function(next) { db.sortedSetCard('registration:queue', next); @@ -94,6 +95,9 @@ usersController.registrationQueue = function(req, res, next) { users: function(next) { user.getRegistrationQueue(start, stop, next); }, + customHeaders: function(next) { + plugins.fireHook('filter:admin.registrationQueue.customHeaders', {headers: []}, next); + }, invites: function(next) { async.waterfall([ function(next) { @@ -132,6 +136,7 @@ usersController.registrationQueue = function(req, res, next) { } var pageCount = Math.max(1, Math.ceil(data.registrationQueueCount / itemsPerPage)); data.pagination = pagination.create(page, pageCount); + data.customHeaders = data.customHeaders.headers; res.render('admin/manage/registration', data); }); }; diff --git a/src/user/approval.js b/src/user/approval.js index 95b2daa68b..25dcf3479a 100644 --- a/src/user/approval.js +++ b/src/user/approval.js @@ -11,7 +11,7 @@ var notifications = require('../notifications'); var groups = require('../groups'); var translator = require('../../public/src/modules/translator'); var utils = require('../../public/src/utils'); - +var plugins = require('../plugins'); module.exports = function(User) { @@ -31,8 +31,10 @@ module.exports = function(User) { ip: userData.ip, hashedPassword: hashedPassword }; - - db.setObject('registration:queue:name:' + userData.username, data, next); + plugins.fireHook('filter:user.addToApprovalQueue', {data: data, userData: userData}, next); + }, + function(results, next) { + db.setObject('registration:queue:name:' + userData.username, results.data, next); }, function(next) { db.sortedSetAdd('registration:queue', Date.now(), userData.username, next); @@ -206,6 +208,12 @@ module.exports = function(User) { next(err, user); }); }, next); + }, + function(users, next) { + plugins.fireHook('filter:user.getRegistrationQueue', {users: users}, next); + }, + function(results, next) { + next(null, results.users); } ], callback); }; diff --git a/src/views/admin/manage/registration.tpl b/src/views/admin/manage/registration.tpl index 5944219794..99c6517c93 100644 --- a/src/views/admin/manage/registration.tpl +++ b/src/views/admin/manage/registration.tpl @@ -15,6 +15,9 @@ Email IP Time + + {customHeaders.label} + @@ -55,6 +58,11 @@ + + + {users.customRows.value} + +
From f47f93f9bbada642615c5c7cd4f9100df37bac8f Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 13 Sep 2016 14:43:03 +0300 Subject: [PATCH 03/60] up widget essentials --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0dfef19c29..b106e79057 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "nodebb-theme-lavender": "3.0.14", "nodebb-theme-persona": "4.1.43", "nodebb-theme-vanilla": "5.1.27", - "nodebb-widget-essentials": "2.0.10", + "nodebb-widget-essentials": "2.0.11", "nodemailer": "2.0.0", "nodemailer-sendmail-transport": "1.0.0", "nodemailer-smtp-transport": "^2.4.1", From 30da4ac748cca224b2a3f985fe0ec8a7e76a3067 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 13 Sep 2016 22:54:40 -0400 Subject: [PATCH 04/60] closes #5031 --- public/src/admin/admin.js | 2 +- public/src/admin/appearance/themes.js | 8 +++++--- public/src/client/topic/flag.js | 6 ++++-- public/src/client/topic/move.js | 18 ++++++++++-------- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/public/src/admin/admin.js b/public/src/admin/admin.js index add13c30cc..5647f8b2d7 100644 --- a/public/src/admin/admin.js +++ b/public/src/admin/admin.js @@ -1,5 +1,5 @@ "use strict"; -/*global config, translator, componentHandler, define, socket, app, ajaxify, utils, bootbox, Slideout, NProgress, RELATIVE_PATH*/ +/*global config, componentHandler, define, socket, app, ajaxify, utils, bootbox, Slideout, NProgress, RELATIVE_PATH*/ (function() { var logoutTimer = 0; diff --git a/public/src/admin/appearance/themes.js b/public/src/admin/appearance/themes.js index 901f64b688..0d4e403fbd 100644 --- a/public/src/admin/appearance/themes.js +++ b/public/src/admin/appearance/themes.js @@ -76,9 +76,11 @@ define('admin/appearance/themes', function() { templates.parse('admin/partials/theme_list', { themes: themes }, function(html) { - translator.translate(html, function(html) { - instListEl.html(html); - highlightSelectedTheme(config['theme:id']); + require(['translator'], function(translator) { + translator.translate(html, function(html) { + instListEl.html(html); + highlightSelectedTheme(config['theme:id']); + }); }); }); } diff --git a/public/src/client/topic/flag.js b/public/src/client/topic/flag.js index 3101c0cd1c..9d07330289 100644 --- a/public/src/client/topic/flag.js +++ b/public/src/client/topic/flag.js @@ -1,6 +1,6 @@ 'use strict'; -/* globals define, app, socket, templates, translator */ +/* globals define, app, socket, templates */ define('forum/topic/flag', [], function() { @@ -34,7 +34,9 @@ define('forum/topic/flag', [], function() { function parseModal(callback) { templates.parse('partials/modals/flag_post_modal', {}, function(html) { - translator.translate(html, callback); + require(['translator'], function(translator) { + translator.translate(html, callback); + }); }); } diff --git a/public/src/client/topic/move.js b/public/src/client/topic/move.js index d16eb9bc41..336ea40870 100644 --- a/public/src/client/topic/move.js +++ b/public/src/client/topic/move.js @@ -1,6 +1,6 @@ 'use strict'; -/* globals define, app, socket, templates, translator */ +/* globals define, app, socket, templates */ define('forum/topic/move', function() { @@ -46,14 +46,16 @@ define('forum/topic/move', function() { function parseModal(categories, callback) { templates.parse('partials/move_thread_modal', {categories: []}, function(html) { - translator.translate(html, function(html) { - modal = $(html); - categories.forEach(function(category) { - if (!category.link) { - buildRecursive(modal.find('.category-list'), category, ''); - } + require(['translator'], function(translator) { + translator.translate(html, function(html) { + modal = $(html); + categories.forEach(function(category) { + if (!category.link) { + buildRecursive(modal.find('.category-list'), category, ''); + } + }); + callback(); }); - callback(); }); }); } From ea6a1b774171a71b1c4c0e03523f649ce08dd882 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 13:07:15 +0300 Subject: [PATCH 05/60] new language strings --- public/language/en_GB/error.json | 1 + public/language/en_GB/modules.json | 1 + 2 files changed, 2 insertions(+) diff --git a/public/language/en_GB/error.json b/public/language/en_GB/error.json index a5e7cf9cbe..a7f47b9ac3 100644 --- a/public/language/en_GB/error.json +++ b/public/language/en_GB/error.json @@ -76,6 +76,7 @@ "title-too-short": "Please enter a longer title. Titles should contain at least %1 character(s).", "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 character(s).", "invalid-title": "Invalid title!", + "category-not-selected": "Category not selected.", "too-many-posts": "You can only post once every %1 second(s) - please wait before posting again", "too-many-posts-newbie": "As a new user, you can only post once every %1 second(s) until you have earned %2 reputation - please wait before posting again", "tag-too-short": "Please enter a longer tag. Tags should contain at least %1 character(s)", diff --git a/public/language/en_GB/modules.json b/public/language/en_GB/modules.json index fb820534b8..363dafeada 100644 --- a/public/language/en_GB/modules.json +++ b/public/language/en_GB/modules.json @@ -39,6 +39,7 @@ "composer.upload-picture": "Upload Image", "composer.upload-file": "Upload File", "composer.zen_mode": "Zen Mode", + "composer.select_category": "Select a category", "bootbox.ok": "OK", "bootbox.cancel": "Cancel", From 001eb3454c27802dcfa76444f25523dd211b117f Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 13:08:51 +0300 Subject: [PATCH 06/60] up composer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b106e79057..9d419eaa79 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "morgan": "^1.3.2", "mousetrap": "^1.5.3", "nconf": "~0.8.2", - "nodebb-plugin-composer-default": "4.2.4", + "nodebb-plugin-composer-default": "4.2.5", "nodebb-plugin-dbsearch": "1.0.2", "nodebb-plugin-emoji-extended": "1.1.1", "nodebb-plugin-emoji-one": "1.1.5", From aefba6e2b1d54650a72c279a164e92ab62259c4c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 14:33:39 +0300 Subject: [PATCH 07/60] removed some methods helpers.getBaseUser exposeUid, exposeGroupName --- src/controllers/accounts/follow.js | 2 +- src/controllers/accounts/groups.js | 10 ++--- src/controllers/accounts/helpers.js | 67 +++------------------------- src/controllers/accounts/info.js | 47 ++++++++++--------- src/controllers/accounts/posts.js | 18 ++++---- src/controllers/accounts/session.js | 13 ++++-- src/controllers/accounts/settings.js | 2 +- src/controllers/groups.js | 31 ++++++++----- src/middleware/index.js | 22 --------- src/routes/accounts.js | 4 +- src/routes/index.js | 2 +- 11 files changed, 78 insertions(+), 140 deletions(-) diff --git a/src/controllers/accounts/follow.js b/src/controllers/accounts/follow.js index 5897347a12..f54d825081 100644 --- a/src/controllers/accounts/follow.js +++ b/src/controllers/accounts/follow.js @@ -27,7 +27,7 @@ function getFollow(tpl, name, req, res, callback) { async.waterfall([ function(next) { - accountHelpers.getBaseUser(req.params.userslug, req.uid, next); + accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, next); }, function(data, next) { userData = data; diff --git a/src/controllers/accounts/groups.js b/src/controllers/accounts/groups.js index e19034c908..7957b3c251 100644 --- a/src/controllers/accounts/groups.js +++ b/src/controllers/accounts/groups.js @@ -1,11 +1,11 @@ 'use strict'; -var async = require('async'), +var async = require('async'); - groups = require('../../groups'), - helpers = require('../helpers'), - accountHelpers = require('./helpers'); +var groups = require('../../groups'); +var helpers = require('../helpers'); +var accountHelpers = require('./helpers'); var groupsController = {}; @@ -15,7 +15,7 @@ groupsController.get = function(req, res, callback) { var groupsData; async.waterfall([ function (next) { - accountHelpers.getBaseUser(req.params.userslug, req.uid, next); + accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, next); }, function (_userData, next) { userData = _userData; diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index fc78f3af91..b54af6da13 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -3,6 +3,7 @@ var async = require('async'); var validator = require('validator'); +var winston = require('winston'); var user = require('../../user'); var groups = require('../../groups'); @@ -35,6 +36,9 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) { isGlobalModerator: function(next) { user.isGlobalModerator(callerUID, next); }, + isFollowing: function(next) { + user.isFollowing(callerUID, uid, next); + }, ips: function(next) { user.getIPs(uid, 4, next); }, @@ -88,6 +92,7 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) { userData.canBan = isAdmin || isGlobalModerator; userData.canChangePassword = isAdmin || (isSelf && parseInt(meta.config['password:disableEdit'], 10) !== 1); userData.isSelf = isSelf; + userData.isFollowing = results.isFollowing; userData.showHidden = isSelf || isAdmin || isGlobalModerator; userData.groups = Array.isArray(results.groups) && results.groups.length ? results.groups[0] : []; userData.disableSignatures = meta.config.disableSignatures !== undefined && parseInt(meta.config.disableSignatures, 10) === 1; @@ -122,66 +127,8 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) { helpers.getBaseUser = function(userslug, callerUID, callback) { - async.waterfall([ - function (next) { - user.getUidByUserslug(userslug, next); - }, - function (uid, next) { - if (!uid) { - return callback(null, null); - } - - async.parallel({ - user: function(next) { - user.getUserFields(uid, [ - 'uid', - 'username', - 'userslug', - 'picture', - 'cover:url', - 'cover:position', - 'status', - 'lastonline', - 'groupTitle', - 'followingCount', - 'followerCount' - ], next); - }, - isAdmin: function(next) { - user.isAdministrator(callerUID, next); - }, - isGlobalModerator: function(next) { - user.isGlobalModerator(callerUID, next); - }, - isFollowing: function(next) { - user.isFollowing(callerUID, uid, next); - }, - profile_links: function(next) { - plugins.fireHook('filter:user.profileLinks', [], next); - } - }, next); - }, - function (results, next) { - if (!results.user) { - return callback(); - } - - results.user.yourid = callerUID; - results.user.theirid = results.user.uid; - results.user.status = user.getStatus(results.user); - results.user.isSelf = parseInt(callerUID, 10) === parseInt(results.user.uid, 10); - results.user.isFollowing = results.isFollowing; - results.user.showHidden = results.user.isSelf || results.isAdmin || results.isGlobalModerator; - results.user.profile_links = filterLinks(results.profile_links, results.user.isSelf); - - results.user['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1; - results.user['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1; - results.user['cover:url'] = results.user['cover:url'] || require('../../coverPhoto').getDefaultProfileCover(results.user.uid); - results.user['cover:position'] = results.user['cover:position'] || '50% 50%'; - - next(null, results.user); - } - ], callback); + winston.warn('helpers.getBaseUser deprecated please use helpers.getUserDataByUserSlug'); + helpers.getUserDataByUserSlug(userslug, callerUID, callback); }; function filterLinks(links, self) { diff --git a/src/controllers/accounts/info.js b/src/controllers/accounts/info.js index b39c82f939..117c7ad47c 100644 --- a/src/controllers/accounts/info.js +++ b/src/controllers/accounts/info.js @@ -1,7 +1,6 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); var user = require('../../user'); var helpers = require('../helpers'); @@ -9,33 +8,33 @@ var accountHelpers = require('./helpers'); var infoController = {}; -infoController.get = function(req, res, next) { - accountHelpers.getBaseUser(req.params.userslug, req.uid, function(err, userData) { +infoController.get = function(req, res, callback) { + var userData; + async.waterfall([ + function(next) { + accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, next); + }, + function(_userData, next) { + userData = _userData; + if (!userData) { + return callback(); + } + async.parallel({ + history: async.apply(user.getModerationHistory, userData.uid), + sessions: async.apply(user.auth.getSessions, userData.uid, req.sessionID) + }, next); + } + ], function(err, data) { if (err) { - return next(err); + return callback(err); } - async.parallel({ - ips: async.apply(user.getIPs, res.locals.uid, 4), - history: async.apply(user.getModerationHistory, res.locals.uid), - fields: async.apply(user.getUserFields, res.locals.uid, ['banned']), - sessions: async.apply(user.auth.getSessions, userData.uid, req.sessionID) - }, function(err, data) { - if (err) { - return next(err); - } + userData.history = data.history; + userData.sessions = data.sessions; + userData.title = '[[pages:account/info]]'; + userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[user:account_info]]'}]); - userData = _.extend(userData, { - ips: data.ips, - history: data.history - }, data.fields); - - userData.sessions = data.sessions; - userData.title = '[[pages:account/info]]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[user:account_info]]'}]); - - res.render('account/info', userData); - }); + res.render('account/info', userData); }); }; diff --git a/src/controllers/accounts/posts.js b/src/controllers/accounts/posts.js index 7e1e67a8bd..08737f0cde 100644 --- a/src/controllers/accounts/posts.js +++ b/src/controllers/accounts/posts.js @@ -1,15 +1,15 @@ 'use strict'; -var async = require('async'), +var async = require('async'); - db = require('../../database'), - user = require('../../user'), - posts = require('../../posts'), - topics = require('../../topics'), - pagination = require('../../pagination'), - helpers = require('../helpers'), - accountHelpers = require('./helpers'); +var db = require('../../database'); +var user = require('../../user'); +var posts = require('../../posts'); +var topics = require('../../topics'); +var pagination = require('../../pagination'); +var helpers = require('../helpers'); +var accountHelpers = require('./helpers'); var postsController = {}; @@ -103,7 +103,7 @@ function getFromUserSet(data, req, res, next) { user.getSettings(req.uid, next); }, userData: function(next) { - accountHelpers.getBaseUser(req.params.userslug, req.uid, next); + accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, next); } }, function(err, results) { if (err || !results.userData) { diff --git a/src/controllers/accounts/session.js b/src/controllers/accounts/session.js index dd9f0f4a88..20c32909df 100644 --- a/src/controllers/accounts/session.js +++ b/src/controllers/accounts/session.js @@ -13,10 +13,17 @@ sessionController.revoke = function(req, res, next) { } var _id; - + var uid; async.waterfall([ function (next) { - db.getSortedSetRange('uid:' + res.locals.uid + ':sessions', 0, -1, next); + user.getUidByUserslug(req.params.userslug, next); + }, + function (_uid, next) { + uid = _uid; + if (!uid) { + return next(new Error('[[error:no-session-found]]')); + } + db.getSortedSetRange('uid:' + uid + ':sessions', 0, -1, next); }, function (sids, done) { async.eachSeries(sids, function(sid, next) { @@ -38,7 +45,7 @@ sessionController.revoke = function(req, res, next) { return next(new Error('[[error:no-session-found]]')); } - user.auth.revokeSession(_id, res.locals.uid, next); + user.auth.revokeSession(_id, uid, next); } ], function(err) { if (err) { diff --git a/src/controllers/accounts/settings.js b/src/controllers/accounts/settings.js index e491d67efd..9b16050934 100644 --- a/src/controllers/accounts/settings.js +++ b/src/controllers/accounts/settings.js @@ -20,7 +20,7 @@ settingsController.get = function(req, res, callback) { var userData; async.waterfall([ function(next) { - accountHelpers.getBaseUser(req.params.userslug, req.uid, next); + accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, next); }, function(_userData, next) { userData = _userData; diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 294e9ac1fc..4f87045344 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -46,23 +46,30 @@ groupsController.getGroupsFromSet = function(uid, sort, start, stop, callback) { }; groupsController.details = function(req, res, callback) { + var groupName; async.waterfall([ - async.apply(groups.exists, res.locals.groupName), - function (exists, next) { - if (!exists) { + function(next) { + groups.getGroupNameByGroupSlug(req.params.slug, next); + }, + function(groupName, next) { + if (!groupName) { return callback(); } - - groups.isHidden(res.locals.groupName, next); + async.parallel({ + exists: async.apply(groups.exists, groupName), + hidden: async.apply(groups.isHidden, groupName) + }, next); }, - function (hidden, next) { - if (!hidden) { + function (results, next) { + if (!results.exists) { + return callback(); + } + if (!results.hidden) { return next(); } - async.parallel({ - isMember: async.apply(groups.isMember, req.uid, res.locals.groupName), - isInvited: async.apply(groups.isInvited, req.uid, res.locals.groupName) + isMember: async.apply(groups.isMember, req.uid, groupName), + isInvited: async.apply(groups.isInvited, req.uid, groupName) }, function(err, checks) { if (err || checks.isMember || checks.isInvited) { return next(err); @@ -73,14 +80,14 @@ groupsController.details = function(req, res, callback) { function (next) { async.parallel({ group: function(next) { - groups.get(res.locals.groupName, { + groups.get(groupName, { uid: req.uid, truncateUserList: true, userListCount: 20 }, next); }, posts: function(next) { - groups.getLatestMemberPosts(res.locals.groupName, 10, req.uid, next); + groups.getLatestMemberPosts(groupName, 10, req.uid, next); }, isAdmin:function(next) { user.isAdministrator(req.uid, next); diff --git a/src/middleware/index.js b/src/middleware/index.js index 7d5b5a4e80..e827744017 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -112,28 +112,6 @@ middleware.privateTagListing = function(req, res, next) { } }; -middleware.exposeGroupName = function(req, res, next) { - expose('groupName', groups.getGroupNameByGroupSlug, 'slug', req, res, next); -}; - -middleware.exposeUid = function(req, res, next) { - expose('uid', user.getUidByUserslug, 'userslug', req, res, next); -}; - -function expose(exposedField, method, field, req, res, next) { - if (!req.params.hasOwnProperty(field)) { - return next(); - } - method(req.params[field], function(err, id) { - if (err) { - return next(err); - } - - res.locals[exposedField] = id; - next(); - }); -} - middleware.privateUploads = function(req, res, next) { if (req.user || parseInt(meta.config.privateUploads, 10) !== 1) { return next(); diff --git a/src/routes/accounts.js b/src/routes/accounts.js index 5bd0a474e3..7b6ead07cf 100644 --- a/src/routes/accounts.js +++ b/src/routes/accounts.js @@ -5,7 +5,7 @@ var setupPageRoute = helpers.setupPageRoute; module.exports = function (app, middleware, controllers) { var middlewares = [middleware.checkGlobalPrivacySettings]; - var accountMiddlewares = [middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, middleware.exposeUid]; + var accountMiddlewares = [middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions]; setupPageRoute(app, '/uid/:uid/:section?', middleware, [], middleware.redirectUidToUserslug); @@ -28,7 +28,7 @@ module.exports = function (app, middleware, controllers) { setupPageRoute(app, '/user/:userslug/info', middleware, accountMiddlewares, controllers.accounts.info.get); setupPageRoute(app, '/user/:userslug/settings', middleware, accountMiddlewares, controllers.accounts.settings.get); - app.delete('/api/user/:userslug/session/:uuid', [middleware.requireUser, middleware.exposeUid], controllers.accounts.session.revoke); + app.delete('/api/user/:userslug/session/:uuid', [middleware.requireUser], controllers.accounts.session.revoke); setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.notifications.get); setupPageRoute(app, '/chats/:roomid?', middleware, [middleware.authenticate], controllers.accounts.chats.get); diff --git a/src/routes/index.js b/src/routes/index.js index 00e0ea0e77..b4e1be4a5b 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -77,7 +77,7 @@ function userRoutes(app, middleware, controllers) { } function groupRoutes(app, middleware, controllers) { - var middlewares = [middleware.checkGlobalPrivacySettings, middleware.exposeGroupName]; + var middlewares = [middleware.checkGlobalPrivacySettings]; setupPageRoute(app, '/groups', middleware, middlewares, controllers.groups.list); setupPageRoute(app, '/groups/:slug', middleware, middlewares, controllers.groups.details); From ae8b9c3683fa2fa79160e432a2f4701404335068 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 15:56:35 +0300 Subject: [PATCH 08/60] closes #4665 --- src/controllers/accounts/helpers.js | 6 +++++- src/plugins/hooks.js | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index b54af6da13..29bcb1d851 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -45,6 +45,9 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) { profile_links: function(next) { plugins.fireHook('filter:user.profileLinks', [], next); }, + profile_menu: function(next) { + plugins.fireHook('filter:user.profileMenu', {uid: uid, callerUID: callerUID, links: []}, next); + }, groups: function(next) { groups.getUserGroups([uid], next); }, @@ -99,7 +102,8 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) { userData['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1; userData['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1; userData['email:confirmed'] = !!parseInt(userData['email:confirmed'], 10); - userData.profile_links = filterLinks(results.profile_links, isSelf); + userData.profile_links = filterLinks(results.profile_links.concat(results.profile_menu.links), isSelf); + userData.sso = results.sso.associations; userData.status = user.getStatus(userData); userData.banned = parseInt(userData.banned, 10) === 1; diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 111a09a86d..e7cf97b5fc 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -6,7 +6,8 @@ var winston = require('winston'), module.exports = function(Plugins) { Plugins.deprecatedHooks = { 'filter:user.custom_fields': null, // remove in v1.1.0 - 'filter:post.save': 'filter:post.create' + 'filter:post.save': 'filter:post.create', + 'filter:user.profileLinks': 'filter:user.profileMenu' }; /* `data` is an object consisting of (* is required): From dc6e4bcb67a68001bd111fc31f2f3edb6ab4ecaf Mon Sep 17 00:00:00 2001 From: NodeBB Misty Date: Wed, 14 Sep 2016 09:03:25 -0400 Subject: [PATCH 09/60] Latest translations and fallbacks --- public/language/ar/error.json | 1 + public/language/bg/error.json | 1 + public/language/bn/error.json | 1 + public/language/cs/error.json | 1 + public/language/da/error.json | 1 + public/language/de/error.json | 1 + public/language/el/error.json | 1 + public/language/en@pirate/error.json | 1 + public/language/en_US/error.json | 1 + public/language/es/error.json | 1 + public/language/et/error.json | 1 + public/language/fa_IR/error.json | 1 + public/language/fi/error.json | 1 + public/language/fr/error.json | 1 + public/language/gl/error.json | 1 + public/language/he/error.json | 1 + public/language/hu/error.json | 1 + public/language/id/error.json | 1 + public/language/it/error.json | 1 + public/language/ja/error.json | 1 + public/language/ko/error.json | 1 + public/language/lt/error.json | 1 + public/language/ms/error.json | 1 + public/language/nb/error.json | 1 + public/language/nl/error.json | 1 + public/language/pl/error.json | 1 + public/language/pt_BR/error.json | 1 + public/language/ro/error.json | 1 + public/language/ru/error.json | 1 + public/language/rw/error.json | 1 + public/language/sc/error.json | 1 + public/language/sk/error.json | 1 + public/language/sl/error.json | 1 + public/language/sr/error.json | 1 + public/language/sv/error.json | 1 + public/language/th/error.json | 1 + public/language/tr/error.json | 1 + public/language/vi/error.json | 1 + public/language/zh_CN/error.json | 1 + public/language/zh_TW/error.json | 1 + 40 files changed, 40 insertions(+) diff --git a/public/language/ar/error.json b/public/language/ar/error.json index fdd300043b..78999c99ef 100644 --- a/public/language/ar/error.json +++ b/public/language/ar/error.json @@ -29,6 +29,7 @@ "username-too-long": "اسم المستخدم طويل", "password-too-long": "كلمة السر طويلة ", "user-banned": "المستخدم محظور", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "عذرا, يجب أن تنتظر 1% ثواني قبل قيامك بأول مشاركة", "blacklisted-ip": "نأسف، لقد تم حظرك من استخدام وتصفح المنتدى. إذا كنت تعتقد أن هذا خطأ رجاءًا اتصل بالإدارة. ", "ban-expiry-missing": "رجاءًا ضع تاريخ نهاية الحظر. ", diff --git a/public/language/bg/error.json b/public/language/bg/error.json index 42e826cb48..301cd0640e 100644 --- a/public/language/bg/error.json +++ b/public/language/bg/error.json @@ -29,6 +29,7 @@ "username-too-long": "Потребителското име е твърде дълго", "password-too-long": "Паролата е твърде дълга", "user-banned": "Потребителят е блокиран", + "user-banned-reason": "Потребителят е блокиран (Причина: %1)", "user-too-new": "Съжаляваме, но трябва да изчакате поне %1 секунда/и, преди да направите първата си публикация", "blacklisted-ip": "Съжаляваме, но Вашият IP адрес е забранен за ползване в тази общност. Ако смятате, че това е грешка, моля, свържете се с администратор.", "ban-expiry-missing": "Моля, задайте крайна дата за това блокиране", diff --git a/public/language/bn/error.json b/public/language/bn/error.json index d55a11cb39..f321d4406a 100644 --- a/public/language/bn/error.json +++ b/public/language/bn/error.json @@ -29,6 +29,7 @@ "username-too-long": "ইউজারনেম বড় হয়ে গিয়েছে", "password-too-long": "Password too long", "user-banned": "ব্যবহারকারী নিষিদ্ধ", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/cs/error.json b/public/language/cs/error.json index 02627687a6..e3f4a05c9f 100644 --- a/public/language/cs/error.json +++ b/public/language/cs/error.json @@ -29,6 +29,7 @@ "username-too-long": "Uživatelské jméno je příliš dlouhé", "password-too-long": "Heslo je příliš dlouhé", "user-banned": "Uživatel byl zakázán", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/da/error.json b/public/language/da/error.json index da3251a3f7..3265c62c5a 100644 --- a/public/language/da/error.json +++ b/public/language/da/error.json @@ -29,6 +29,7 @@ "username-too-long": "Brugernavn er for langt", "password-too-long": "Kodeord er for langt", "user-banned": "Bruger er bortvist", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Beklager, du er nødt til at vente %1 sekund(er) før du opretter dit indlæg", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/de/error.json b/public/language/de/error.json index 77cea0ae9e..d833ba50dc 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -29,6 +29,7 @@ "username-too-long": "Benutzername ist zu lang", "password-too-long": "Passwort ist zu lang", "user-banned": "Benutzer ist gesperrt", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Entschuldigung, du musst %1 Sekunde(n) warten, bevor du deinen ersten Beitrag schreiben kannst.", "blacklisted-ip": "Deine IP-Adresse ist für diese Plattform gesperrt. Sollte dies ein Irrtum sein, dann kontaktiere bitte einen Administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/el/error.json b/public/language/el/error.json index 13e6988445..87c1c1e434 100644 --- a/public/language/el/error.json +++ b/public/language/el/error.json @@ -29,6 +29,7 @@ "username-too-long": "Το όνομα χρήστη είναι πολύ μεγάλο", "password-too-long": "Password too long", "user-banned": "Ο Χρήστης είναι αποκλεισμένος/η", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/en@pirate/error.json b/public/language/en@pirate/error.json index 1d2065d115..a28c95316f 100644 --- a/public/language/en@pirate/error.json +++ b/public/language/en@pirate/error.json @@ -29,6 +29,7 @@ "username-too-long": "Username too long", "password-too-long": "Password too long", "user-banned": "User banned", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/en_US/error.json b/public/language/en_US/error.json index 1d2065d115..a28c95316f 100644 --- a/public/language/en_US/error.json +++ b/public/language/en_US/error.json @@ -29,6 +29,7 @@ "username-too-long": "Username too long", "password-too-long": "Password too long", "user-banned": "User banned", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/es/error.json b/public/language/es/error.json index 288e4c4088..95830f27a1 100644 --- a/public/language/es/error.json +++ b/public/language/es/error.json @@ -29,6 +29,7 @@ "username-too-long": "Nombre de usuario demasiado largo", "password-too-long": "Contraseña muy corta", "user-banned": "Usuario baneado", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Lo sentimos, es necesario que esperes %1 segundo(s) antes poder hacer tu primera publicación", "blacklisted-ip": "Lo sentimos, tu dirección IP ha sido baneada de esta comunidad. Si crees que debe de haber un error, por favor contacte con un administrador.", "ban-expiry-missing": "Por favor pon una fecha de fin del ban", diff --git a/public/language/et/error.json b/public/language/et/error.json index 9bf49634ee..74d2ee9a29 100644 --- a/public/language/et/error.json +++ b/public/language/et/error.json @@ -29,6 +29,7 @@ "username-too-long": "Kasutajanimi on liiga pikk", "password-too-long": "Parool liiga pikk", "user-banned": "Kasutaja bannitud", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Vabandust, te peate ootama %1 sekund(it) enne esimese postituse loomist.", "blacklisted-ip": "Vabandust! Sinu IP-aadress on siin kogukonnas keelatud. Kui arvad, et see on eksitus, palun leia kontakti administraatoriga.", "ban-expiry-missing": "Palun sisesta keelu lõpukuupäev", diff --git a/public/language/fa_IR/error.json b/public/language/fa_IR/error.json index 5daaf16e9c..e1cc16e9ec 100644 --- a/public/language/fa_IR/error.json +++ b/public/language/fa_IR/error.json @@ -29,6 +29,7 @@ "username-too-long": "نام کاربری بسیار طولانیست", "password-too-long": "کلمه عبور بسیار طولانیست", "user-banned": "کاربر محروم شد.", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "با عرض پوزش، شما باید %1 ثانیه پیش از فرستادن پست نخست خود صبر کنید", "blacklisted-ip": "با عرض پوزش فراوان، نشانی آی پی شما در این انجمن مسدود شده است، اگر فکر می‌کنید اشتباهی رخ داده با مدیریت انجمن تماس بگیرید.", "ban-expiry-missing": "لطفا تاریخ پایان برای این مسدود کردن ارائه دهید", diff --git a/public/language/fi/error.json b/public/language/fi/error.json index de8e27a50d..cbeaf9533b 100644 --- a/public/language/fi/error.json +++ b/public/language/fi/error.json @@ -29,6 +29,7 @@ "username-too-long": "Käyttäjänimi on liian pitkä", "password-too-long": "Password too long", "user-banned": "Käyttäjä on estetty", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Anteeksi, mutta sinun täytyy odottaa %1 sekunti(a) ennen sinun ensimmäisen viestin lähettämistä", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/fr/error.json b/public/language/fr/error.json index e6e70bad78..a6440cb83a 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -29,6 +29,7 @@ "username-too-long": "Nom d'utilisateur trop long", "password-too-long": "Mot de passe trop long", "user-banned": "Utilisateur banni", + "user-banned-reason": "Utilisateur banni (Raison : %1)", "user-too-new": "Désolé, vous devez attendre encore %1 seconde(s) avant d'envoyer votre premier message", "blacklisted-ip": "Désolé, votre adresse IP a été bannie de cette communauté. Si vous pensez que c'est une erreur, veuillez contacter un administrateur.", "ban-expiry-missing": "Veuillez entrer une date de fin de banissement.", diff --git a/public/language/gl/error.json b/public/language/gl/error.json index acbab0cc58..b0870bda3b 100644 --- a/public/language/gl/error.json +++ b/public/language/gl/error.json @@ -29,6 +29,7 @@ "username-too-long": "Nome de usuario demasiado longo.", "password-too-long": "Contrasinal moi longa", "user-banned": "Usuario expulsado", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Desculpa, agarda %1 second(s) antes de facer a túa primeira publicación.", "blacklisted-ip": "Sentímolo, o teu enderezo IP foi baneado desta comunidade. Se crees que se debe a un erro, por favor, contacte cun administrador.", "ban-expiry-missing": "Por favor, engade unha data de fin do ban", diff --git a/public/language/he/error.json b/public/language/he/error.json index c2a970ee36..1213807b3b 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -29,6 +29,7 @@ "username-too-long": "שם משתמש ארוך מדי", "password-too-long": "הסיסמה ארוכה מדי", "user-banned": "המשתמש מושעה", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "אנא המתן %1 שניות לפני פרסום ההודעה", "blacklisted-ip": "מצטערים, אך הורחקת מקהילה זו. אם הנך סבור שמדובר בטעות, אנא צור קשר עם מנהלי הקהילה.", "ban-expiry-missing": "אנא ספק תאריך סיום להרחקה זו.", diff --git a/public/language/hu/error.json b/public/language/hu/error.json index dc2bc327f7..afd1c84a0b 100644 --- a/public/language/hu/error.json +++ b/public/language/hu/error.json @@ -29,6 +29,7 @@ "username-too-long": "Túl hosszú felhasználónév", "password-too-long": "Password too long", "user-banned": "Kitiltott felhasználó", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/id/error.json b/public/language/id/error.json index 11d0c9a830..39c2518a99 100644 --- a/public/language/id/error.json +++ b/public/language/id/error.json @@ -29,6 +29,7 @@ "username-too-long": "Username terlalu panjang", "password-too-long": "Password too long", "user-banned": "Pengguna dibanned", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/it/error.json b/public/language/it/error.json index 2971a8e20c..6bd9bef48a 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -29,6 +29,7 @@ "username-too-long": "Nome utente troppo lungo", "password-too-long": "Password troppo lunga", "user-banned": "Utente bannato", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Devi attendere %1 secondi prima di creare il tuo primo post", "blacklisted-ip": "Purtroppo il tuo indirizzo IP è stato bannato da questa community. Se credi che ci sia stato un errore contatta un amministratore.", "ban-expiry-missing": "Per favore fornisci una data finale per questo ban", diff --git a/public/language/ja/error.json b/public/language/ja/error.json index cbe33de039..67d3215940 100644 --- a/public/language/ja/error.json +++ b/public/language/ja/error.json @@ -29,6 +29,7 @@ "username-too-long": "ユーザー名が長すぎます", "password-too-long": "パスワードが長すぎます", "user-banned": "ユーザーは停止されています", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "申し訳ありません。登録後に投稿を行うには%1秒お待ち下さい。", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/ko/error.json b/public/language/ko/error.json index 383a9405a5..48643741b3 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -29,6 +29,7 @@ "username-too-long": "사용자 이름이 너무 깁니다.", "password-too-long": "패스워드가 너무 깁니다.", "user-banned": "차단된 사용자입니다.", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "죄송합니다, 첫 번째 게시물은 %1 초 후에 작성할 수 있습니다.", "blacklisted-ip": "죄송하지만, 당신의 IP는 이 커뮤니티로부터 차단되었습니다. 만약 에러라는 생각이 드신다면 관리자에게 연락해주세요.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/lt/error.json b/public/language/lt/error.json index 2d5b6ecf02..aada6824bf 100644 --- a/public/language/lt/error.json +++ b/public/language/lt/error.json @@ -29,6 +29,7 @@ "username-too-long": "Vartotojo vardas per ilgas", "password-too-long": "Password too long", "user-banned": "Vartotojas užblokuotas", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Atsiprašome, jūs įpareigoti palaukti %1 sekunde(s) prieš rašant pirmą pranešimą", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/ms/error.json b/public/language/ms/error.json index 826b75b19a..c6874b35aa 100644 --- a/public/language/ms/error.json +++ b/public/language/ms/error.json @@ -29,6 +29,7 @@ "username-too-long": "Nama pengunna terlalu panjang", "password-too-long": "Kata laluan terlalu panjang", "user-banned": "Pengguna diharamkan", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Maaf, anda dikehendaki menunggu %1 saat() sebelum membuat kiriman pertama anda", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/nb/error.json b/public/language/nb/error.json index b9aa7192cb..1fd4792c83 100644 --- a/public/language/nb/error.json +++ b/public/language/nb/error.json @@ -29,6 +29,7 @@ "username-too-long": "Brukernavnet er for langt", "password-too-long": "Password too long", "user-banned": "Bruker utestengt", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Beklager, du må vente %1 sekund(er) før du oppretter ditt første innlegg", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index c0423cb7d4..e4791abff6 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -29,6 +29,7 @@ "username-too-long": "Gebruikersnaam is te lang", "password-too-long": "Wachtwoord is te lang", "user-banned": "Gebruiker verbannen", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Helaas, het is een vereiste om %1 seconde(n) te wachten voordat het eerste bericht geplaatst kan worden.", "blacklisted-ip": "Sorry, uw IP-adres is verbannen uit deze community. Als u meent dat dit onterecht is, neem dan contact op met een beheerder.", "ban-expiry-missing": "Geef een einddatum op voor deze ban.", diff --git a/public/language/pl/error.json b/public/language/pl/error.json index 82d6fb5d78..9e2e24f64d 100644 --- a/public/language/pl/error.json +++ b/public/language/pl/error.json @@ -29,6 +29,7 @@ "username-too-long": "Zbyt długa nazwa użytkownika", "password-too-long": "Hasło jest za długie", "user-banned": "Użytkownik zbanowany", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Przepraszamy, musisz odczekać %1 sekund(y) przed utworzeniem pierwszego posta", "blacklisted-ip": "Twój adres IP został zablokowany na tej społeczności. Jeśli uważasz to za błąd, zgłoś to administratorowi", "ban-expiry-missing": "Wprowadź datę końca blokady", diff --git a/public/language/pt_BR/error.json b/public/language/pt_BR/error.json index 307bc1c6ae..b99b1bada0 100644 --- a/public/language/pt_BR/error.json +++ b/public/language/pt_BR/error.json @@ -29,6 +29,7 @@ "username-too-long": "Nome de usuário muito longo", "password-too-long": "A senha é muito grande", "user-banned": "Usuário banido", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Desculpe, é necessário que você aguarde %1 segundo(s) antes de fazer o seu primeiro post.", "blacklisted-ip": "Desculpe, o seu endereço IP foi banido desta comunidade. Se você acha que isso é um engano, por favor contate um administrador.", "ban-expiry-missing": "Por favor forneça uma data para o fim deste banimento", diff --git a/public/language/ro/error.json b/public/language/ro/error.json index ee38cdc1c6..3e8dcded59 100644 --- a/public/language/ro/error.json +++ b/public/language/ro/error.json @@ -29,6 +29,7 @@ "username-too-long": "Numele de utilizator este prea lung", "password-too-long": "Parola prea lunga.", "user-banned": "Utilizator banat", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Imi pare rau dar trebuie sa astepti %1 secunda(e) pentru a posta prima oara.", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/ru/error.json b/public/language/ru/error.json index 5c3b5f35c4..85276aab5b 100644 --- a/public/language/ru/error.json +++ b/public/language/ru/error.json @@ -29,6 +29,7 @@ "username-too-long": "Имя пользователя слишком длинное", "password-too-long": "Пароль слишком длинный", "user-banned": "Пользователь заблокирован", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Вы можете написать свое первой сообщение через %1 сек.", "blacklisted-ip": "Извините, ваш IP адрес был забанен этим сообществом. Если вы считаете что это ошибка, пожалуйста, свяжитесь с администратором.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/rw/error.json b/public/language/rw/error.json index d2b97f8f0c..11e3d59d6f 100644 --- a/public/language/rw/error.json +++ b/public/language/rw/error.json @@ -29,6 +29,7 @@ "username-too-long": "Izina ni rirerire cyane", "password-too-long": "Password too long", "user-banned": "Umuntu wirukanwe", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Wihangena kuko usabwa gutegereza amasegonda (isegonda) %1 mbere yo gushyiraho ikintu cyawe cya mbere", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/sc/error.json b/public/language/sc/error.json index 1d2065d115..a28c95316f 100644 --- a/public/language/sc/error.json +++ b/public/language/sc/error.json @@ -29,6 +29,7 @@ "username-too-long": "Username too long", "password-too-long": "Password too long", "user-banned": "User banned", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/sk/error.json b/public/language/sk/error.json index 4e9fb7cfb1..5dbdeb828a 100644 --- a/public/language/sk/error.json +++ b/public/language/sk/error.json @@ -29,6 +29,7 @@ "username-too-long": "Username too long", "password-too-long": "Password too long", "user-banned": "Užívateľ je zakázaný", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/sl/error.json b/public/language/sl/error.json index 16561b4c63..b4d43f9a4d 100644 --- a/public/language/sl/error.json +++ b/public/language/sl/error.json @@ -29,6 +29,7 @@ "username-too-long": "Uporabniško ime je predolgo", "password-too-long": "Geslo je predolgo", "user-banned": "Uporabnik je izločen", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Oprostite, počakajte %1 sekund pred vašo prvo objavo", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/sr/error.json b/public/language/sr/error.json index f2e1f37f8a..b0e706c2c1 100644 --- a/public/language/sr/error.json +++ b/public/language/sr/error.json @@ -29,6 +29,7 @@ "username-too-long": "Корисничко име је предуго", "password-too-long": "Шифра је предугачка.", "user-banned": "Члан банован", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/sv/error.json b/public/language/sv/error.json index b283278f61..c60d19c82a 100644 --- a/public/language/sv/error.json +++ b/public/language/sv/error.json @@ -29,6 +29,7 @@ "username-too-long": "Användarnamnet är för långt", "password-too-long": "Lösenordet är för långt", "user-banned": "Användare bannlyst", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "När du är ny medlem måste du vänta %1 sekund(er) innan du gör ditt första inlägg", "blacklisted-ip": "Din IP-adress har blivit bannlyst från det här forumet. Om du tror att det beror på ett misstag, vad god kontakta en administratör. ", "ban-expiry-missing": "Ange ett slutdatum för denna banning", diff --git a/public/language/th/error.json b/public/language/th/error.json index 08a09e83e5..31966be6ae 100644 --- a/public/language/th/error.json +++ b/public/language/th/error.json @@ -29,6 +29,7 @@ "username-too-long": "ชื่อบัญชีผู้ใช้ ยาวเกินไป", "password-too-long": "Password too long", "user-banned": "User banned", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/public/language/tr/error.json b/public/language/tr/error.json index f90a44f198..65c8a3586f 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -29,6 +29,7 @@ "username-too-long": "Kullanıcı ismi çok uzun.", "password-too-long": "Parola çok uzun", "user-banned": "Kullanıcı Yasaklı", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Özür dileriz, ilk iletinizi yapmadan önce %1 saniye beklemeniz gerekiyor", "blacklisted-ip": "Üzgünüz, IP adresiniz, bu toplulukta yasaklandı. Bunun bir hata olduğunu düşünüyorsanız, bir yönetici ile irtibata geçiniz.", "ban-expiry-missing": "Bu yasak için bir bitiş tarihi girin", diff --git a/public/language/vi/error.json b/public/language/vi/error.json index 542b9d00f3..73fb8df4c8 100644 --- a/public/language/vi/error.json +++ b/public/language/vi/error.json @@ -29,6 +29,7 @@ "username-too-long": "Tên đăng nhập quá dài", "password-too-long": "Mật khẩu quá dài", "user-banned": "Tài khoản bị ban", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Rất tiếc, bạn phải chờ %1 giây để đăng bài viết đầu tiên.", "blacklisted-ip": "Rất tiếc, địa chỉ IP của bạn đã bị cấm khỏi cộng đồng. Nếu bạn cảm thấy có gì không đúng, hãy liên lạc với người quản trị.", "ban-expiry-missing": "Vui lòng cung cấp ngày hết hạn của lệnh cấm", diff --git a/public/language/zh_CN/error.json b/public/language/zh_CN/error.json index 4d5ee16393..7a4fa4d198 100644 --- a/public/language/zh_CN/error.json +++ b/public/language/zh_CN/error.json @@ -29,6 +29,7 @@ "username-too-long": "用户名太长", "password-too-long": "密码太长", "user-banned": "用户已禁止", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "抱歉,您需要等待 %1 秒后,才可以发帖!", "blacklisted-ip": "对不起,您的IP地址已被社区禁用。如果您认为这是一个错误,请与管理员联系。", "ban-expiry-missing": "请提供此次禁言结束日期", diff --git a/public/language/zh_TW/error.json b/public/language/zh_TW/error.json index 6c45cf3ff3..26b65dc708 100644 --- a/public/language/zh_TW/error.json +++ b/public/language/zh_TW/error.json @@ -29,6 +29,7 @@ "username-too-long": "帳號太長", "password-too-long": "密碼太長", "user-banned": "該使用者已被停用", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "抱歉,發表你第一篇文章須要等待 %1 秒", "blacklisted-ip": "抱歉,你的IP位置已經被這個社群禁用了。如果你覺得這是一個失誤,請連絡管理員。", "ban-expiry-missing": "請提供這個禁用的到期時間", From 9c1b1acc5b2cc9e8e7a055d0b012bd083bae5cd0 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 17:02:27 +0300 Subject: [PATCH 10/60] removed unsused requires --- src/routes/index.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/routes/index.js b/src/routes/index.js index b4e1be4a5b..47fad11e6c 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -3,15 +3,12 @@ var nconf = require('nconf'); var path = require('path'); var async = require('async'); -var winston = require('winston'); var controllers = require('../controllers'); var plugins = require('../plugins'); var user = require('../user'); var express = require('express'); -var validator = require('validator'); var accountRoutes = require('./accounts'); - var metaRoutes = require('./meta'); var apiRoutes = require('./api'); var adminRoutes = require('./admin'); From 599ac80f3d6c2758bf23f73eafe60fd794652fcc Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 17:07:18 +0300 Subject: [PATCH 11/60] use array.find --- src/controllers/accounts/profile.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/controllers/accounts/profile.js b/src/controllers/accounts/profile.js index de10c69b6a..ee66a1a4d7 100644 --- a/src/controllers/accounts/profile.js +++ b/src/controllers/accounts/profile.js @@ -118,11 +118,8 @@ profileController.get = function(req, res, callback) { } ); } - - userData.groups.forEach(function(group) { - if (group && group.name === userData.groupTitle) { - userData.selectedGroup = group; - } + userData.selectedGroup = userData.groups.find(function(group) { + return group && group.name === userData.groupTitle; }); plugins.fireHook('filter:user.account', {userData: userData, uid: req.uid}, next); From fac68d52f69933bfaad54de1ea865adca5b29ca6 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 21:00:41 +0300 Subject: [PATCH 12/60] cache group membership methods groups.isMember groups.isMembers groups.isMemberOfGroups clear cache for user on group.join & group.leave --- src/controllers/admin.js | 2 +- src/controllers/admin/cache.js | 36 +++++++ src/controllers/admin/postCache.js | 26 ----- src/groups/membership.js | 129 ++++++++++++++++++++++-- src/routes/admin.js | 2 +- src/views/admin/advanced/cache.tpl | 46 +++++++++ src/views/admin/advanced/post-cache.tpl | 27 ----- src/views/admin/partials/menu.tpl | 4 +- tests/user.js | 5 +- 9 files changed, 213 insertions(+), 64 deletions(-) create mode 100644 src/controllers/admin/cache.js delete mode 100644 src/controllers/admin/postCache.js create mode 100644 src/views/admin/advanced/cache.tpl delete mode 100644 src/views/admin/advanced/post-cache.tpl diff --git a/src/controllers/admin.js b/src/controllers/admin.js index c3ce96d205..7f622466cd 100644 --- a/src/controllers/admin.js +++ b/src/controllers/admin.js @@ -16,7 +16,7 @@ var adminController = { logs: require('./admin/logs'), errors: require('./admin/errors'), database: require('./admin/database'), - postCache: require('./admin/postCache'), + cache: require('./admin/cache'), plugins: require('./admin/plugins'), languages: require('./admin/languages'), settings: require('./admin/settings'), diff --git a/src/controllers/admin/cache.js b/src/controllers/admin/cache.js new file mode 100644 index 0000000000..de27a16775 --- /dev/null +++ b/src/controllers/admin/cache.js @@ -0,0 +1,36 @@ +'use strict'; + +var cacheController = {}; + +cacheController.get = function(req, res, next) { + var postCache = require('../../posts/cache'); + var groupCache = require('../../groups').cache; + + var avgPostSize = 0; + var percentFull = 0; + if (postCache.itemCount > 0) { + avgPostSize = parseInt((postCache.length / postCache.itemCount), 10); + percentFull = ((postCache.length / postCache.max) * 100).toFixed(2); + } + + res.render('admin/advanced/cache', { + postCache: { + length: postCache.length, + max: postCache.max, + itemCount: postCache.itemCount, + percentFull: percentFull, + avgPostSize: avgPostSize, + dump: req.query.debug ? postCache.dump() : undefined + }, + groupCache: { + length: groupCache.length, + max: groupCache.max, + itemCount: groupCache.itemCount, + percentFull: ((groupCache.length / groupCache.max) * 100).toFixed(2), + dump: req.query.debug ? groupCache.dump() : undefined + } + }); +}; + + +module.exports = cacheController; \ No newline at end of file diff --git a/src/controllers/admin/postCache.js b/src/controllers/admin/postCache.js deleted file mode 100644 index bbfd222586..0000000000 --- a/src/controllers/admin/postCache.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -var postCacheController = {}; - -postCacheController.get = function(req, res, next) { - var cache = require('../../posts/cache'); - var avgPostSize = 0; - var percentFull = 0; - if (cache.itemCount > 0) { - avgPostSize = parseInt((cache.length / cache.itemCount), 10); - percentFull = ((cache.length / cache.max) * 100).toFixed(2); - } - - res.render('admin/advanced/post-cache', { - cache: { - length: cache.length, - max: cache.max, - itemCount: cache.itemCount, - percentFull: percentFull, - avgPostSize: avgPostSize - } - }); -}; - - -module.exports = postCacheController; \ No newline at end of file diff --git a/src/groups/membership.js b/src/groups/membership.js index 3e18979f96..88993f0c9c 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -8,10 +8,21 @@ var user = require('../user'); var utils = require('../../public/src/utils'); var plugins = require('../plugins'); var notifications = require('../notifications'); -var db = require('./../database'); +var db = require('../database'); + +var pubsub = require('../pubsub'); +var LRU = require('lru-cache'); + +var cache = LRU({ + max: 200, + maxAge: 1000 * 60 * 60 +}); + module.exports = function(Groups) { + Groups.cache = cache; + Groups.join = function(groupName, uid, callback) { callback = callback || function() {}; @@ -69,6 +80,7 @@ module.exports = function(Groups) { async.parallel(tasks, next); }, function(results, next) { + clearCache(uid); setGroupTitleIfNotSet(groupName, uid, next); }, function(next) { @@ -222,6 +234,7 @@ module.exports = function(Groups) { ], next); }, function(results, next) { + clearCache(uid); Groups.getGroupFields(groupName, ['hidden', 'memberCount'], next); }, function(groupData, next) { @@ -296,26 +309,130 @@ module.exports = function(Groups) { }), callback); }; + Groups.resetCache = function() { + pubsub.publish('group:cache:reset'); + cache.reset(); + }; + + pubsub.on('group:cache:reset', function() { + cache.reset(); + }); + + function clearCache(uid) { + pubsub.publish('group:cache:del', {uid: uid}); + cache.del(uid); + } + + pubsub.on('group:cache:del', function(data) { + cache.del(data.uid); + }); + Groups.isMember = function(uid, groupName, callback) { if (!uid || parseInt(uid, 10) <= 0) { return callback(null, false); } - db.isSortedSetMember('group:' + groupName + ':members', uid, callback); + + var cachedData = cache.get(uid); + + if (cachedData && cachedData.hasOwnProperty(groupName)) { + return process.nextTick(callback, null, cachedData[groupName]); + } + + db.isSortedSetMember('group:' + groupName + ':members', uid, function(err, isMember) { + if (err) { + return callback(err); + } + + cachedData = cachedData || {}; + cachedData[groupName] = isMember; + cache.set(uid, cachedData); + callback(null, isMember); + }); }; Groups.isMembers = function(uids, groupName, callback) { - db.isSortedSetMembers('group:' + groupName + ':members', uids, callback); + if (!groupName || !uids.length) { + return callback(null, uids.map(function() {return false;})); + } + + var cachedUids = {}; + var nonCachedUids = []; + uids.forEach(function(uid) { + cachedUids[uid] = cache.get(uid); + if (!cachedUids[uid] || !cachedUids[uid].hasOwnProperty(groupName)) { + nonCachedUids.push(uid); + } + }); + + if (!nonCachedUids.length) { + var result = uids.map(function(uid) { + return cachedUids[uid] && cachedUids[uid][groupName]; + }); + return process.nextTick(callback, null, result); + } + + db.isSortedSetMembers('group:' + groupName + ':members', nonCachedUids, function(err, isMembers) { + if (err) { + return callback(err); + } + + nonCachedUids.forEach(function(uid, index) { + cachedUids[uid] = cachedUids[uid] || {}; + cachedUids[uid][groupName] = isMembers[index]; + cache.set(uid, cachedUids[uid]); + }); + + var result = uids.map(function(uid) { + return cachedUids[uid][groupName]; + }); + + callback(null, result); + }); }; Groups.isMemberOfGroups = function(uid, groups, callback) { - if (!uid || parseInt(uid, 10) <= 0) { + if (!uid || parseInt(uid, 10) <= 0 || !groups.length) { return callback(null, groups.map(function() {return false;})); } - groups = groups.map(function(groupName) { + + var cachedData = cache.get(uid); + var nonCachedGroups = []; + if (cachedData) { + groups.forEach(function(groupName) { + if (!cachedData.hasOwnProperty(groupName)) { + nonCachedGroups.push(groupName); + } + }); + } else { + nonCachedGroups = groups; + } + + // are they all cached? + if (cachedData && !nonCachedGroups.length) { + var result = groups.map(function(groupName) { + return cachedData[groupName]; + }); + return process.nextTick(callback, null, result); + } + + var nonCachedGroupsMemberSets = nonCachedGroups.map(function(groupName) { return 'group:' + groupName + ':members'; }); - db.isMemberOfSortedSets(groups, uid, callback); + db.isMemberOfSortedSets(nonCachedGroupsMemberSets, uid, function(err, isMembers) { + if (err) { + return callback(err); + } + cachedData = cachedData || {}; + nonCachedGroups.forEach(function(groupName, index) { + cachedData[groupName] = isMembers[index]; + }); + cache.set(uid, cachedData); + var result = groups.map(function(groupName) { + return cachedData[groupName]; + }); + callback(null, result); + }); }; Groups.getMemberCount = function(groupName, callback) { diff --git a/src/routes/admin.js b/src/routes/admin.js index 543b9e8489..b84e744685 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -85,7 +85,7 @@ function addRoutes(router, middleware, controllers) { router.get('/advanced/logs', middlewares, controllers.admin.logs.get); router.get('/advanced/errors', middlewares, controllers.admin.errors.get); router.get('/advanced/errors/export', middlewares, controllers.admin.errors.export); - router.get('/advanced/post-cache', middlewares, controllers.admin.postCache.get); + router.get('/advanced/cache', middlewares, controllers.admin.cache.get); router.get('/development/logger', middlewares, controllers.admin.logger.get); router.get('/development/info', middlewares, controllers.admin.info.get); diff --git a/src/views/admin/advanced/cache.tpl b/src/views/admin/advanced/cache.tpl new file mode 100644 index 0000000000..68acef6be9 --- /dev/null +++ b/src/views/admin/advanced/cache.tpl @@ -0,0 +1,46 @@ + +
+
+
+
Post Cache
+
+ +
+ {postCache.itemCount}
+ +
+ {postCache.avgPostSize}
+ +
+ {postCache.length} / {postCache.max}
+ +
+
+ {postCache.percentFull}% Full +
+
+ +
+
+ +
+
Group Cache
+
+ +
+ {groupCache.itemCount}
+ +
+ {groupCache.length} / {groupCache.max}
+ +
+
+ {groupCache.percentFull}% Full +
+
+ +
+
+
+ +
diff --git a/src/views/admin/advanced/post-cache.tpl b/src/views/admin/advanced/post-cache.tpl deleted file mode 100644 index 7f688327e4..0000000000 --- a/src/views/admin/advanced/post-cache.tpl +++ /dev/null @@ -1,27 +0,0 @@ - -
-
-
-
Post Cache
-
- -
- {cache.itemCount}
- -
- {cache.avgPostSize}
- -
- {cache.length} / {cache.max}
- -
-
- {cache.percentFull}% Full -
-
- -
-
-
- -
diff --git a/src/views/admin/partials/menu.tpl b/src/views/admin/partials/menu.tpl index b971348439..712155a30b 100644 --- a/src/views/admin/partials/menu.tpl +++ b/src/views/admin/partials/menu.tpl @@ -96,7 +96,7 @@
  • Events
  • Logs
  • Errors
  • -
  • Post Cache
  • +
  • Cache
  • Logger
  • @@ -245,7 +245,7 @@
  • Events
  • Logs
  • Errors
  • -
  • Post Cache
  • +
  • Cache
  • Logger
  • diff --git a/tests/user.js b/tests/user.js index 32f43c7dbf..9ec4e49094 100644 --- a/tests/user.js +++ b/tests/user.js @@ -23,6 +23,9 @@ describe('User', function() { testCid; before(function(done) { + var groups = require('../src/groups'); + groups.resetCache(); + Categories.create({ name: 'Test Category', description: 'A test', @@ -37,7 +40,7 @@ describe('User', function() { }); }); - beforeEach(function(){ + beforeEach(function() { userData = { username: 'John Smith', fullname: 'John Smith McNamara', From 282ac56bf686fc133d667e53d3184afaec48912a Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 21:21:32 +0300 Subject: [PATCH 13/60] adde expose methods back used by plugins --- src/middleware/index.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/middleware/index.js b/src/middleware/index.js index e827744017..7d5b5a4e80 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -112,6 +112,28 @@ middleware.privateTagListing = function(req, res, next) { } }; +middleware.exposeGroupName = function(req, res, next) { + expose('groupName', groups.getGroupNameByGroupSlug, 'slug', req, res, next); +}; + +middleware.exposeUid = function(req, res, next) { + expose('uid', user.getUidByUserslug, 'userslug', req, res, next); +}; + +function expose(exposedField, method, field, req, res, next) { + if (!req.params.hasOwnProperty(field)) { + return next(); + } + method(req.params[field], function(err, id) { + if (err) { + return next(err); + } + + res.locals[exposedField] = id; + next(); + }); +} + middleware.privateUploads = function(req, res, next) { if (req.user || parseInt(meta.config.privateUploads, 10) !== 1) { return next(); From d621b120b08eb9a31c73761d308976eae33a3b5f Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 21:24:14 +0300 Subject: [PATCH 14/60] fix groups --- src/controllers/groups.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 4f87045344..55b408183a 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -51,7 +51,8 @@ groupsController.details = function(req, res, callback) { function(next) { groups.getGroupNameByGroupSlug(req.params.slug, next); }, - function(groupName, next) { + function(_groupName, next) { + groupName = _groupName; if (!groupName) { return callback(); } From 1364fb94bf66364d4093d45bd40b15615750c24f Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 21:30:29 +0300 Subject: [PATCH 15/60] show debug info --- src/controllers/admin/cache.js | 4 ++-- src/views/admin/advanced/cache.tpl | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/controllers/admin/cache.js b/src/controllers/admin/cache.js index de27a16775..c0e1c06b65 100644 --- a/src/controllers/admin/cache.js +++ b/src/controllers/admin/cache.js @@ -20,14 +20,14 @@ cacheController.get = function(req, res, next) { itemCount: postCache.itemCount, percentFull: percentFull, avgPostSize: avgPostSize, - dump: req.query.debug ? postCache.dump() : undefined + dump: req.query.debug ? JSON.stringify(postCache.dump(), null, 4) : false }, groupCache: { length: groupCache.length, max: groupCache.max, itemCount: groupCache.itemCount, percentFull: ((groupCache.length / groupCache.max) * 100).toFixed(2), - dump: req.query.debug ? groupCache.dump() : undefined + dump: req.query.debug ? JSON.stringify(groupCache.dump(), null, 4) : false } }); }; diff --git a/src/views/admin/advanced/cache.tpl b/src/views/admin/advanced/cache.tpl index 68acef6be9..1c7b8ab589 100644 --- a/src/views/admin/advanced/cache.tpl +++ b/src/views/admin/advanced/cache.tpl @@ -20,6 +20,10 @@
    + +
    {postCache.dump}
    + + @@ -39,6 +43,10 @@ + +
    {groupCache.dump}
    + + From fcbdfa56885b98f0af31f08e7564d637592b1ee6 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 21:34:36 +0300 Subject: [PATCH 16/60] remove post cache dump --- src/controllers/admin/cache.js | 3 +-- src/views/admin/advanced/cache.tpl | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/controllers/admin/cache.js b/src/controllers/admin/cache.js index c0e1c06b65..116c928020 100644 --- a/src/controllers/admin/cache.js +++ b/src/controllers/admin/cache.js @@ -19,8 +19,7 @@ cacheController.get = function(req, res, next) { max: postCache.max, itemCount: postCache.itemCount, percentFull: percentFull, - avgPostSize: avgPostSize, - dump: req.query.debug ? JSON.stringify(postCache.dump(), null, 4) : false + avgPostSize: avgPostSize }, groupCache: { length: groupCache.length, diff --git a/src/views/admin/advanced/cache.tpl b/src/views/admin/advanced/cache.tpl index 1c7b8ab589..4c8857483d 100644 --- a/src/views/admin/advanced/cache.tpl +++ b/src/views/admin/advanced/cache.tpl @@ -19,11 +19,6 @@ {postCache.percentFull}% Full - - -
    {postCache.dump}
    - - From 9ba3612895f12146870a63ee6a3393dab36c4887 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 Sep 2016 22:48:30 +0300 Subject: [PATCH 17/60] remove winston --- public/src/modules/translator.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/public/src/modules/translator.js b/public/src/modules/translator.js index d978abe147..00a57183ef 100644 --- a/public/src/modules/translator.js +++ b/public/src/modules/translator.js @@ -1,4 +1,4 @@ -/* global define, jQuery, config, RELATIVE_PATH, utils, window, Promise, winston */ +/* global define, jQuery, config, RELATIVE_PATH, utils, window, Promise */ (function (factory) { 'use strict'; @@ -103,17 +103,17 @@ // is equal to the length of the string since // slice doesn't include the ending index while (cursor + 2 <= len) { - // if the current position in the string looks + // if the current position in the string looks // like the beginning of a translation string if (str.slice(cursor, cursor + 2) === '[[') { // split the string from the last break // to the character before the cursor // add that to the result array toTranslate.push(str.slice(lastBreak, cursor)); - // set the cursor position past the beginning + // set the cursor position past the beginning // brackets of the translation string cursor += 2; - // set the last break to our current + // set the last break to our current // spot since we just broke the string lastBreak = cursor; @@ -217,7 +217,7 @@ Translator.prototype.getTranslation = function getTranslation(namespace, key) { var translation; if (!namespace) { - winston.warn('[translator] Parameter `namespace` is ' + namespace + (namespace === '' ? '(empty string)' : '')); + console.warn('[translator] Parameter `namespace` is ' + namespace + (namespace === '' ? '(empty string)' : '')); translation = Promise.resolve({}); } else if (this.translations[namespace]) { translation = this.translations[namespace]; @@ -265,7 +265,7 @@ return Translator.cache[language]; }; - + Translator.cache = {}; return Translator; @@ -281,7 +281,7 @@ * Legacy translator function for backwards compatibility */ translate: function translate(text, language, callback) { - // console.warn('[translator] `translator.translate(text, [lang, ]callback)` is deprecated. ' + + // console.warn('[translator] `translator.translate(text, [lang, ]callback)` is deprecated. ' + // 'Use the `translator.Translator` class instead.'); var cb = callback; From 49bd03b8ec1ea8b56dc7045044ec1e30c587c49c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 15 Sep 2016 00:50:24 +0300 Subject: [PATCH 18/60] closes #5004 --- public/src/client/topic/posts.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index 6aae064794..1c0d03eeb0 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -1,6 +1,6 @@ 'use strict'; -/* globals config, app, ajaxify, define, socket, utils */ +/* globals config, app, ajaxify, define, utils */ define('forum/topic/posts', [ 'forum/pagination', @@ -71,7 +71,10 @@ define('forum/topic/posts', [ if (isPostVisible) { createNewPosts(data, components.get('post').not('[data-index=0]'), direction, scrollToPost); } else if (ajaxify.data.scrollToMyPost && parseInt(posts[0].uid, 10) === parseInt(app.user.uid, 10)) { - pagination.loadPage(ajaxify.data.pagination.pageCount, scrollToPost); + // https://github.com/NodeBB/NodeBB/issues/5004#issuecomment-247157441 + setTimeout(function() { + pagination.loadPage(ajaxify.data.pagination.pageCount, scrollToPost); + }, 250); } else { updatePagination(); } From a42d8c5be214dfcec91496ab340932e9a026ef62 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 15 Sep 2016 01:57:08 +0300 Subject: [PATCH 19/60] simplify keys --- src/groups/membership.js | 66 ++++++++++++------------------ src/views/admin/advanced/cache.tpl | 2 +- 2 files changed, 28 insertions(+), 40 deletions(-) diff --git a/src/groups/membership.js b/src/groups/membership.js index 88993f0c9c..17e70a12dc 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -14,11 +14,10 @@ var pubsub = require('../pubsub'); var LRU = require('lru-cache'); var cache = LRU({ - max: 200, + max: 40000, maxAge: 1000 * 60 * 60 }); - module.exports = function(Groups) { Groups.cache = cache; @@ -80,7 +79,7 @@ module.exports = function(Groups) { async.parallel(tasks, next); }, function(results, next) { - clearCache(uid); + clearCache(uid, groupName); setGroupTitleIfNotSet(groupName, uid, next); }, function(next) { @@ -234,7 +233,7 @@ module.exports = function(Groups) { ], next); }, function(results, next) { - clearCache(uid); + clearCache(uid, groupName); Groups.getGroupFields(groupName, ['hidden', 'memberCount'], next); }, function(groupData, next) { @@ -318,13 +317,13 @@ module.exports = function(Groups) { cache.reset(); }); - function clearCache(uid) { - pubsub.publish('group:cache:del', {uid: uid}); - cache.del(uid); + function clearCache(uid, groupName) { + pubsub.publish('group:cache:del', {uid: uid, groupName: groupName}); + cache.del(uid + ':' + groupName); } pubsub.on('group:cache:del', function(data) { - cache.del(data.uid); + cache.del(data.uid + ':' + data.groupName); }); Groups.isMember = function(uid, groupName, callback) { @@ -332,10 +331,9 @@ module.exports = function(Groups) { return callback(null, false); } - var cachedData = cache.get(uid); - - if (cachedData && cachedData.hasOwnProperty(groupName)) { - return process.nextTick(callback, null, cachedData[groupName]); + var cacheKey = uid + ':' + groupName; + if (cache.has(cacheKey)) { + return process.nextTick(callback, null, cache.get(cacheKey)); } db.isSortedSetMember('group:' + groupName + ':members', uid, function(err, isMember) { @@ -343,9 +341,7 @@ module.exports = function(Groups) { return callback(err); } - cachedData = cachedData || {}; - cachedData[groupName] = isMember; - cache.set(uid, cachedData); + cache.set(cacheKey, isMember); callback(null, isMember); }); }; @@ -355,18 +351,16 @@ module.exports = function(Groups) { return callback(null, uids.map(function() {return false;})); } - var cachedUids = {}; var nonCachedUids = []; uids.forEach(function(uid) { - cachedUids[uid] = cache.get(uid); - if (!cachedUids[uid] || !cachedUids[uid].hasOwnProperty(groupName)) { + if (!cache.has(uid + ':' + groupName)) { nonCachedUids.push(uid); } }); if (!nonCachedUids.length) { var result = uids.map(function(uid) { - return cachedUids[uid] && cachedUids[uid][groupName]; + return cache.get(uid + ':' + groupName); }); return process.nextTick(callback, null, result); } @@ -377,13 +371,11 @@ module.exports = function(Groups) { } nonCachedUids.forEach(function(uid, index) { - cachedUids[uid] = cachedUids[uid] || {}; - cachedUids[uid][groupName] = isMembers[index]; - cache.set(uid, cachedUids[uid]); + cache.set(uid + ':' + groupName, isMembers[index]); }); var result = uids.map(function(uid) { - return cachedUids[uid][groupName]; + return cache.get(uid + ':' + groupName); }); callback(null, result); @@ -395,22 +387,18 @@ module.exports = function(Groups) { return callback(null, groups.map(function() {return false;})); } - var cachedData = cache.get(uid); var nonCachedGroups = []; - if (cachedData) { - groups.forEach(function(groupName) { - if (!cachedData.hasOwnProperty(groupName)) { - nonCachedGroups.push(groupName); - } - }); - } else { - nonCachedGroups = groups; - } + + groups.forEach(function(groupName) { + if (!cache.has(uid + ':' + groupName)) { + nonCachedGroups.push(groupName); + } + }); // are they all cached? - if (cachedData && !nonCachedGroups.length) { + if (!nonCachedGroups.length) { var result = groups.map(function(groupName) { - return cachedData[groupName]; + return cache.get(uid + ':' + groupName); }); return process.nextTick(callback, null, result); } @@ -423,13 +411,13 @@ module.exports = function(Groups) { if (err) { return callback(err); } - cachedData = cachedData || {}; + nonCachedGroups.forEach(function(groupName, index) { - cachedData[groupName] = isMembers[index]; + cache.set(uid + ':' + groupName, isMembers[index]); }); - cache.set(uid, cachedData); + var result = groups.map(function(groupName) { - return cachedData[groupName]; + return cache.get(uid + ':' + groupName); }); callback(null, result); }); diff --git a/src/views/admin/advanced/cache.tpl b/src/views/admin/advanced/cache.tpl index 4c8857483d..d8e3860367 100644 --- a/src/views/admin/advanced/cache.tpl +++ b/src/views/admin/advanced/cache.tpl @@ -26,7 +26,7 @@
    Group Cache
    -
    +
    {groupCache.itemCount}

    From 07852862f5bb564cfce2e7663b267a8f8eef10a2 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 15 Sep 2016 14:01:56 +0300 Subject: [PATCH 20/60] improve helpers.isUserAllowedTo ability to pass in an array of privileges and a single cid --- src/privileges/categories.js | 19 +++++------- src/privileges/helpers.js | 59 +++++++++++++++++++++++++++++++++--- src/privileges/topics.js | 31 ++++++++----------- 3 files changed, 75 insertions(+), 34 deletions(-) diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 972b79f1d5..98d94c3aff 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -157,15 +157,10 @@ module.exports = function(privileges) { }; privileges.categories.get = function(cid, uid, callback) { + var privs = ['topics:create', 'topics:read', 'read']; async.parallel({ - 'topics:create': function(next) { - helpers.isUserAllowedTo('topics:create', uid, [cid], next); - }, - 'topics:read': function(next) { - helpers.isUserAllowedTo('topics:read', uid, [cid], next); - }, - read: function(next) { - helpers.isUserAllowedTo('read', uid, [cid], next); + privileges: function(next) { + helpers.isUserAllowedTo(privs, uid, cid, next); }, isAdministrator: function(next) { user.isAdministrator(uid, next); @@ -177,17 +172,17 @@ module.exports = function(privileges) { if (err) { return callback(err); } - + var privData = _.object(privs, results.privileges); var isAdminOrMod = results.isAdministrator || results.isModerator; plugins.fireHook('filter:privileges.categories.get', { + 'topics:create': privData['topics:create'] || isAdminOrMod, + 'topics:read': privData['topics:read'] || isAdminOrMod, + read: privData.read || isAdminOrMod, cid: cid, uid: uid, - 'topics:create': results['topics:create'][0] || isAdminOrMod, - 'topics:read': results['topics:read'][0] || isAdminOrMod, editable: isAdminOrMod, view_deleted: isAdminOrMod, - read: results.read[0] || isAdminOrMod, isAdminOrMod: isAdminOrMod }, callback); }); diff --git a/src/privileges/helpers.js b/src/privileges/helpers.js index 7b5cb0c561..15853fde2c 100644 --- a/src/privileges/helpers.js +++ b/src/privileges/helpers.js @@ -16,9 +16,19 @@ helpers.some = function(tasks, callback) { }); }; -helpers.isUserAllowedTo = function(privilege, uid, cids, callback) { +helpers.isUserAllowedTo = function(privilege, uid, cid, callback) { + if (Array.isArray(privilege) && !Array.isArray(cid)) { + isUserAllowedToPrivileges(privilege, uid, cid, callback); + } else if (Array.isArray(cid) && !Array.isArray(privilege)) { + isUserAllowedToCids(privilege, uid, cid, callback); + } else { + return callback(new Error('[[error:invalid-data]]')); + } +}; + +function isUserAllowedToCids(privilege, uid, cids, callback) { if (parseInt(uid, 10) === 0) { - return isGuestAllowedTo(privilege, cids, callback); + return isGuestAllowedToCids(privilege, cids, callback); } var userKeys = [], groupKeys = []; @@ -46,7 +56,40 @@ helpers.isUserAllowedTo = function(privilege, uid, cids, callback) { callback(null, result); }); -}; +} + +function isUserAllowedToPrivileges(privileges, uid, cid, callback) { + if (parseInt(uid, 10) === 0) { + return isGuestAllowedToPrivileges(privileges, cid, callback); + } + + var userKeys = [], groupKeys = []; + for (var i=0; i Date: Thu, 15 Sep 2016 09:02:31 -0400 Subject: [PATCH 21/60] Latest translations and fallbacks --- public/language/fa_IR/error.json | 4 ++-- public/language/zh_CN/error.json | 6 +++--- public/language/zh_CN/global.json | 2 +- public/language/zh_CN/user.json | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/public/language/fa_IR/error.json b/public/language/fa_IR/error.json index e1cc16e9ec..4426710bc8 100644 --- a/public/language/fa_IR/error.json +++ b/public/language/fa_IR/error.json @@ -28,8 +28,8 @@ "username-too-short": "نام کاربری خیلی کوتاه است.", "username-too-long": "نام کاربری بسیار طولانیست", "password-too-long": "کلمه عبور بسیار طولانیست", - "user-banned": "کاربر محروم شد.", - "user-banned-reason": "User banned (Reason: %1)", + "user-banned": "کاربر اخراج شد", + "user-banned-reason": "کاربر اخراج شده (دلیل: %1)", "user-too-new": "با عرض پوزش، شما باید %1 ثانیه پیش از فرستادن پست نخست خود صبر کنید", "blacklisted-ip": "با عرض پوزش فراوان، نشانی آی پی شما در این انجمن مسدود شده است، اگر فکر می‌کنید اشتباهی رخ داده با مدیریت انجمن تماس بگیرید.", "ban-expiry-missing": "لطفا تاریخ پایان برای این مسدود کردن ارائه دهید", diff --git a/public/language/zh_CN/error.json b/public/language/zh_CN/error.json index 7a4fa4d198..3ef83e4a53 100644 --- a/public/language/zh_CN/error.json +++ b/public/language/zh_CN/error.json @@ -122,9 +122,9 @@ "no-session-found": "未登录!", "not-in-room": "用户已不在聊天室中", "no-users-in-room": "这个聊天室中没有用户", - "cant-kick-self": "你不能把自己踢出群组", + "cant-kick-self": "您不能把自己踢出群组", "no-users-selected": "尚未选择用户", "invalid-home-page-route": "无效的首页路径", - "invalid-session": "Session Mismatch", - "invalid-session-text": "It looks like your login session is no longer active, or no longer matches with the server. Please refresh this page." + "invalid-session": "Session 无法匹配", + "invalid-session-text": "您的登入状态已经失效,或者是与服务器信息不匹配。请刷新此页面。" } \ No newline at end of file diff --git a/public/language/zh_CN/global.json b/public/language/zh_CN/global.json index c94f323598..23a31f52a6 100644 --- a/public/language/zh_CN/global.json +++ b/public/language/zh_CN/global.json @@ -96,5 +96,5 @@ "upload": "上传", "allowed-file-types": "允许的文件类型有 %1", "unsaved-changes": "您有未保存的更改,您确定您要离开么?", - "reconnecting-message": "Looks like your connection to %1 was lost, please wait while we try to reconnect." + "reconnecting-message": "与 %1 的连接断开,我们正在尝试重连,请耐心等待" } \ No newline at end of file diff --git a/public/language/zh_CN/user.json b/public/language/zh_CN/user.json index c5fee0f7e2..cca3ffd437 100644 --- a/public/language/zh_CN/user.json +++ b/public/language/zh_CN/user.json @@ -27,7 +27,7 @@ "watched": "已订阅", "followers": "粉丝", "following": "关注", - "aboutme": "About me", + "aboutme": "关于我", "signature": "签名档", "birthday": "生日", "chat": "聊天", @@ -89,10 +89,10 @@ "topics_per_page": "每页主题数", "posts_per_page": "每页帖子数", "notification_sounds": "收到通知时播放提示音", - "notifications_and_sounds": "Notifications & Sounds", - "incoming-message-sound": "Incoming message sound", - "outgoing-message-sound": "Outgoing message sound", - "notification-sound": "Notification sound", + "notifications_and_sounds": "通知 & 提示音", + "incoming-message-sound": "消息到达提示音", + "outgoing-message-sound": "消息送出提示音", + "notification-sound": "通知提示音", "browsing": "浏览设置", "open_links_in_new_tab": "在新标签打开外部链接", "enable_topic_searching": "启用主题内搜索", @@ -119,6 +119,6 @@ "info.no-ban-history": "该用户从未被封禁", "info.banned-until": "封禁到 %1", "info.banned-permanently": "永久封禁", - "info.banned-reason-label": "Reason", - "info.banned-no-reason": "No reason given." + "info.banned-reason-label": "原因", + "info.banned-no-reason": "没有原因" } \ No newline at end of file From 447fc26b9ab803f6e787f41a520e75d756430e6f Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 15 Sep 2016 17:36:43 +0300 Subject: [PATCH 22/60] fix styling issue on reqister queue --- src/views/admin/manage/registration.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/admin/manage/registration.tpl b/src/views/admin/manage/registration.tpl index 99c6517c93..486686996d 100644 --- a/src/views/admin/manage/registration.tpl +++ b/src/views/admin/manage/registration.tpl @@ -50,7 +50,7 @@ -
    {users.ipMatch.icon:text}
    +
    {users.ipMatch.icon:text}
    {users.ipMatch.username} From a72ccfb067e635c1576b012875ff746880fbdaa8 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 15 Sep 2016 19:16:52 +0300 Subject: [PATCH 23/60] only remove page # on IS --- public/src/client/topic.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/public/src/client/topic.js b/public/src/client/topic.js index be41d85ac7..284fc42803 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -55,7 +55,9 @@ define('forum/topic', [ sort.handleSort('topicPostSort', 'user.setTopicSort', 'topic/' + ajaxify.data.slug); - enableInfiniteLoadingOrPagination(); + if (!config.usePagination) { + infinitescroll.init($('[component="topic"]'), posts.loadMorePosts); + } addBlockQuoteHandler(); @@ -207,14 +209,6 @@ define('forum/topic', [ }); } - function enableInfiniteLoadingOrPagination() { - if (!config.usePagination) { - infinitescroll.init($('[component="topic"]'), posts.loadMorePosts); - } else { - navigator.disable(); - } - } - function updateTopicTitle() { var span = components.get('navbar/title').find('span'); if ($(window).scrollTop() > 50 && span.hasClass('hidden')) { @@ -264,7 +258,11 @@ define('forum/topic', [ Topic.replaceURLTimeout = 0; if (history.replaceState) { - var search = (window.location.search && !/^\?page=\d+$/.test(window.location.search) ? window.location.search : ''); + var search = window.location.search || ''; + if (!config.usePagination) { + search = (search && !/^\?page=\d+$/.test(search) ? search : ''); + } + history.replaceState({ url: newUrl + search }, null, window.location.protocol + '//' + window.location.host + RELATIVE_PATH + '/' + newUrl + search); From 7d53b778de7fa1f0e939ad98c498fa4a1b245846 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 13 Sep 2016 12:02:39 -0400 Subject: [PATCH 24/60] WIP extending flags management interface with new options for state, assignee, notes, etc --- public/language/en_GB/topic.json | 12 +++ src/views/admin/manage/flags.tpl | 142 ++++++++++++++++++++----------- 2 files changed, 106 insertions(+), 48 deletions(-) diff --git a/public/language/en_GB/topic.json b/public/language/en_GB/topic.json index f177725d56..e38f4b1d84 100644 --- a/public/language/en_GB/topic.json +++ b/public/language/en_GB/topic.json @@ -36,6 +36,18 @@ "flag_title": "Flag this post for moderation", "flag_success": "This post has been flagged for moderation.", + "flag_manage_title": "Flagged post in %1", + "flag_manage_history": "Action History", + "flag_manage_no_history": "No event history to report", + "flag_manage_assignee": "Assignee", + "flag_manage_state": "State", + "flag_manage_state_open": "New/Open", + "flag_manage_state_wip": "Work in Progress", + "flag_manage_state_resolved": "Resolved", + "flag_manage_state_rejected": "Rejected", + "flag_manage_notes": "Shared Notes", + "flag_manage_update": "Update Flag Status", + "deleted_message": "This topic has been deleted. Only users with topic management privileges can see it.", "following_topic.message": "You will now be receiving notifications when somebody posts to this topic.", diff --git a/src/views/admin/manage/flags.tpl b/src/views/admin/manage/flags.tpl index 1bd1726b97..1e12d5c51a 100644 --- a/src/views/admin/manage/flags.tpl +++ b/src/views/admin/manage/flags.tpl @@ -44,7 +44,7 @@
    -
    +
    No flagged posts! @@ -52,54 +52,100 @@ -
    -
    -
    -
    - - - - -
    {../user.icon:text}
    - -
    - - - {../user.username} - -
    -

    {posts.content}

    -
    - - - Posted in {posts.category.name}, • - Read More - - -
    -
    +
    + -
    - This post has been flagged {posts.flags} time(s): -
    - -
    -
    - - +
    +
    +
    +
    +
    + + + + +
    {../user.icon:text}
    + +
    + + + {../user.username} + +
    +

    {posts.content}

    +
    + + + Posted in {posts.category.name}, • + Read More + + +
    +
    +
    + This post has been flagged {posts.flags} time(s): +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    + +
    +
    +
    +
    [[topic:flag_manage_history]]
    + +
    [[topic:flag_manage_no_history]]
    + +
    +
    From 8dc57cba58721d075474810f61c82e9016db66e9 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 14 Sep 2016 21:06:55 -0400 Subject: [PATCH 25/60] allowing updating of flag data --- public/src/admin/manage/flags.js | 20 +++++++++++++++++-- src/controllers/admin/flags.js | 20 ++++++++++++++++++- src/posts/flags.js | 34 ++++++++++++++++++++++++++++++++ src/socket.io/posts/flag.js | 30 +++++++++++++++++++++++++++- src/user.js | 14 +++++++++++++ src/views/admin/manage/flags.tpl | 23 +++++++++++---------- 6 files changed, 127 insertions(+), 14 deletions(-) diff --git a/public/src/admin/manage/flags.js b/public/src/admin/manage/flags.js index a686c4a07e..8885d7b8a5 100644 --- a/public/src/admin/manage/flags.js +++ b/public/src/admin/manage/flags.js @@ -4,8 +4,9 @@ define('admin/manage/flags', [ 'forum/infinitescroll', 'autocomplete', - 'Chart' -], function(infinitescroll, autocomplete, Chart) { + 'Chart', + 'components' +], function(infinitescroll, autocomplete, Chart, components) { var Flags = {}; @@ -21,6 +22,7 @@ define('admin/manage/flags', [ handleDelete(); handleInfiniteScroll(); handleGraphs(); + handleFormActions(); }; function handleDismiss() { @@ -150,5 +152,19 @@ define('admin/manage/flags', [ }); } + function handleFormActions() { + components.get('posts/flag').find('[component="posts/flag/update"]').on('click', function() { + var pid = $(this).parents('[component="posts/flag"]').attr('data-pid'); + var formData = $($(this).parents('form').get(0)).serializeArray(); + + socket.emit('posts.updateFlag', { + pid: pid, + data: formData + }, function(err) { + console.log(arguments); + }); + }); + } + return Flags; }); \ No newline at end of file diff --git a/src/controllers/admin/flags.js b/src/controllers/admin/flags.js index 340eda0a9d..f21cc773ad 100644 --- a/src/controllers/admin/flags.js +++ b/src/controllers/admin/flags.js @@ -2,6 +2,7 @@ var async = require('async'); var posts = require('../../posts'); +var user = require('../../user'); var analytics = require('../../analytics'); var flagsController = {}; @@ -25,15 +26,32 @@ flagsController.get = function(req, res, next) { }, analytics: function(next) { analytics.getDailyStatsForSet('analytics:flags', Date.now(), 30, next); - } + }, + assignees: async.apply(user.getAdminsandGlobalMods) }, next); } ], function (err, results) { if (err) { return next(err); } + + // Minimise data set for assignees so tjs does less work + results.assignees = results.assignees.map(function(userObj) { + var keep = ['uid', 'username']; + for(var prop in userObj) { + if (userObj.hasOwnProperty(prop)) { + if (keep.indexOf(prop) === -1) { + delete userObj[prop]; + } + } + } + + return userObj; + }); + var data = { posts: results.posts, + assignees: results.assignees, analytics: results.analytics, next: stop + 1, byUsername: byUsername, diff --git a/src/posts/flags.js b/src/posts/flags.js index dcc2f32f1d..ba0196bedf 100644 --- a/src/posts/flags.js +++ b/src/posts/flags.js @@ -226,4 +226,38 @@ module.exports = function(Posts) { } ], callback); }; + + Posts.updateFlagData = function(pid, flagObj, callback) { + // Retrieve existing flag data to compare for history-saving purposes + var changes = []; + var changeset = {}; + var prop; + Posts.getPostData(pid, function(err, postData) { + // Track new additions + for(prop in flagObj) { + if (flagObj.hasOwnProperty(prop) && !postData.hasOwnProperty('flag:' + prop)) { + changes.push(prop); + } + + // Generate changeset for object modification + if (flagObj.hasOwnProperty(prop)) { + changeset['flag:' + prop] = flagObj[prop]; + } + } + + // Track changed items + for(prop in postData) { + if ( + postData.hasOwnProperty(prop) && prop.startsWith('flag:') && + flagObj.hasOwnProperty(prop.slice(5)) && + postData[prop] !== flagObj[prop.slice(5)] + ) { + changes.push(prop.slice(5)); + } + } + + // Save flag data into post hash + Posts.setPostFields(pid, changeset, callback); + }); + }; }; diff --git a/src/socket.io/posts/flag.js b/src/socket.io/posts/flag.js index 2ad5dcd2b8..6ebf9c05d8 100644 --- a/src/socket.io/posts/flag.js +++ b/src/socket.io/posts/flag.js @@ -163,7 +163,35 @@ module.exports = function(SocketPosts) { }, function (posts, next) { next(null, {posts: posts, next: stop + 1}); - }, + } ], callback); }; + + SocketPosts.updateFlag = function(socket, data, callback) { + if (!data || !(data.pid && data.data)) { + return callback('[[error:invalid-data]]'); + } + + var payload = {}; + + async.waterfall([ + function (next) { + user.isAdminOrGlobalMod(socket.uid, next); + }, + function (isAdminOrGlobalModerator, next) { + if (!isAdminOrGlobalModerator) { + return next(new Error('[[no-privileges]]')); + } + + // Translate form data into object + payload = data.data.reduce(function(memo, cur) { + memo[cur.name] = cur.value; + return memo; + }, payload); + + next(null, data.pid, payload); + }, + async.apply(posts.updateFlagData) + ], callback); + } }; diff --git a/src/user.js b/src/user.js index d04b7c8cce..48abf3f28c 100644 --- a/src/user.js +++ b/src/user.js @@ -2,6 +2,7 @@ var async = require('async'); +var groups = require('./groups'); var plugins = require('./plugins'); var db = require('./database'); var topics = require('./topics'); @@ -260,6 +261,19 @@ var utils = require('../public/src/utils'); }); }; + User.getAdminsandGlobalMods = function(callback) { + async.parallel({ + admins: async.apply(groups.getMembers, 'administrators', 0, -1), + mods: async.apply(groups.getMembers, 'Global Moderators', 0, -1) + }, function(err, results) { + if (err) { + return callback(err); + } + + User.getUsersData(results.admins.concat(results.mods), callback); + }); + }; + User.addInterstitials = function(callback) { plugins.registerHook('core', { hook: 'filter:register.interstitial', diff --git a/src/views/admin/manage/flags.tpl b/src/views/admin/manage/flags.tpl index 1e12d5c51a..04e7d86d1f 100644 --- a/src/views/admin/manage/flags.tpl +++ b/src/views/admin/manage/flags.tpl @@ -44,7 +44,7 @@
    -
    +
    No flagged posts! @@ -52,7 +52,7 @@ -
    +
    From 4e6b2555d0d633511e98fbb7c4dc803cfccfc1cb Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 15 Sep 2016 10:53:24 -0400 Subject: [PATCH 27/60] moved flag history expansion to its own method, showing usernames in assignee history event --- public/language/en_GB/topic.json | 3 ++ src/posts/flags.js | 50 +++++++++++++++++++++++--------- src/views/admin/manage/flags.tpl | 2 +- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/public/language/en_GB/topic.json b/public/language/en_GB/topic.json index e38f4b1d84..e3479cb989 100644 --- a/public/language/en_GB/topic.json +++ b/public/language/en_GB/topic.json @@ -47,6 +47,9 @@ "flag_manage_state_rejected": "Rejected", "flag_manage_notes": "Shared Notes", "flag_manage_update": "Update Flag Status", + "flag_manage_history_assignee": "Assigned to %1", + "flag_manage_history_state": "Updated state to %1", + "flag_manage_history_notes": "Updates flag notes", "deleted_message": "This topic has been deleted. Only users with topic management privileges can see it.", diff --git a/src/posts/flags.js b/src/posts/flags.js index 6a9ad6ecfd..62956ee161 100644 --- a/src/posts/flags.js +++ b/src/posts/flags.js @@ -195,24 +195,13 @@ module.exports = function(Posts) { if (post) { post.flagReasons = reasons[index]; - - // Expand flag history - try { - history = JSON.parse(post['flag:history'] || '[]'); - history.map(function(event) { - event.timestampISO = new Date(event.timestamp).toISOString(); - return event; - }); - post['flag:history'] = history; - } catch (e) { - winston.warn('[posts/getFlags] Unable to deserialise post flag history, likely malformed data'); - } } }); next(null, results.posts); }); - } + }, + async.apply(Posts.expandFlagHistory) ], callback); } @@ -305,4 +294,39 @@ module.exports = function(Posts) { Posts.setPostFields(pid, changeset, callback); }); }; + + Posts.expandFlagHistory = function(posts, callback) { + // Expand flag history + async.map(posts, function(post, next) { + try { + var history = JSON.parse(post['flag:history'] || '[]'); + } catch (e) { + winston.warn('[posts/getFlags] Unable to deserialise post flag history, likely malformed data'); + callback(e); + } + + async.map(history, function(event, next) { + event.timestampISO = new Date(event.timestamp).toISOString(); + + if (event.type === 'assignee') { + user.getUserField(parseInt(event.value, 10), 'username', function(err, username) { + if (err) { + return next(err); + } + + event.label = username || 'Unknown user'; + next(null, event); + }); + } else if (event.type === 'state') { + event.label = '[[topic:flag_manage_state_' + event.value + ']]'; + setImmediate(next.bind(null, null, event)); + } else { + setImmediate(next.bind(null, null, event)); + } + }, function(err, history) { + post['flag:history'] = history; + next(null, post); + }); + }, callback); + } }; diff --git a/src/views/admin/manage/flags.tpl b/src/views/admin/manage/flags.tpl index 40416d3a70..1ffb5856b1 100644 --- a/src/views/admin/manage/flags.tpl +++ b/src/views/admin/manage/flags.tpl @@ -151,7 +151,7 @@
  • - Updated {../type} to {../value} + [[topic:flag_manage_history_{../type}, {../label}]]
  • From b12607b1de4c97ef086a4140e477d54e1150736a Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 15 Sep 2016 12:33:36 -0400 Subject: [PATCH 28/60] added uid to flag history, fixed loading on IS, worked around tjs bug --- public/language/en_GB/topic.json | 2 +- public/less/flags.less | 4 ++ public/src/admin/manage/flags.js | 27 +++++----- src/controllers/admin/flags.js | 14 ------ src/posts/flags.js | 86 ++++++++++++++++++++++++++------ src/socket.io/posts/flag.js | 2 +- src/views/admin/manage/flags.tpl | 19 ++++--- 7 files changed, 103 insertions(+), 51 deletions(-) diff --git a/public/language/en_GB/topic.json b/public/language/en_GB/topic.json index e3479cb989..091bdf359f 100644 --- a/public/language/en_GB/topic.json +++ b/public/language/en_GB/topic.json @@ -49,7 +49,7 @@ "flag_manage_update": "Update Flag Status", "flag_manage_history_assignee": "Assigned to %1", "flag_manage_history_state": "Updated state to %1", - "flag_manage_history_notes": "Updates flag notes", + "flag_manage_history_notes": "Updated flag notes", "deleted_message": "This topic has been deleted. Only users with topic management privileges can see it.", diff --git a/public/less/flags.less b/public/less/flags.less index da44e61552..29b5998933 100644 --- a/public/less/flags.less +++ b/public/less/flags.less @@ -31,4 +31,8 @@ .user-icon-style(24px, 1.5rem); } } + + [component="posts/flag/history"] .avatar { + margin-right: 1rem; + } } \ No newline at end of file diff --git a/public/src/admin/manage/flags.js b/public/src/admin/manage/flags.js index 3b235677ca..12327526ca 100644 --- a/public/src/admin/manage/flags.js +++ b/public/src/admin/manage/flags.js @@ -24,7 +24,8 @@ define('admin/manage/flags', [ handleGraphs(); updateFlagDetails(ajaxify.data.posts); - handleFormActions(); + + components.get('posts/flags').on('click', '[component="posts/flag/update"]', updateFlag); }; function handleDismiss() { @@ -93,10 +94,14 @@ define('admin/manage/flags', [ after: $('[data-next]').attr('data-next') }, function(data, done) { if (data.posts && data.posts.length) { - app.parseAndTranslate('admin/manage/flags', 'posts', {posts: data.posts}, function(html) { + app.parseAndTranslate('admin/manage/flags', 'posts', { + posts: data.posts, + assignees: ajaxify.data.assignees + }, function(html) { $('[data-next]').attr('data-next', data.next); $('.post-container').append(html); html.find('img:not(.not-responsive)').addClass('img-responsive'); + updateFlagDetails(data.posts); done(); }); } else { @@ -177,17 +182,15 @@ define('admin/manage/flags', [ }); } - function handleFormActions() { - components.get('posts/flag').find('[component="posts/flag/update"]').on('click', function() { - var pid = $(this).parents('[component="posts/flag"]').attr('data-pid'); - var formData = $($(this).parents('form').get(0)).serializeArray(); + function updateFlag() { + var pid = $(this).parents('[component="posts/flag"]').attr('data-pid'); + var formData = $($(this).parents('form').get(0)).serializeArray(); - socket.emit('posts.updateFlag', { - pid: pid, - data: formData - }, function(err) { - console.log(arguments); - }); + socket.emit('posts.updateFlag', { + pid: pid, + data: formData + }, function(err) { + console.log(arguments); }); } diff --git a/src/controllers/admin/flags.js b/src/controllers/admin/flags.js index 61413ce1f0..f21cc773ad 100644 --- a/src/controllers/admin/flags.js +++ b/src/controllers/admin/flags.js @@ -35,20 +35,6 @@ flagsController.get = function(req, res, next) { return next(err); } - // Parse out flag data into its own object inside each post hash - results.posts = results.posts.map(function(postObj) { - for(var prop in postObj) { - postObj.flagData = postObj.flagData || {}; - - if (postObj.hasOwnProperty(prop) && prop.startsWith('flag:')) { - postObj.flagData[prop.slice(5)] = postObj[prop]; - delete postObj[prop]; - } - } - - return postObj; - }); - // Minimise data set for assignees so tjs does less work results.assignees = results.assignees.map(function(userObj) { var keep = ['uid', 'username']; diff --git a/src/posts/flags.js b/src/posts/flags.js index 62956ee161..82ea31dd00 100644 --- a/src/posts/flags.js +++ b/src/posts/flags.js @@ -201,7 +201,42 @@ module.exports = function(Posts) { next(null, results.posts); }); }, - async.apply(Posts.expandFlagHistory) + async.apply(Posts.expandFlagHistory), + function(posts, next) { + // Parse out flag data into its own object inside each post hash + posts = posts.map(function(postObj) { + for(var prop in postObj) { + postObj.flagData = postObj.flagData || {}; + + if (postObj.hasOwnProperty(prop) && prop.startsWith('flag:')) { + postObj.flagData[prop.slice(5)] = postObj[prop]; + + if (prop === 'flag:state') { + switch(postObj[prop]) { + case 'open': + postObj.flagData.labelClass = 'info'; + break; + case 'wip': + postObj.flagData.labelClass = 'warning'; + break; + case 'resolved': + postObj.flagData.labelClass = 'success'; + break; + case 'rejected': + postObj.flagData.labelClass = 'danger'; + break; + } + } + + delete postObj[prop]; + } + } + + return postObj; + }); + + setImmediate(next.bind(null, null, posts)); + } ], callback); } @@ -231,11 +266,12 @@ module.exports = function(Posts) { ], callback); }; - Posts.updateFlagData = function(pid, flagObj, callback) { + Posts.updateFlagData = function(uid, pid, flagObj, callback) { // Retrieve existing flag data to compare for history-saving purposes var changes = []; var changeset = {}; var prop; + Posts.getPostData(pid, function(err, postData) { // Track new additions for(prop in flagObj) { @@ -270,6 +306,7 @@ module.exports = function(Posts) { case 'assignee': // intentional fall-through case 'state': history.unshift({ + uid: uid, type: property, value: flagObj[property], timestamp: Date.now() @@ -278,6 +315,7 @@ module.exports = function(Posts) { case 'notes': history.unshift({ + uid: uid, type: property, timestamp: Date.now() }); @@ -308,21 +346,37 @@ module.exports = function(Posts) { async.map(history, function(event, next) { event.timestampISO = new Date(event.timestamp).toISOString(); - if (event.type === 'assignee') { - user.getUserField(parseInt(event.value, 10), 'username', function(err, username) { - if (err) { - return next(err); - } + async.parallel([ + function(next) { + user.getUserFields(event.uid, ['username', 'picture'], function(err, userData) { + if (err) { + return next(err); + } - event.label = username || 'Unknown user'; - next(null, event); - }); - } else if (event.type === 'state') { - event.label = '[[topic:flag_manage_state_' + event.value + ']]'; - setImmediate(next.bind(null, null, event)); - } else { - setImmediate(next.bind(null, null, event)); - } + event.user = userData; + next(); + }); + }, + function(next) { + if (event.type === 'assignee') { + user.getUserField(parseInt(event.value, 10), 'username', function(err, username) { + if (err) { + return next(err); + } + + event.label = username || 'Unknown user'; + next(null); + }); + } else if (event.type === 'state') { + event.label = '[[topic:flag_manage_state_' + event.value + ']]'; + setImmediate(next); + } else { + setImmediate(next); + } + } + ], function(err) { + next(err, event); + }) }, function(err, history) { post['flag:history'] = history; next(null, post); diff --git a/src/socket.io/posts/flag.js b/src/socket.io/posts/flag.js index 6ebf9c05d8..5a44461ffb 100644 --- a/src/socket.io/posts/flag.js +++ b/src/socket.io/posts/flag.js @@ -189,7 +189,7 @@ module.exports = function(SocketPosts) { return memo; }, payload); - next(null, data.pid, payload); + next(null, socket.uid, data.pid, payload); }, async.apply(posts.updateFlagData) ], callback); diff --git a/src/views/admin/manage/flags.tpl b/src/views/admin/manage/flags.tpl index 1ffb5856b1..5a9dca8edf 100644 --- a/src/views/admin/manage/flags.tpl +++ b/src/views/admin/manage/flags.tpl @@ -56,13 +56,13 @@
    -
    +
    @@ -102,7 +102,7 @@
    {../user.icon:text}
    {../user.username} - : "{../reason}" + : "{posts.flagReasons.reason}" @@ -122,7 +122,7 @@
    @@ -147,11 +147,16 @@
    [[topic:flag_manage_no_history]]
    -
      +
      • -
        - [[topic:flag_manage_history_{../type}, {../label}]] +
        + + + +
        {../user.icon:text}
        + + [[topic:flag_manage_history_{posts.flagData.history.type}, {posts.flagData.history.label}]]
      From 4897e861fb4e9d6ab45506597dbc46ce791678bb Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 15 Sep 2016 13:03:46 -0400 Subject: [PATCH 29/60] handling errors :rage2: --- public/language/en_GB/topic.json | 1 + public/src/admin/manage/flags.js | 6 +++++- src/posts/flags.js | 8 ++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/public/language/en_GB/topic.json b/public/language/en_GB/topic.json index 091bdf359f..36daa3d044 100644 --- a/public/language/en_GB/topic.json +++ b/public/language/en_GB/topic.json @@ -50,6 +50,7 @@ "flag_manage_history_assignee": "Assigned to %1", "flag_manage_history_state": "Updated state to %1", "flag_manage_history_notes": "Updated flag notes", + "flag_manage_saved": "Flag Details Updated", "deleted_message": "This topic has been deleted. Only users with topic management privileges can see it.", diff --git a/public/src/admin/manage/flags.js b/public/src/admin/manage/flags.js index 12327526ca..ae44e9232c 100644 --- a/public/src/admin/manage/flags.js +++ b/public/src/admin/manage/flags.js @@ -190,7 +190,11 @@ define('admin/manage/flags', [ pid: pid, data: formData }, function(err) { - console.log(arguments); + if (err) { + return app.alertError(err.message); + } else { + app.alertSuccess('[[topic:flag_manage_saved]]'); + } }); } diff --git a/src/posts/flags.js b/src/posts/flags.js index 82ea31dd00..424a54084f 100644 --- a/src/posts/flags.js +++ b/src/posts/flags.js @@ -273,6 +273,10 @@ module.exports = function(Posts) { var prop; Posts.getPostData(pid, function(err, postData) { + if (err) { + return callback(err); + } + // Track new additions for(prop in flagObj) { if (flagObj.hasOwnProperty(prop) && !postData.hasOwnProperty('flag:' + prop)) { @@ -378,6 +382,10 @@ module.exports = function(Posts) { next(err, event); }) }, function(err, history) { + if (err) { + return next(err); + } + post['flag:history'] = history; next(null, post); }); From f46755759a22a50bdbd3113943351bb3896fc55a Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 15 Sep 2016 20:31:47 +0300 Subject: [PATCH 30/60] show categories in unread as tree --- src/categories.js | 2 +- src/controllers/unread.js | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/categories.js b/src/categories.js index 539a643f80..3233f2dbcd 100644 --- a/src/categories.js +++ b/src/categories.js @@ -292,7 +292,7 @@ var privileges = require('./privileges'); for (i; i < len; ++i) { category = categories[i]; - if (!category.hasOwnProperty('parentCid')) { + if (!category.hasOwnProperty('parentCid') || category.parentCid === null) { category.parentCid = 0; } diff --git a/src/controllers/unread.js b/src/controllers/unread.js index 2e988601c2..c610b91723 100644 --- a/src/controllers/unread.js +++ b/src/controllers/unread.js @@ -100,12 +100,13 @@ function getWatchedCategories(uid, selectedCid, callback) { privileges.categories.filterCids('read', cids, uid, next); }, function (cids, next) { - categories.getCategoriesFields(cids, ['cid', 'name', 'slug', 'icon', 'link', 'color', 'bgColor'], next); + categories.getCategoriesFields(cids, ['cid', 'name', 'slug', 'icon', 'link', 'color', 'bgColor', 'parentCid'], next); }, function (categoryData, next) { categoryData = categoryData.filter(function(category) { return category && !category.link; }); + var selectedCategory; categoryData.forEach(function(category) { category.selected = parseInt(category.cid, 10) === parseInt(selectedCid, 10); @@ -113,11 +114,27 @@ function getWatchedCategories(uid, selectedCid, callback) { selectedCategory = category; } }); - next(null, {categories: categoryData, selectedCategory: selectedCategory}); + + var categoriesData = []; + var tree = categories.getTree(categoryData, 0); + + tree.forEach(function(category) { + recursive(category, categoriesData, ''); + }); + + next(null, {categories: categoriesData, selectedCategory: selectedCategory}); } ], callback); } +function recursive(category, categoriesData, level) { + category.level = level; + categoriesData.push(category); + + category.children.forEach(function(child) { + recursive(child, categoriesData, '    ' + level); + }); +} unreadController.unreadTotal = function(req, res, next) { var filter = req.params.filter || ''; From d86666024b5196a839b907edab88f41cf7dc1b00 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 15 Sep 2016 20:36:18 +0300 Subject: [PATCH 31/60] up themes --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9d419eaa79..91b5af9599 100644 --- a/package.json +++ b/package.json @@ -61,8 +61,8 @@ "nodebb-plugin-spam-be-gone": "0.4.10", "nodebb-rewards-essentials": "0.0.9", "nodebb-theme-lavender": "3.0.14", - "nodebb-theme-persona": "4.1.43", - "nodebb-theme-vanilla": "5.1.27", + "nodebb-theme-persona": "4.1.44", + "nodebb-theme-vanilla": "5.1.28", "nodebb-widget-essentials": "2.0.11", "nodemailer": "2.0.0", "nodemailer-sendmail-transport": "1.0.0", From dc317d61b65798ae21193c32d71a01b11d9ecffc Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 15 Sep 2016 20:42:38 +0300 Subject: [PATCH 32/60] add missing next --- src/posts/flags.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/posts/flags.js b/src/posts/flags.js index 424a54084f..152414e436 100644 --- a/src/posts/flags.js +++ b/src/posts/flags.js @@ -94,6 +94,8 @@ module.exports = function(Posts) { } else { next(); } + } else { + next(); } }, function(next) { From 2342d59e6f2a14b51e7ea18458b5497c1a6a2e65 Mon Sep 17 00:00:00 2001 From: phit Date: Thu, 15 Sep 2016 20:17:04 +0200 Subject: [PATCH 33/60] fix mixed content warning on 503 status page and installer --- public/503.html | 2 +- src/views/install/index.tpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/503.html b/public/503.html index 8907525ec4..119c710ab7 100644 --- a/public/503.html +++ b/public/503.html @@ -1,7 +1,7 @@ Excessive Load Warning - +