From 12a7e57117d2985ba3793070b157379b2a572c32 Mon Sep 17 00:00:00 2001 From: "Misty (Bot)" Date: Wed, 27 Jun 2018 18:28:46 +0000 Subject: [PATCH 01/27] Incremented version number - v1.10.0 --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 58cada2253..0b92fa2ea9 100644 --- a/install/package.json +++ b/install/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPL-3.0", "description": "NodeBB Forum", - "version": "1.9.3", + "version": "1.10.0", "homepage": "http://www.nodebb.org", "repository": { "type": "git", @@ -145,4 +145,4 @@ "url": "https://github.com/barisusakli" } ] -} +} \ No newline at end of file From 57b7c7ede4661108dd6cbf95331718331f59c612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 27 Jun 2018 14:36:08 -0400 Subject: [PATCH 02/27] closes #6607 --- install/package.json | 6 +- public/language/en-GB/groups.json | 2 +- public/src/admin/manage/group.js | 89 +------------------ public/src/client/groups/memberlist.js | 32 ++++++- src/socket.io/groups.js | 17 +++- src/views/admin/manage/group.tpl | 7 -- .../admin/partials/groups/memberlist.tpl | 21 +++-- 7 files changed, 66 insertions(+), 108 deletions(-) diff --git a/install/package.json b/install/package.json index 0b92fa2ea9..f3d3b431cc 100644 --- a/install/package.json +++ b/install/package.json @@ -75,9 +75,9 @@ "nodebb-plugin-spam-be-gone": "0.5.4", "nodebb-rewards-essentials": "0.0.11", "nodebb-theme-lavender": "5.0.5", - "nodebb-theme-persona": "9.0.17", - "nodebb-theme-slick": "1.2.5", - "nodebb-theme-vanilla": "10.0.15", + "nodebb-theme-persona": "9.0.18", + "nodebb-theme-slick": "1.2.6", + "nodebb-theme-vanilla": "10.0.16", "nodebb-widget-essentials": "4.0.7", "nodemailer": "^4.6.5", "passport": "^0.4.0", diff --git a/public/language/en-GB/groups.json b/public/language/en-GB/groups.json index 08c8d4d1f5..c18335bb5e 100644 --- a/public/language/en-GB/groups.json +++ b/public/language/en-GB/groups.json @@ -33,7 +33,7 @@ "details.grant": "Grant/Rescind Ownership", "details.kick": "Kick", "details.kick_confirm": "Are you sure you want to remove this member from the group?", - + "details.add-member": "Add Member", "details.owner_options": "Group Administration", "details.group_name": "Group Name", "details.member_count": "Member Count", diff --git a/public/src/admin/manage/group.js b/public/src/admin/manage/group.js index 95e1751ff6..92ef056630 100644 --- a/public/src/admin/manage/group.js +++ b/public/src/admin/manage/group.js @@ -5,20 +5,14 @@ define('admin/manage/group', [ 'forum/groups/memberlist', 'iconSelect', 'admin/modules/colorpicker', - 'translator', - 'benchpress', -], function (memberList, iconSelect, colorpicker, translator, Benchpress) { +], function (memberList, iconSelect, colorpicker) { var Groups = {}; Groups.init = function () { - var groupDetailsSearch = $('#group-details-search'); - var groupDetailsSearchResults = $('#group-details-search-results'); var groupIcon = $('#group-icon'); var changeGroupUserTitle = $('#change-group-user-title'); var changeGroupLabelColor = $('#change-group-label-color'); var groupLabelPreview = $('#group-label-preview'); - var searchDelay; - var groupName = ajaxify.data.group.name; @@ -36,87 +30,6 @@ define('admin/manage/group', [ groupLabelPreview.css('background', changeGroupLabelColor.val() || '#000000'); }); - groupDetailsSearch.on('keyup', function () { - if (searchDelay) { - clearTimeout(searchDelay); - } - - searchDelay = setTimeout(function () { - var searchText = groupDetailsSearch.val(); - var foundUser; - - socket.emit('admin.user.search', { - query: searchText, - }, function (err, results) { - if (!err && results && results.users.length > 0) { - var numResults = results.users.length; - var x; - if (numResults > 20) { - numResults = 20; - } - - groupDetailsSearchResults.empty(); - - for (x = 0; x < numResults; x += 1) { - foundUser = $('
  • '); - foundUser - .attr({ - title: results.users[x].username, - 'data-uid': results.users[x].uid, - 'data-username': results.users[x].username, - 'data-userslug': results.users[x].userslug, - 'data-picture': results.users[x].picture, - 'data-usericon-bgColor': results.users[x]['icon:bgColor'], - 'data-usericon-text': results.users[x]['icon:text'], - }) - .append(results.users[x].picture ? - $('').addClass('avatar avatar-sm').attr('src', results.users[x].picture) : - $('
    ').addClass('avatar avatar-sm').css('background-color', results.users[x]['icon:bgColor']).html(results.users[x]['icon:text'])) - .append($('').html(results.users[x].username)); - - groupDetailsSearchResults.append(foundUser); - } - } else { - groupDetailsSearchResults.translateHtml('
  • [[admin/manage/groups:edit.no-users-found]]
  • '); - } - }); - }, 200); - }); - - groupDetailsSearchResults.on('click', 'li[data-uid]', function () { - var userLabel = $(this); - var uid = parseInt(userLabel.attr('data-uid'), 10); - - socket.emit('admin.groups.join', { - groupName: groupName, - uid: uid, - }, function (err) { - if (err) { - return app.alertError(err.message); - } - - var member = { - uid: userLabel.attr('data-uid'), - username: userLabel.attr('data-username'), - userslug: userLabel.attr('data-userslug'), - picture: userLabel.attr('data-picture'), - 'icon:bgColor': userLabel.attr('data-usericon-bgColor'), - 'icon:text': userLabel.attr('data-usericon-text'), - }; - - Benchpress.parse('admin/partials/groups/memberlist', 'group.members', { - group: { - isOwner: ajaxify.data.group.isOwner, - members: [member], - }, - }, function (html) { - translator.translate(html, function (html) { - $('[component="groups/members"] tbody').prepend(html); - }); - }); - }); - }); - $('[component="groups/members"]').on('click', '[data-action]', function () { var btnEl = $(this); var userRow = btnEl.parents('[data-uid]'); diff --git a/public/src/client/groups/memberlist.js b/public/src/client/groups/memberlist.js index cc3b36ce3c..82e2cdc9a7 100644 --- a/public/src/client/groups/memberlist.js +++ b/public/src/client/groups/memberlist.js @@ -1,7 +1,7 @@ 'use strict'; -define('forum/groups/memberlist', ['components', 'forum/infinitescroll'], function () { +define('forum/groups/memberlist', ['autocomplete'], function (autocomplete) { var MemberList = {}; var searchInterval; var groupName; @@ -11,10 +11,40 @@ define('forum/groups/memberlist', ['components', 'forum/infinitescroll'], functi templateName = _templateName || 'groups/details'; groupName = ajaxify.data.group.name; + handleMemberAdd(); handleMemberSearch(); handleMemberInfiniteScroll(); }; + function handleMemberAdd() { + $('[component="groups/members/add"]').on('click', function () { + var modal = bootbox.dialog({ + title: '[[groups:details.add-member]]', + message: '', + }); + autocomplete.user(modal.find('input'), function (ev, ui) { + var user = ui.item.user; + if (user) { + addUserToGroup(user, function () { + modal.modal('hide'); + }); + } + }); + }); + } + + function addUserToGroup(user, callback) { + socket.emit('groups.addMember', { groupName: groupName, uid: user.uid }, function (err) { + if (err) { + return app.alertError(err); + } + parseAndTranslate([user], function (html) { + $('[component="groups/members"] tbody').prepend(html); + }); + callback(); + }); + } + function handleMemberSearch() { $('[component="groups/members/search"]').on('keyup', function () { var query = $(this).val(); diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index e98b8451c6..033a4e7a4b 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -71,14 +71,27 @@ SocketGroups.leave = function (socket, data, callback) { groups.leave(data.groupName, socket.uid, callback); }; +SocketGroups.addMember = isOwner(function (socket, data, callback) { + if (data.groupName === 'administrators' || groups.isPrivilegeGroup(data.groupName)) { + return callback(new Error('[[error:not-allowed]]')); + } + groups.join(data.groupName, data.uid, callback); +}); + function isOwner(next) { return function (socket, data, callback) { async.parallel({ isAdmin: async.apply(user.isAdministrator, socket.uid), + isGlobalModerator: async.apply(user.isGlobalModerator, socket.uid), isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName), + group: async.apply(groups.getGroupData, data.groupName), }, function (err, results) { - if (err || (!results.isOwner && !results.isAdmin)) { - return callback(err || new Error('[[error:no-privileges]]')); + if (err) { + return callback(err); + } + var isOwner = results.isOwner || results.isAdmin || (results.isGlobalModerator && !results.group.system); + if (!isOwner) { + return callback(new Error('[[error:no-privileges]]')); } next(socket, data, callback); }); diff --git a/src/views/admin/manage/group.tpl b/src/views/admin/manage/group.tpl index b9170df21a..51301f8e56 100644 --- a/src/views/admin/manage/group.tpl +++ b/src/views/admin/manage/group.tpl @@ -74,13 +74,6 @@ -
    - - -
      - -
      -
      diff --git a/src/views/admin/partials/groups/memberlist.tpl b/src/views/admin/partials/groups/memberlist.tpl index f7456de2b5..c6aae28af7 100644 --- a/src/views/admin/partials/groups/memberlist.tpl +++ b/src/views/admin/partials/groups/memberlist.tpl @@ -1,7 +1,16 @@ -
      - - -

      +
      + +
      + +
      + +
      +
      + + +
      +
      +
      @@ -10,9 +19,9 @@ From 625ab1a46b98431655ed55a44bb469bae3f01429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 27 Jun 2018 15:12:02 -0400 Subject: [PATCH 03/27] remove deprecated method --- src/plugins.js | 52 +------------------------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/src/plugins.js b/src/plugins.js index a4d28944fe..54aa45d49a 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -9,7 +9,6 @@ var express = require('express'); var nconf = require('nconf'); var hotswap = require('./hotswap'); -var file = require('./file'); var app; var middleware; @@ -138,56 +137,6 @@ Plugins.reloadRoutes = function (callback) { }); }; -var themeNamePattern = /^(@.*?\/)?nodebb-theme-.*$/; - -// DEPRECATED: remove in v1.8.0 -Plugins.getTemplates = function (callback) { - var templates = {}; - var tplName; - - winston.warn('[deprecated] Plugins.getTemplates is DEPRECATED to be removed in v1.8.0'); - - Plugins.data.getActive(function (err, plugins) { - if (err) { - return callback(err); - } - - async.eachSeries(plugins, function (plugin, next) { - if (plugin.templates || themeNamePattern.test(plugin.id)) { - winston.verbose('[plugins] Loading templates (' + plugin.id + ')'); - var templatesPath = path.join(__dirname, '../node_modules', plugin.id, plugin.templates || 'templates'); - file.walk(templatesPath, function (err, pluginTemplates) { - if (pluginTemplates) { - pluginTemplates.forEach(function (pluginTemplate) { - if (pluginTemplate.endsWith('.tpl')) { - tplName = '/' + pluginTemplate.replace(templatesPath, '').substring(1); - - if (templates.hasOwnProperty(tplName)) { - winston.verbose('[plugins] ' + tplName + ' replaced by ' + plugin.id); - } - - templates[tplName] = pluginTemplate; - } else { - winston.warn('[plugins] Skipping ' + pluginTemplate + ' by plugin ' + plugin.id); - } - }); - } else if (err) { - winston.error(err); - } else { - winston.warn('[plugins/' + plugin.id + '] A templates directory was defined for this plugin, but was not found.'); - } - - next(false); - }); - } else { - next(false); - } - }, function (err) { - callback(err, templates); - }); - }); -}; - Plugins.get = function (id, callback) { var url = (nconf.get('registry') || 'https://packages.nodebb.org') + '/api/v1/plugins/' + id; @@ -228,6 +177,7 @@ Plugins.list = function (matching, callback) { }; Plugins.normalise = function (apiReturn, callback) { + var themeNamePattern = /^(@.*?\/)?nodebb-theme-.*$/; var pluginMap = {}; var dependencies = require(path.join(nconf.get('base_dir'), 'package.json')).dependencies; apiReturn = Array.isArray(apiReturn) ? apiReturn : []; From 5cf662e565149e3966be5da32cac448e4bad443a Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 27 Jun 2018 11:24:23 -0400 Subject: [PATCH 04/27] closes #6613 --- .../en-GB/admin/settings/advanced.json | 4 +++ src/views/admin/settings/advanced.tpl | 27 +++++++++++++++++++ src/webserver.js | 5 ++++ 3 files changed, 36 insertions(+) diff --git a/public/language/en-GB/admin/settings/advanced.json b/public/language/en-GB/admin/settings/advanced.json index 16eae5a8bd..e4070ab7be 100644 --- a/public/language/en-GB/admin/settings/advanced.json +++ b/public/language/en-GB/admin/settings/advanced.json @@ -12,6 +12,10 @@ "headers.acac": "Access-Control-Allow-Credentials", "headers.acam": "Access-Control-Allow-Methods", "headers.acah": "Access-Control-Allow-Headers", + "hsts": "Strict Transport Security", + "hsts.subdomains": "Include subdomains in HSTS header", + "hsts.preload": "Allow preloading of HSTS header", + "hsts.help": "An HSTS header is already pre-configured for this site. You can elect to include subdomains and preloading flags in your header. If in doubt, you can leave these unchecked. More information ", "traffic-management": "Traffic Management", "traffic.help": "NodeBB deploys equipped with a module that automatically denies requests in high-traffic situations. You can tune these settings here, although the defaults are a good starting point.", "traffic.enable": "Enable Traffic Management", diff --git a/src/views/admin/settings/advanced.tpl b/src/views/admin/settings/advanced.tpl index 958ae73c3f..44d34fa80f 100644 --- a/src/views/admin/settings/advanced.tpl +++ b/src/views/admin/settings/advanced.tpl @@ -63,6 +63,33 @@ +
      +
      [[admin/settings/advanced:hsts]]
      +
      +
      +
      + +
      +
      +
      + +
      +
      + +
      +

      + [[admin/settings/advanced:hsts.help, https:\/\/hstspreload.org\/]] +

      + +
      +
      +
      [[admin/settings/advanced:traffic-management]]
      diff --git a/src/webserver.js b/src/webserver.js index 89e710c9c2..be4c02f443 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -195,6 +195,11 @@ function setupExpressApp(app, callback) { app.use(helmet()); app.use(helmet.referrerPolicy({ policy: 'strict-origin-when-cross-origin' })); + app.use(helmet.hsts({ + maxAge: parseInt(meta.config['hsts-maxage'], 10) || 31536000, + includeSubdomains: !!parseInt(meta.config['hsts-subdomains'], 10), + preload: !!parseInt(meta.config['hsts-preload'], 10), + })); app.use(middleware.addHeaders); app.use(middleware.processRender); auth.initialize(app, middleware); From 9912c400b6cc3191f25286f54c245122d67e3076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 27 Jun 2018 16:14:40 -0400 Subject: [PATCH 05/27] closes #6612 --- public/language/en-GB/pages.json | 5 +++- src/controllers/popular.js | 4 +-- src/controllers/recent.js | 2 +- src/controllers/top.js | 14 +++++++++++ src/routes/feeds.js | 42 +++++++++++++++++++++++--------- 5 files changed, 51 insertions(+), 16 deletions(-) diff --git a/public/language/en-GB/pages.json b/public/language/en-GB/pages.json index 6780f5cf5d..f6927e63a2 100644 --- a/public/language/en-GB/pages.json +++ b/public/language/en-GB/pages.json @@ -6,7 +6,10 @@ "popular-month": "Popular topics this month", "popular-alltime": "All time popular topics", "recent": "Recent Topics", - "top": "Top Voted Topics", + "top-day": "Top voted topics today", + "top-week": "Top voted topics this week", + "top-month": "Top voted topics this month", + "top-alltime": "Top Voted Topics", "moderator-tools": "Moderator Tools", "flagged-content": "Flagged Content", "ip-blacklist": "IP Blacklist", diff --git a/src/controllers/popular.js b/src/controllers/popular.js index d8e7fbb4bf..138fc11817 100644 --- a/src/controllers/popular.js +++ b/src/controllers/popular.js @@ -3,7 +3,7 @@ var async = require('async'); var nconf = require('nconf'); - +var validator = require('validator'); var helpers = require('./helpers'); var recentController = require('./recent'); @@ -26,7 +26,7 @@ popularController.get = function (req, res, next) { data.breadcrumbs = helpers.buildBreadcrumbs(breadcrumbs); } var feedQs = data.rssFeedUrl.split('?')[1]; - data.rssFeedUrl = nconf.get('relative_path') + '/popular/' + (req.query.term || 'alltime') + '.rss'; + data.rssFeedUrl = nconf.get('relative_path') + '/popular/' + (validator.escape(String(req.query.term)) || 'alltime') + '.rss'; if (req.loggedIn) { data.rssFeedUrl += '?' + feedQs; } diff --git a/src/controllers/recent.js b/src/controllers/recent.js index e0d037d0f6..334d709784 100644 --- a/src/controllers/recent.js +++ b/src/controllers/recent.js @@ -37,7 +37,7 @@ recentController.getData = function (req, url, sort, callback) { var rssToken; if (!helpers.validFilters[filter] || (!term && req.query.term)) { - return callback(); + return callback(null, null); } term = term || 'alltime'; diff --git a/src/controllers/top.js b/src/controllers/top.js index b471acac60..718d9cfa47 100644 --- a/src/controllers/top.js +++ b/src/controllers/top.js @@ -2,6 +2,10 @@ 'use strict'; var async = require('async'); +var nconf = require('nconf'); +var validator = require('validator'); + +var helpers = require('./helpers'); var recentController = require('./recent'); var topController = module.exports; @@ -15,6 +19,16 @@ topController.get = function (req, res, next) { if (!data) { return next(); } + var term = helpers.terms[req.query.term] || 'alltime'; + if (req.originalUrl.startsWith(nconf.get('relative_path') + '/api/top') || req.originalUrl.startsWith(nconf.get('relative_path') + '/top')) { + data.title = '[[pages:top-' + term + ']]'; + } + + var feedQs = data.rssFeedUrl.split('?')[1]; + data.rssFeedUrl = nconf.get('relative_path') + '/top/' + (validator.escape(String(req.query.term)) || 'alltime') + '.rss'; + if (req.loggedIn) { + data.rssFeedUrl += '?' + feedQs; + } res.render('top', data); }, ], next); diff --git a/src/routes/feeds.js b/src/routes/feeds.js index f800ab806d..f843e08e7a 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -16,11 +16,19 @@ var db = require('../database'); var utils = require('../utils'); var controllers404 = require('../controllers/404.js'); +var terms = { + daily: 'day', + weekly: 'week', + monthly: 'month', + alltime: 'alltime', +}; + module.exports = function (app, middleware) { app.get('/topic/:topic_id.rss', middleware.maintenanceMode, generateForTopic); app.get('/category/:category_id.rss', middleware.maintenanceMode, generateForCategory); app.get('/recent.rss', middleware.maintenanceMode, generateForRecent); app.get('/top.rss', middleware.maintenanceMode, generateForTop); + app.get('/top/:term.rss', middleware.maintenanceMode, generateForTop); app.get('/popular.rss', middleware.maintenanceMode, generateForPopular); app.get('/popular/:term.rss', middleware.maintenanceMode, generateForPopular); app.get('/recentposts.rss', middleware.maintenanceMode, generateForRecentPosts); @@ -212,7 +220,8 @@ function generateForTop(req, res, next) { if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { return controllers404.send404(req, res); } - + var term = terms[req.params.term] || 'day'; + var uid; async.waterfall([ function (next) { if (req.query.token && req.query.uid) { @@ -222,13 +231,27 @@ function generateForTop(req, res, next) { } }, function (token, next) { - generateForTopics({ - uid: token && token === req.query.token ? req.query.uid : req.uid, + uid = token && token === req.query.token ? req.query.uid : req.uid; + + topics.getSortedTopics({ + uid: uid, + start: 0, + stop: 19, + term: term, + sort: 'votes', + }, next); + }, + function (result, next) { + generateTopicsFeed({ + uid: uid, title: 'Top Voted Topics', description: 'A list of topics that have received the most votes', - feed_url: '/top.rss', - site_url: '/top', - }, 'topics:votes', req, res, next); + feed_url: '/top/' + (req.params.term || 'daily') + '.rss', + site_url: '/top/' + (req.params.term || 'daily'), + }, result.topics, next); + }, + function (feed) { + sendFeed(feed, res); }, ], next); } @@ -237,12 +260,7 @@ function generateForPopular(req, res, next) { if (parseInt(meta.config['feeds:disableRSS'], 10) === 1) { return controllers404.send404(req, res); } - var terms = { - daily: 'day', - weekly: 'week', - monthly: 'month', - alltime: 'alltime', - }; + var term = terms[req.params.term] || 'day'; var uid; async.waterfall([ From fd5dfdc01c154b9034099974fd1e2b19182a4ef2 Mon Sep 17 00:00:00 2001 From: "Misty (Bot)" Date: Fri, 29 Jun 2018 09:29:06 +0000 Subject: [PATCH 06/27] Latest translations and fallbacks --- public/language/bg/admin/manage/privileges.json | 2 +- public/language/bg/admin/settings/advanced.json | 4 ++-- public/language/cs/admin/manage/privileges.json | 2 +- public/language/cs/admin/settings/advanced.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/public/language/bg/admin/manage/privileges.json b/public/language/bg/admin/manage/privileges.json index 1128fca181..3c1d24bba8 100644 --- a/public/language/bg/admin/manage/privileges.json +++ b/public/language/bg/admin/manage/privileges.json @@ -20,7 +20,7 @@ "edit-posts": "Редактиране на публикации", "view-edit-history": "Преглед на историята на редакциите", "delete-posts": "Изтриване на публикации", - "view_deleted": "View Deleted Posts", + "view_deleted": "Преглед на изтритите публикации", "upvote-posts": "Положително гласуване за публикации", "downvote-posts": "Отрицателно гласуване за публикации", "delete-topics": "Изтриване на теми", diff --git a/public/language/bg/admin/settings/advanced.json b/public/language/bg/admin/settings/advanced.json index 7ae142a4e4..8e92299247 100644 --- a/public/language/bg/admin/settings/advanced.json +++ b/public/language/bg/admin/settings/advanced.json @@ -6,9 +6,9 @@ "headers.allow-from": "Задайте „ALLOW-FROM“, за да поставите NodeBB в „iFrame“", "headers.powered-by": "Персонализиране на заглавната част „Захранван от“, която се изпраща от NodeBB", "headers.acao": "Произход за разрешаване на управлението на достъпа", - "headers.acao-regex": "Access-Control-Allow-Origin Regular Expression", + "headers.acao-regex": "Регулярен израз за произхода за разрешаване на управлението на достъпа", "headers.acao-help": "За да забраните достъпа до всички уеб сайтове, оставете празно", - "headers.acao-regex-help": "Enter regular expressions here to match dynamic origins. To deny access to all sites, leave empty", + "headers.acao-regex-help": "Въведете регулярен израз за съвпадение с динамичните произходи. За да забраните достъпа на всички уеб сайтове, оставете това празно.", "headers.acac": "Удостоверителни данни за разрешаване на управлението на достъпа", "headers.acam": "Методи за разрешаване на управлението на достъпа", "headers.acah": "Заглавки за разрешаване на управлението на достъпа", diff --git a/public/language/cs/admin/manage/privileges.json b/public/language/cs/admin/manage/privileges.json index 2ca282d43e..0320ddcb94 100644 --- a/public/language/cs/admin/manage/privileges.json +++ b/public/language/cs/admin/manage/privileges.json @@ -20,7 +20,7 @@ "edit-posts": "Upravit příspěvek", "view-edit-history": "Zobrazit historii editace", "delete-posts": "Odstranit příspěvky", - "view_deleted": "View Deleted Posts", + "view_deleted": "Zobrazit odstraněné příspěvky", "upvote-posts": "Souhlasné příspěvky", "downvote-posts": "Nesouhlasné příspěvky", "delete-topics": "Odstranit témata", diff --git a/public/language/cs/admin/settings/advanced.json b/public/language/cs/admin/settings/advanced.json index 268c7429cc..5cf39f453d 100644 --- a/public/language/cs/admin/settings/advanced.json +++ b/public/language/cs/admin/settings/advanced.json @@ -8,7 +8,7 @@ "headers.acao": "Access-Control-Allow-Origin", "headers.acao-regex": "Access-Control-Allow-Origin Regular Expression", "headers.acao-help": "Pro zakázání přístupu na všechny stránky, zanechte prázdné", - "headers.acao-regex-help": "Enter regular expressions here to match dynamic origins. To deny access to all sites, leave empty", + "headers.acao-regex-help": "Zde zadejte regulární výrazy, které odpovídají dynamickým originálům. Pro zakázání všech stránek, ponechte prázdné.", "headers.acac": "Access-Control-Allow-Credentials", "headers.acam": "Access-Control-Allow-Methods", "headers.acah": "Access-Control-Allow-Headers", From d0997ed83f53faba4a7395d340f551561a54939f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 29 Jun 2018 11:18:38 -0400 Subject: [PATCH 07/27] fixes #6615 --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f3d3b431cc..2b85e914a8 100644 --- a/install/package.json +++ b/install/package.json @@ -65,7 +65,7 @@ "mousetrap": "^1.6.1", "mubsub-nbb": "^1.5.0", "nconf": "^0.10.0", - "nodebb-plugin-composer-default": "6.0.28", + "nodebb-plugin-composer-default": "6.0.29", "nodebb-plugin-dbsearch": "2.0.19", "nodebb-plugin-emoji": "^2.2.2", "nodebb-plugin-emoji-android": "2.0.0", From 002cde1057e0b397144838165ce11e3d8b6040f9 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 29 Jun 2018 13:56:22 -0400 Subject: [PATCH 08/27] added progress bar to ip hash upgrade script --- src/upgrades/1.10.0/hash_recent_ip_addresses.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/upgrades/1.10.0/hash_recent_ip_addresses.js b/src/upgrades/1.10.0/hash_recent_ip_addresses.js index 14bb0ee60e..9e13db0252 100644 --- a/src/upgrades/1.10.0/hash_recent_ip_addresses.js +++ b/src/upgrades/1.10.0/hash_recent_ip_addresses.js @@ -11,6 +11,7 @@ module.exports = { name: 'Hash all IP addresses stored in Recent IPs zset', timestamp: Date.UTC(2017, 5, 22), method: function (callback) { + const progress = this.progress; var hashed = /[a-f0-9]{32}/; let hash; @@ -18,6 +19,7 @@ module.exports = { async.each(ips, function (set, next) { // Short circuit if already processed if (hashed.test(set.value)) { + progress.incr(); return setImmediate(next); } @@ -26,8 +28,14 @@ module.exports = { async.series([ async.apply(db.sortedSetAdd, 'ip:recent', set.score, hash), async.apply(db.sortedSetRemove, 'ip:recent', set.value), - ], next); + ], function (err) { + progress.incr(); + next(err); + }); }, next); - }, { withScores: 1 }, callback); + }, { + withScores: 1, + progress: this.progress, + }, callback); }, }; From be0ef799ee161db427293ef15daa875d05283780 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 29 Jun 2018 14:16:28 -0400 Subject: [PATCH 09/27] closes #6592 --- src/socket.io/user.js | 1 + src/user/profile.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 071cb6a5f7..2534b156b0 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -115,6 +115,7 @@ SocketUser.reset.commit = function (socket, data, callback) { async.parallel({ uid: async.apply(db.getObjectField, 'reset:uid', data.code), reset: async.apply(user.reset.commit, data.code, data.password), + hook: async.apply(plugins.fireHook, 'action:password.reset', { uid: socket.uid }), }, next); }, function (results, next) { diff --git a/src/user/profile.js b/src/user/profile.js index fc320bd5d0..5ee4fed689 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -339,6 +339,7 @@ module.exports = function (User) { }), async.apply(User.reset.updateExpiry, data.uid), async.apply(User.auth.revokeAllSessions, data.uid), + async.apply(plugins.fireHook, 'action:password.change', { uid: uid }), ], function (err) { next(err); }); From 7e6007e1464fbfeb53151002897466bbaeae2799 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 29 Jun 2018 14:23:25 -0400 Subject: [PATCH 10/27] revoke all sessions on email change --- src/user/profile.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/user/profile.js b/src/user/profile.js index 5ee4fed689..5da6eb7409 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -200,6 +200,7 @@ module.exports = function (User) { async.series([ async.apply(db.sortedSetRemove, 'email:uid', oldEmail.toLowerCase()), async.apply(db.sortedSetRemove, 'email:sorted', oldEmail.toLowerCase() + ':' + uid), + async.apply(User.auth.revokeAllSessions, uid), ], function (err) { next(err); }); From be1e83bfc12bf8f3c299448801794b3a8cc6283f Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Fri, 29 Jun 2018 15:20:26 -0400 Subject: [PATCH 11/27] fix tests --- test/user.js | 58 +++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/test/user.js b/test/user.js index d3dfc1d359..b29cd8c865 100644 --- a/test/user.js +++ b/test/user.js @@ -641,30 +641,33 @@ describe('User', function () { }); it('should update a user\'s profile', function (done) { - var data = { - uid: uid, - username: 'updatedUserName', - email: 'updatedEmail@me.com', - fullname: 'updatedFullname', - website: 'http://nodebb.org', - location: 'izmir', - groupTitle: 'testGroup', - birthday: '01/01/1980', - signature: 'nodebb is good', - }; - socketUser.updateProfile({ uid: uid }, data, function (err, result) { + User.create({ username: 'justforupdate', email: 'just@for.updated', password: '123456' }, function (err, uid) { assert.ifError(err); - - assert.equal(result.username, 'updatedUserName'); - assert.equal(result.userslug, 'updatedusername'); - assert.equal(result.email, 'updatedEmail@me.com'); - - db.getObject('user:' + uid, function (err, userData) { + var data = { + uid: uid, + username: 'updatedUserName', + email: 'updatedEmail@me.com', + fullname: 'updatedFullname', + website: 'http://nodebb.org', + location: 'izmir', + groupTitle: 'testGroup', + birthday: '01/01/1980', + signature: 'nodebb is good', + }; + socketUser.updateProfile({ uid: uid }, data, function (err, result) { assert.ifError(err); - Object.keys(data).forEach(function (key) { - assert.equal(data[key], userData[key]); + + assert.equal(result.username, 'updatedUserName'); + assert.equal(result.userslug, 'updatedusername'); + assert.equal(result.email, 'updatedEmail@me.com'); + + db.getObject('user:' + uid, function (err, userData) { + assert.ifError(err); + Object.keys(data).forEach(function (key) { + assert.equal(data[key], userData[key]); + }); + done(); }); - done(); }); }); }); @@ -699,20 +702,23 @@ describe('User', function () { assert.ifError(err); db.getSortedSetRevRange('user:' + uid + ':usernames', 0, -1, function (err, data) { assert.ifError(err); + assert.equal(data.length, 1); assert(data[0].startsWith('updatedAgain')); - assert(data[1].startsWith('updatedUserName')); done(); }); }); }); it('should change email', function (done) { - socketUser.changeUsernameEmail({ uid: uid }, { uid: uid, email: 'updatedAgain@me.com', password: '123456' }, function (err) { + User.create({ username: 'pooremailupdate', email: 'poor@update.me', password: '123456' }, function (err, uid) { assert.ifError(err); - db.getObjectField('user:' + uid, 'email', function (err, email) { + socketUser.changeUsernameEmail({ uid: uid }, { uid: uid, email: 'updatedAgain@me.com', password: '123456' }, function (err) { assert.ifError(err); - assert.equal(email, 'updatedAgain@me.com'); - done(); + db.getObjectField('user:' + uid, 'email', function (err, email) { + assert.ifError(err); + assert.equal(email, 'updatedAgain@me.com'); + done(); + }); }); }); }); From ee64437f8ab9d156cf1a25f881aaa4a18838d735 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Fri, 29 Jun 2018 15:50:19 -0400 Subject: [PATCH 12/27] fix runJobs --- src/prestart.js | 2 +- src/start.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/prestart.js b/src/prestart.js index dcc64cf527..1d5a5146ab 100644 --- a/src/prestart.js +++ b/src/prestart.js @@ -67,7 +67,7 @@ function loadConfig(configFile) { }); nconf.stores.env.readOnly = true; - nconf.set('runJobs', nconf.get('isPrimary') && !nconf.get('jobsDisabled')); + nconf.set('runJobs', nconf.get('isPrimary') === 'true' && !nconf.get('jobsDisabled')); } function versionCheck() { diff --git a/src/start.js b/src/start.js index c8b0905b32..427a58830b 100644 --- a/src/start.js +++ b/src/start.js @@ -47,7 +47,7 @@ start.start = function () { var webserver = require('./webserver'); require('./socket.io').init(webserver.server); - if (nconf.get('isPrimary') === 'true' && !nconf.get('jobsDisabled')) { + if (nconf.get('runJobs')) { require('./notifications').startJobs(); require('./user').startJobs(); } From 23b665ca8b8c6231c13a59f2995237d7f24981ab Mon Sep 17 00:00:00 2001 From: "Misty (Bot)" Date: Sun, 1 Jul 2018 09:28:39 +0000 Subject: [PATCH 13/27] Latest translations and fallbacks --- public/language/zh-CN/admin/manage/privileges.json | 2 +- public/language/zh-CN/admin/settings/advanced.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/language/zh-CN/admin/manage/privileges.json b/public/language/zh-CN/admin/manage/privileges.json index 780d2d40a1..492f826cac 100644 --- a/public/language/zh-CN/admin/manage/privileges.json +++ b/public/language/zh-CN/admin/manage/privileges.json @@ -20,7 +20,7 @@ "edit-posts": "修改回复", "view-edit-history": "查看修改历史", "delete-posts": "删除回复", - "view_deleted": "View Deleted Posts", + "view_deleted": "查看已删除回复", "upvote-posts": "顶", "downvote-posts": "踩", "delete-topics": "删除主题", diff --git a/public/language/zh-CN/admin/settings/advanced.json b/public/language/zh-CN/admin/settings/advanced.json index 2c890a7076..e81c53baf0 100644 --- a/public/language/zh-CN/admin/settings/advanced.json +++ b/public/language/zh-CN/admin/settings/advanced.json @@ -6,9 +6,9 @@ "headers.allow-from": "设置 ALLOW-FROM 来放置 NodeBB 于 iFrame 中", "headers.powered-by": "自定义由 NodeBB 发送的 \"Powered By\" 头部 ", "headers.acao": "Access-Control-Allow-Origin", - "headers.acao-regex": "Access-Control-Allow-Origin Regular Expression", + "headers.acao-regex": "Access-Control-Allow-Origin 正则表达式", "headers.acao-help": "要拒绝所有网站,请留空", - "headers.acao-regex-help": "Enter regular expressions here to match dynamic origins. To deny access to all sites, leave empty", + "headers.acao-regex-help": "输入正则表达式以匹配动态来源。要拒绝所有网站,请留空", "headers.acac": "Access-Control-Allow-Credentials", "headers.acam": "Access-Control-Allow-Methods", "headers.acah": "Access-Control-Allow-Headers", From c2b0be1f2c1c2c804fc92f5a85a2669656003965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 2 Jul 2018 17:11:32 -0400 Subject: [PATCH 14/27] if stack is undefined fallback to message and then to hardcoded string --- src/meta/minifier.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/meta/minifier.js b/src/meta/minifier.js index c48bbb890f..14da9beb93 100644 --- a/src/meta/minifier.js +++ b/src/meta/minifier.js @@ -112,7 +112,7 @@ if (process.env.minifier_child) { if (err) { process.send({ type: 'error', - message: err.stack, + message: err.stack || err.message || 'unknown error', }); return; } @@ -277,7 +277,7 @@ function buildCSS(data, callback) { from: undefined, }).then(function (result) { process.nextTick(callback, null, { code: result.css }); - }, function (err) { + }).catch(function (err) { process.nextTick(callback, err); }); }); From e8a3c23d4246668a06b1b609aa7234f372889e9e Mon Sep 17 00:00:00 2001 From: Timothy Fike Date: Mon, 2 Jul 2018 21:36:21 -0400 Subject: [PATCH 15/27] Fix verion regex Fixes #6620 (#6625) --- public/src/admin/extend/plugins.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/admin/extend/plugins.js b/public/src/admin/extend/plugins.js index a7dd240e04..1d43db6043 100644 --- a/public/src/admin/extend/plugins.js +++ b/public/src/admin/extend/plugins.js @@ -268,7 +268,7 @@ define('admin/extend/plugins', ['jqueryui', 'translator', 'benchpress'], functio }; Plugins.suggest = function (pluginId, callback) { - var nbbVersion = app.config.version.match(/^\d\.\d\.\d/); + var nbbVersion = app.config.version.match(/^\d+\.\d+\.\d+/); $.ajax((app.config.registry || 'https://packages.nodebb.org') + '/api/v1/suggest', { type: 'GET', data: { From 584f88e0923250f2a2a044c9e98a5ba3ac74f8ac Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Tue, 3 Jul 2018 15:12:23 -0400 Subject: [PATCH 16/27] blocks WIP --- public/src/client/account/blocks.js | 3 +- src/socket.io/user/profile.js | 6 +-- src/user/blocks.js | 65 ++++++++++++++--------------- test/user.js | 24 +++++++++++ 4 files changed, 61 insertions(+), 37 deletions(-) diff --git a/public/src/client/account/blocks.js b/public/src/client/account/blocks.js index f6ef1154d0..11d656fa46 100644 --- a/public/src/client/account/blocks.js +++ b/public/src/client/account/blocks.js @@ -17,7 +17,8 @@ define('forum/account/blocks', ['forum/account/header', 'autocomplete'], functio $('.block-edit').on('click', '[data-action="toggle"]', function () { var uid = parseInt(this.getAttribute('data-uid'), 10); socket.emit('user.toggleBlock', { - uid: uid, + blockeeUid: uid, + blockerUid: ajaxify.data.uid, }, Blocks.refreshList); }); }; diff --git a/src/socket.io/user/profile.js b/src/socket.io/user/profile.js index 49e63744c6..fa76573a54 100644 --- a/src/socket.io/user/profile.js +++ b/src/socket.io/user/profile.js @@ -210,16 +210,16 @@ module.exports = function (SocketUser) { SocketUser.toggleBlock = function (socket, data, callback) { async.waterfall([ function (next) { - user.blocks.can(data.uid, next); + user.blocks.can(socket.uid, data.blockerUid, data.blockeeUid, next); }, function (can, next) { if (!can) { return next(new Error('[[error:cannot-block-privileged]]')); } - user.blocks.is(data.uid, socket.uid, next); + user.blocks.is(data.blockeeUid, data.blockerUid, next); }, function (is, next) { - user.blocks[is ? 'remove' : 'add'](data.uid, socket.uid, next); + user.blocks[is ? 'remove' : 'add'](data.blockeeUid, data.blockerUid, next); }, ], callback); }; diff --git a/src/user/blocks.js b/src/user/blocks.js index 75767e4a12..d28ea5c505 100644 --- a/src/user/blocks.js +++ b/src/user/blocks.js @@ -2,40 +2,46 @@ var async = require('async'); var db = require('../database'); -var LRU = require('lru-cache'); module.exports = function (User) { - User.blocks = { - _cache: LRU({ - max: 100, - length: function () { return 1; }, - maxAge: 0, - }), - }; + User.blocks = {}; User.blocks.is = function (targetUid, uid, callback) { - User.blocks.list(uid, function (err, blocks) { - callback(err, blocks.includes(parseInt(targetUid, 10))); - }); + db.isSortedSetMember('uid:' + uid + ':blocked_uids', String(targetUid), callback); }; - User.blocks.can = function (uid, callback) { + User.blocks.can = function (callerUid, blockerUid, blockeeUid, callback) { // Administrators and global moderators cannot be blocked - User.isAdminOrGlobalMod(uid, (err, can) => callback(err, !can)); + async.waterfall([ + function (next) { + async.parallel({ + isCallerAdminOrMod: function (next) { + User.isAdminOrGlobalMod(callerUid, next); + }, + isBlockeeAdminOrMod: function (next) { + User.isAdminOrGlobalMod(blockeeUid, next); + }, + }, next); + }, + function (results, next) { + if (results.isBlockeeAdminOrMod) { + return callback(null, false); + } + if (parseInt(callerUid, 10) !== parseInt(blockerUid, 10) && !results.isCallerAdminOrMod) { + return callback(null, false); + } + next(null, true); + }, + ], callback); }; User.blocks.list = function (uid, callback) { - if (User.blocks._cache.has(uid)) { - return setImmediate(callback, null, User.blocks._cache.get(uid)); - } - db.getSortedSetRange('uid:' + uid + ':blocked_uids', 0, -1, function (err, blocked) { if (err) { return callback(err); } blocked = blocked.map(uid => parseInt(uid, 10)).filter(Boolean); - User.blocks._cache.set(uid, blocked); callback(null, blocked); }); }; @@ -45,11 +51,6 @@ module.exports = function (User) { async.apply(this.applyChecks, true, targetUid, uid), async.apply(db.sortedSetAdd.bind(db), 'uid:' + uid + ':blocked_uids', Date.now(), targetUid), async.apply(User.incrementUserFieldBy, uid, 'blocksCount', 1), - function (_blank, next) { - User.blocks._cache.del(uid); - setImmediate(next); - }, - async.apply(User.blocks.list, uid), ], callback); }; @@ -58,11 +59,6 @@ module.exports = function (User) { async.apply(this.applyChecks, false, targetUid, uid), async.apply(db.sortedSetRemove.bind(db), 'uid:' + uid + ':blocked_uids', targetUid), async.apply(User.decrementUserFieldBy, uid, 'blocksCount', 1), - function (_blank, next) { - User.blocks._cache.del(uid); - setImmediate(next); - }, - async.apply(User.blocks.list, uid), ], callback); }; @@ -77,11 +73,14 @@ module.exports = function (User) { }; User.blocks.filterUids = function (targetUid, uids, callback) { - async.filter(uids, function (uid, next) { - User.blocks.is(targetUid, uid, function (err, blocked) { - next(err, !blocked); - }); - }, callback); + const sets = uids.map(uid => 'uid:' + uid + ':blocked_uids'); + db.isMemberOfSortedSets(sets, targetUid, function (err, isMembers) { + if (err) { + return callback(err); + } + uids = uids.filter((uid, index) => isMembers[index]); + callback(null, uids); + }); }; User.blocks.filter = function (uid, property, set, callback) { diff --git a/test/user.js b/test/user.js index b29cd8c865..4ee40c61a7 100644 --- a/test/user.js +++ b/test/user.js @@ -1797,6 +1797,30 @@ describe('User', function () { }); }); + describe('.toggle()', function () { + it('should toggle block', function (done) { + socketUser.toggleBlock({ uid: 1 }, { blockerUid: 1, blockeeUid: blockeeUid }, function (err) { + assert.ifError(err); + User.blocks.is(blockeeUid, 1, function (err, blocked) { + assert.ifError(err); + assert(blocked); + done(); + }); + }); + }); + + it('should toggle block', function (done) { + socketUser.toggleBlock({ uid: 1 }, { blockerUid: 1, blockeeUid: blockeeUid }, function (err) { + assert.ifError(err); + User.blocks.is(blockeeUid, 1, function (err, blocked) { + assert.ifError(err); + assert(!blocked); + done(); + }); + }); + }); + }); + describe('.add()', function () { it('should block a uid', function (done) { User.blocks.add(blockeeUid, 1, function (err, blocked_uids) { From cb8e62cd7cb5372b87b36484d97c69982bf1987f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 3 Jul 2018 15:47:28 -0400 Subject: [PATCH 17/27] fixes #6626 --- src/meta/themes.js | 4 ++-- src/views/admin/partials/theme_list.tpl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/meta/themes.js b/src/meta/themes.js index 0f22993c3f..d011bed707 100644 --- a/src/meta/themes.js +++ b/src/meta/themes.js @@ -104,9 +104,9 @@ Themes.get = function (callback) { // Minor adjustments for API output configObj.type = 'local'; if (configObj.screenshot) { - configObj.screenshot_url = 'css/previews/' + encodeURIComponent(configObj.id); + configObj.screenshot_url = nconf.get('relative_path') + '/css/previews/' + encodeURIComponent(configObj.id); } else { - configObj.screenshot_url = 'assets/images/themes/default.png'; + configObj.screenshot_url = nconf.get('relative_path') + '/assets/images/themes/default.png'; } next(null, configObj); } catch (err) { diff --git a/src/views/admin/partials/theme_list.tpl b/src/views/admin/partials/theme_list.tpl index aede3d71d0..26a226b803 100644 --- a/src/views/admin/partials/theme_list.tpl +++ b/src/views/admin/partials/theme_list.tpl @@ -1,7 +1,7 @@
      data-css="{themes.css}">
      -
      +

      {themes.name}

      From fb42862ec7a5a3d6a18cbf402818910eb9661129 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 3 Jul 2018 16:38:51 -0400 Subject: [PATCH 18/27] check password validity in user delete socket call --- public/src/client/account/edit.js | 16 +++------------- src/socket.io/user.js | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/public/src/client/account/edit.js b/public/src/client/account/edit.js index 9956c659c6..f7682aae1c 100644 --- a/public/src/client/account/edit.js +++ b/public/src/client/account/edit.js @@ -169,10 +169,9 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' confirmBtn.html(''); confirmBtn.prop('disabled', true); - socket.emit('user.checkPassword', { - uid: parseInt(ajaxify.data.uid, 10), + socket.emit('user.deleteAccount', { password: $('#confirm-password').val(), - }, function (err, ok) { + }, function (err) { function restoreButton() { translator.translate('[[modules:bootbox.confirm]]', function (confirmText) { confirmBtn.text(confirmText); @@ -183,19 +182,10 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' if (err) { restoreButton(); return app.alertError(err.message); - } else if (!ok) { - restoreButton(); - return app.alertError('[[error:invalid-password]]'); } confirmBtn.html(''); - socket.emit('user.deleteAccount', {}, function (err) { - if (err) { - return app.alertError(err.message); - } - - window.location.href = config.relative_path + '/'; - }); + window.location.href = config.relative_path + '/'; }); return false; diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 2534b156b0..5401ccca44 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -36,6 +36,11 @@ SocketUser.deleteAccount = function (socket, data, callback) { } async.waterfall([ + function (next) { + user.isPasswordCorrect(socket.uid, data.password, function (err, ok) { + next(err || !ok ? new Error('[[error:invalid-password]]') : undefined); + }); + }, function (next) { user.isAdministrator(socket.uid, next); }, @@ -56,7 +61,15 @@ SocketUser.deleteAccount = function (socket, data, callback) { }); next(); }, - ], callback); + ], function (err) { + if (err) { + return setTimeout(function () { + callback(err); + }, 2500); + } + + callback(); + }); }; SocketUser.emailExists = function (socket, data, callback) { From ad8ac2bdff4ae4fc3b599c79b16d7ff7917bb65d Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 3 Jul 2018 17:44:49 -0400 Subject: [PATCH 19/27] removed unused checkPassword socket call --- src/socket.io/user/profile.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/socket.io/user/profile.js b/src/socket.io/user/profile.js index 49e63744c6..5193d41c1d 100644 --- a/src/socket.io/user/profile.js +++ b/src/socket.io/user/profile.js @@ -109,13 +109,6 @@ module.exports = function (SocketUser) { ], callback); } - SocketUser.checkPassword = function (socket, data, callback) { - isPrivilegedOrSelfAndPasswordMatch(socket.uid, data, function (err) { - // Return a bool (without delayed response to prevent brute-force checking of password validity) - setTimeout(callback.bind(null, null, !err), 1000); - }); - }; - SocketUser.changePassword = function (socket, data, callback) { if (!socket.uid) { return callback(new Error('[[error:invalid-uid]]')); From ae0563375ed66437b723bada43f1286b16fadec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 3 Jul 2018 18:13:47 -0400 Subject: [PATCH 20/27] derp --- src/user/blocks.js | 14 +++++++------- test/controllers.js | 1 + test/user.js | 24 +++++++++++++++--------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/user/blocks.js b/src/user/blocks.js index d28ea5c505..483fae53f7 100644 --- a/src/user/blocks.js +++ b/src/user/blocks.js @@ -91,7 +91,7 @@ module.exports = function (User) { set = property; property = 'uid'; } - +console.log('derp') if (!Array.isArray(set) || !set.length || !set.every((item) => { if (!item) { return false; @@ -104,15 +104,15 @@ module.exports = function (User) { } const isPlain = typeof set[0] !== 'object'; - User.blocks.list(uid, function (err, blocked_uids) { + const values = set.map(function (item) { + return parseInt(isPlain ? item : item[property], 10); + }); + + db.isSortedSetMembers('uid:' + uid + ':blocked_uids', values, function (err, isMembers) { if (err) { return callback(err); } - - set = set.filter(function (item) { - return !blocked_uids.includes(parseInt(isPlain ? item : item[property], 10)); - }); - + set = set.filter((item, index) => !isMembers[index]); callback(null, set); }); }; diff --git a/test/controllers.js b/test/controllers.js index 302ddd62a0..2346be5df2 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -1229,6 +1229,7 @@ describe('Controllers', function () { function (res, body, next) { assert.equal(res.statusCode, 200); assert(body); + console.log(body); var notif = body.notifications[0]; assert.equal(notif.bodyShort, notifData.bodyShort); assert.equal(notif.bodyLong, notifData.bodyLong); diff --git a/test/user.js b/test/user.js index 4ee40c61a7..6d8abfa98e 100644 --- a/test/user.js +++ b/test/user.js @@ -1823,12 +1823,15 @@ describe('User', function () { describe('.add()', function () { it('should block a uid', function (done) { - User.blocks.add(blockeeUid, 1, function (err, blocked_uids) { + User.blocks.add(blockeeUid, 1, function (err) { assert.ifError(err); - assert.strictEqual(Array.isArray(blocked_uids), true); - assert.strictEqual(blocked_uids.length, 1); - assert.strictEqual(blocked_uids.includes(blockeeUid), true); - done(); + User.blocks.list(1, function (err, blocked_uids) { + assert.ifError(err); + assert.strictEqual(Array.isArray(blocked_uids), true); + assert.strictEqual(blocked_uids.length, 1); + assert.strictEqual(blocked_uids.includes(blockeeUid), true); + done(); + }); }); }); @@ -1850,11 +1853,14 @@ describe('User', function () { describe('.remove()', function () { it('should unblock a uid', function (done) { - User.blocks.remove(blockeeUid, 1, function (err, blocked_uids) { + User.blocks.remove(blockeeUid, 1, function (err) { assert.ifError(err); - assert.strictEqual(Array.isArray(blocked_uids), true); - assert.strictEqual(blocked_uids.length, 0); - done(); + User.blocks.list(1, function (err, blocked_uids) { + assert.ifError(err); + assert.strictEqual(Array.isArray(blocked_uids), true); + assert.strictEqual(blocked_uids.length, 0); + done(); + }); }); }); From 3449cf321bc43f145842c0345578fccc8c871675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 3 Jul 2018 18:43:29 -0400 Subject: [PATCH 21/27] add back cache and pubsub --- src/user/blocks.js | 62 ++++++++++++++++++++++++++++++++------------- test/controllers.js | 2 -- test/user.js | 8 ++++++ 3 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/user/blocks.js b/src/user/blocks.js index 483fae53f7..c390d41679 100644 --- a/src/user/blocks.js +++ b/src/user/blocks.js @@ -1,13 +1,25 @@ 'use strict'; var async = require('async'); +var LRU = require('lru-cache'); + + var db = require('../database'); +var pubsub = require('../pubsub'); module.exports = function (User) { - User.blocks = {}; + User.blocks = { + _cache: LRU({ + max: 100, + length: function () { return 1; }, + maxAge: 0, + }), + }; User.blocks.is = function (targetUid, uid, callback) { - db.isSortedSetMember('uid:' + uid + ':blocked_uids', String(targetUid), callback); + User.blocks.list(uid, function (err, blocks) { + callback(err, blocks.includes(parseInt(targetUid, 10))); + }); }; User.blocks.can = function (callerUid, blockerUid, blockeeUid, callback) { @@ -36,21 +48,35 @@ module.exports = function (User) { }; User.blocks.list = function (uid, callback) { + if (User.blocks._cache.has(uid)) { + return setImmediate(callback, null, User.blocks._cache.get(uid)); + } + db.getSortedSetRange('uid:' + uid + ':blocked_uids', 0, -1, function (err, blocked) { if (err) { return callback(err); } blocked = blocked.map(uid => parseInt(uid, 10)).filter(Boolean); + User.blocks._cache.set(uid, blocked); callback(null, blocked); }); }; + pubsub.on('user:blocks:cache:del', function (uid) { + User.blocks._cache.del(uid); + }); + User.blocks.add = function (targetUid, uid, callback) { async.waterfall([ async.apply(this.applyChecks, true, targetUid, uid), async.apply(db.sortedSetAdd.bind(db), 'uid:' + uid + ':blocked_uids', Date.now(), targetUid), async.apply(User.incrementUserFieldBy, uid, 'blocksCount', 1), + function (_blank, next) { + User.blocks._cache.del(uid); + pubsub.publish('user:blocks:cache:del', uid); + setImmediate(next); + }, ], callback); }; @@ -59,6 +85,11 @@ module.exports = function (User) { async.apply(this.applyChecks, false, targetUid, uid), async.apply(db.sortedSetRemove.bind(db), 'uid:' + uid + ':blocked_uids', targetUid), async.apply(User.decrementUserFieldBy, uid, 'blocksCount', 1), + function (_blank, next) { + User.blocks._cache.del(uid); + pubsub.publish('user:blocks:cache:del', uid); + setImmediate(next); + }, ], callback); }; @@ -73,14 +104,11 @@ module.exports = function (User) { }; User.blocks.filterUids = function (targetUid, uids, callback) { - const sets = uids.map(uid => 'uid:' + uid + ':blocked_uids'); - db.isMemberOfSortedSets(sets, targetUid, function (err, isMembers) { - if (err) { - return callback(err); - } - uids = uids.filter((uid, index) => isMembers[index]); - callback(null, uids); - }); + async.filter(uids, function (uid, next) { + User.blocks.is(targetUid, uid, function (err, blocked) { + next(err, !blocked); + }); + }, callback); }; User.blocks.filter = function (uid, property, set, callback) { @@ -91,7 +119,7 @@ module.exports = function (User) { set = property; property = 'uid'; } -console.log('derp') + if (!Array.isArray(set) || !set.length || !set.every((item) => { if (!item) { return false; @@ -104,15 +132,15 @@ console.log('derp') } const isPlain = typeof set[0] !== 'object'; - const values = set.map(function (item) { - return parseInt(isPlain ? item : item[property], 10); - }); - - db.isSortedSetMembers('uid:' + uid + ':blocked_uids', values, function (err, isMembers) { + User.blocks.list(uid, function (err, blocked_uids) { if (err) { return callback(err); } - set = set.filter((item, index) => !isMembers[index]); + + set = set.filter(function (item) { + return !blocked_uids.includes(parseInt(isPlain ? item : item[property], 10)); + }); + callback(null, set); }); }; diff --git a/test/controllers.js b/test/controllers.js index 2346be5df2..2104fc3230 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -1229,7 +1229,6 @@ describe('Controllers', function () { function (res, body, next) { assert.equal(res.statusCode, 200); assert(body); - console.log(body); var notif = body.notifications[0]; assert.equal(notif.bodyShort, notifData.bodyShort); assert.equal(notif.bodyLong, notifData.bodyLong); @@ -2152,7 +2151,6 @@ describe('Controllers', function () { request(nconf.get('url') + '/api/compose', { json: true }, function (err, res, body) { assert.ifError(err); assert.equal(res.statusCode, 404); - console.log(body); plugins.unregisterHook('myTestPlugin', 'filter:composer.build', hookMethod); done(); diff --git a/test/user.js b/test/user.js index 6d8abfa98e..96b47921c6 100644 --- a/test/user.js +++ b/test/user.js @@ -1965,6 +1965,14 @@ describe('User', function () { done(); }); }); + + it('should filter uids that are blocking targetUid', function (done) { + User.blocks.filterUids(blockeeUid, [1, 2], function (err, filtered) { + assert.ifError(err); + assert.deepEqual(filtered, [2]); + done(); + }); + }); }); }); From 7d7a490550824c019a244e0fe2fa4ea94ce976b4 Mon Sep 17 00:00:00 2001 From: "Misty (Bot)" Date: Wed, 4 Jul 2018 09:29:14 +0000 Subject: [PATCH 22/27] Latest translations and fallbacks --- .../zh-TW/admin/general/languages.json | 8 ++++---- public/language/zh-TW/flags.json | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/public/language/zh-TW/admin/general/languages.json b/public/language/zh-TW/admin/general/languages.json index bdd57849b3..de8ef3e3a4 100644 --- a/public/language/zh-TW/admin/general/languages.json +++ b/public/language/zh-TW/admin/general/languages.json @@ -1,6 +1,6 @@ { - "language-settings": "Language Settings", - "description": "The default language determines the language settings for all users who are visiting your forum.
      Individual users can override the default language on their account settings page.", - "default-language": "Default Language", - "auto-detect": "Auto Detect Language Setting for Guests" + "language-settings": "語言設定", + "description": "所有使用者的預設語言,使用者可以在個人設定內修改", + "default-language": "預設語言", + "auto-detect": "使用者為訪客時,自動偵測語言設定" } \ No newline at end of file diff --git a/public/language/zh-TW/flags.json b/public/language/zh-TW/flags.json index 5d8e09a48a..cac2293840 100644 --- a/public/language/zh-TW/flags.json +++ b/public/language/zh-TW/flags.json @@ -6,20 +6,20 @@ "no-flags": "Hooray! No flags found.", "assignee": "Assignee", "update": "更新", - "updated": "Updated", + "updated": "更新完成", "target-purged": "The content this flag referred to has been purged and is no longer available.", "quick-filters": "快速篩選", "filter-active": "There are one or more filters active in this list of flags", - "filter-reset": "Remove Filters", + "filter-reset": "移除篩選", "filters": "Filter Options", "filter-reporterId": "Reporter UID", "filter-targetUid": "Flagged UID", "filter-type": "Flag Type", "filter-type-all": "All Content", "filter-type-post": "文章", - "filter-type-user": "User", - "filter-state": "State", + "filter-type-user": "用戶", + "filter-state": "狀態", "filter-assignee": "Assignee UID", "filter-cid": "分類", "filter-quick-mine": "Assigned to me", @@ -32,11 +32,11 @@ "start-new-chat": "Start New Chat", "go-to-target": "View Flag Target", - "user-view": "View Profile", - "user-edit": "Edit Profile", + "user-view": "查看個人資料", + "user-edit": "編輯個人資料", - "notes": "Flag Notes", - "add-note": "Add Note", + "notes": "標記備註", + "add-note": "新增備註", "no-notes": "No shared notes.", "history": "Flag History", @@ -47,7 +47,7 @@ "state-open": "New/Open", "state-wip": "Work in Progress", "state-resolved": "Resolved", - "state-rejected": "Rejected", + "state-rejected": "已拒絕", "no-assignee": "Not Assigned", "note-added": "Note Added", From f09b1acfb74840c4e1350e80e8aad2f0ace81781 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 4 Jul 2018 09:52:20 -0400 Subject: [PATCH 23/27] closes #6627 --- src/controllers/index.js | 59 +++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/src/controllers/index.js b/src/controllers/index.js index 052995c60b..a91636dfc7 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -39,32 +39,41 @@ Controllers.errors = require('./errors'); Controllers.composer = require('./composer'); Controllers.reset = function (req, res, next) { + const renderReset = function (code, valid) { + res.render('reset_code', { + valid: valid, + displayExpiryNotice: req.session.passwordExpired, + code: code, + minimumPasswordLength: parseInt(meta.config.minimumPasswordLength, 10), + minimumPasswordStrength: parseInt(meta.config.minimumPasswordStrength, 10), + breadcrumbs: helpers.buildBreadcrumbs([ + { + text: '[[reset_password:reset_password]]', + url: '/reset', + }, + { + text: '[[reset_password:update_password]]', + }, + ]), + title: '[[pages:reset]]', + }); + delete req.session.passwordExpired; + }; + if (req.params.code) { - async.waterfall([ - function (next) { - user.reset.validate(req.params.code, next); - }, - function (valid) { - res.render('reset_code', { - valid: valid, - displayExpiryNotice: req.session.passwordExpired, - code: req.params.code, - minimumPasswordLength: parseInt(meta.config.minimumPasswordLength, 10), - minimumPasswordStrength: parseInt(meta.config.minimumPasswordStrength, 10), - breadcrumbs: helpers.buildBreadcrumbs([ - { - text: '[[reset_password:reset_password]]', - url: '/reset', - }, - { - text: '[[reset_password:update_password]]', - }, - ]), - title: '[[pages:reset]]', - }); - delete req.session.passwordExpired; - }, - ], next); + // Save to session and redirect + req.session.reset_code = req.params.code; + res.redirect(nconf.get('relative_path') + '/reset'); + } else if (req.session.reset_code) { + // Validate and save to local variable before removing from session + user.reset.validate(req.session.reset_code, function (err, valid) { + if (err) { + return next(err); + } + + renderReset(req.session.reset_code, valid); + delete req.session.reset_code; + }); } else { res.render('reset', { code: null, From 6811086bb24bc61626c14891348f4ea442cd6b3d Mon Sep 17 00:00:00 2001 From: "Misty (Bot)" Date: Thu, 5 Jul 2018 09:29:23 +0000 Subject: [PATCH 24/27] Latest translations and fallbacks --- public/language/sk/admin/manage/privileges.json | 2 +- public/language/sk/admin/settings/advanced.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/language/sk/admin/manage/privileges.json b/public/language/sk/admin/manage/privileges.json index 51c095211a..8579b29fd6 100644 --- a/public/language/sk/admin/manage/privileges.json +++ b/public/language/sk/admin/manage/privileges.json @@ -20,7 +20,7 @@ "edit-posts": "Upraviť príspevky", "view-edit-history": "Zobraziť históriu úprav", "delete-posts": "Odstrániť príspevky", - "view_deleted": "View Deleted Posts", + "view_deleted": "Zobraziť odstránené príspevky", "upvote-posts": "Súhlasné príspevky", "downvote-posts": "Nesúhlasné príspevky", "delete-topics": "Odstrániť témy", diff --git a/public/language/sk/admin/settings/advanced.json b/public/language/sk/admin/settings/advanced.json index 0d96976d47..b3678dd04a 100644 --- a/public/language/sk/admin/settings/advanced.json +++ b/public/language/sk/admin/settings/advanced.json @@ -8,7 +8,7 @@ "headers.acao": "Access-Control-Allow-Origin", "headers.acao-regex": "Access-Control-Allow-Origin Regular Expression", "headers.acao-help": "Ak chcete zamietnuť prístup na všetky stránky, nechajte prázdne", - "headers.acao-regex-help": "Enter regular expressions here to match dynamic origins. To deny access to all sites, leave empty", + "headers.acao-regex-help": "Sem zadajte regulárne výrazy, ktoré zodpovedajú dynamickým originálom. Pre zakázanie všetkých stránok, ponechajte prázdne.", "headers.acac": "Access-Control-Allow-Credentials", "headers.acam": "Access-Control-Allow-Methods", "headers.acah": "Access-Control-Allow-Headers", From a34584e8f5f78a64fd2f1d99e3d02dba7190ad8b Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 5 Jul 2018 14:18:03 -0400 Subject: [PATCH 25/27] fixed blocking cache derp --- src/user/blocks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user/blocks.js b/src/user/blocks.js index c390d41679..a3021968e8 100644 --- a/src/user/blocks.js +++ b/src/user/blocks.js @@ -58,7 +58,7 @@ module.exports = function (User) { } blocked = blocked.map(uid => parseInt(uid, 10)).filter(Boolean); - User.blocks._cache.set(uid, blocked); + User.blocks._cache.set(parseInt(uid, 10), blocked); callback(null, blocked); }); }; From 7a53fa9469f0fc0427727cde2498f889a4fc02ef Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 5 Jul 2018 14:18:29 -0400 Subject: [PATCH 26/27] Added block and unblock button to profile dropdown menu, #6560 --- public/language/en-GB/user.json | 2 ++ public/src/client/account/header.js | 20 ++++++++++++++++++++ src/controllers/accounts/helpers.js | 9 ++++++++- src/middleware/user.js | 12 ------------ src/routes/accounts.js | 4 ++-- src/socket.io/user/profile.js | 7 ++++++- 6 files changed, 38 insertions(+), 16 deletions(-) diff --git a/public/language/en-GB/user.json b/public/language/en-GB/user.json index a6f389b888..d69941be5d 100644 --- a/public/language/en-GB/user.json +++ b/public/language/en-GB/user.json @@ -33,6 +33,8 @@ "following": "Following", "blocks": "Blocks", "block_toggle": "Toggle Block", + "block_user": "Block User", + "unblock_user": "Unblock User", "aboutme": "About me", "signature": "Signature", "birthday": "Birthday", diff --git a/public/src/client/account/header.js b/public/src/client/account/header.js index 1ecacc812d..100256e762 100644 --- a/public/src/client/account/header.js +++ b/public/src/client/account/header.js @@ -53,6 +53,7 @@ define('forum/account/header', [ components.get('account/unban').on('click', unbanAccount); components.get('account/delete').on('click', deleteAccount); components.get('account/flag').on('click', flagAccount); + components.get('account/block').on('click', toggleBlockAccount); }; function hidePrivateLinks() { @@ -191,6 +192,25 @@ define('forum/account/header', [ }); } + function toggleBlockAccount() { + var targetEl = this; + socket.emit('user.toggleBlock', { + blockeeUid: ajaxify.data.uid, + blockerUid: app.user.uid, + }, function (err, blocked) { + if (err) { + return app.alertError(err.message); + } + + translator.translate('[[user:' + (blocked ? 'unblock' : 'block') + '_user]]', function (label) { + $(targetEl).text(label); + }); + }); + + // Keep dropdown open + return false; + } + function removeCover() { translator.translate('[[user:remove_cover_picture_confirm]]', function (translated) { bootbox.confirm(translated, function (confirm) { diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index f2f418a52f..1d2a30272e 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -91,6 +91,9 @@ helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) { canBanUser: function (next) { privileges.users.canBanUser(callerUID, uid, next); }, + isBlocked: function (next) { + user.blocks.is(uid, callerUID, next); + }, }, next); }, function (results, next) { @@ -129,6 +132,11 @@ helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) { userData.moderationNote = undefined; } + userData.isBlocked = results.isBlocked; + if (isAdmin || isSelf) { + userData.blocksCount = parseInt(userData.blocksCount, 10) || 0; + } + userData.yourid = callerUID; userData.theirid = userData.uid; userData.isTargetAdmin = results.isTargetAdmin; @@ -165,7 +173,6 @@ helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) { userData.websiteName = userData.website.replace(validator.escape('http://'), '').replace(validator.escape('https://'), ''); userData.followingCount = parseInt(userData.followingCount, 10) || 0; userData.followerCount = parseInt(userData.followerCount, 10) || 0; - userData.blocksCount = parseInt(userData.blocksCount, 10) || 0; userData.email = validator.escape(String(userData.email || '')); userData.fullname = validator.escape(String(userData.fullname || '')); diff --git a/src/middleware/user.js b/src/middleware/user.js index e7c6c7ef36..17c52e7ca6 100644 --- a/src/middleware/user.js +++ b/src/middleware/user.js @@ -223,16 +223,4 @@ module.exports = function (middleware) { return next(); } }; - - middleware.handleBlocking = function (req, res, next) { - user.blocks.is(res.locals.uid, req.uid, function (err, blocked) { - if (err) { - return next(err); - } else if (blocked) { - res.status(404).render('404', { title: '[[global:404.title]]' }); - } else { - return next(); - } - }); - }; }; diff --git a/src/routes/accounts.js b/src/routes/accounts.js index 56cedb809a..9febb67391 100644 --- a/src/routes/accounts.js +++ b/src/routes/accounts.js @@ -4,8 +4,8 @@ var helpers = require('./helpers'); var setupPageRoute = helpers.setupPageRoute; module.exports = function (app, middleware, controllers) { - var middlewares = [middleware.checkGlobalPrivacySettings, middleware.exposeUid, middleware.handleBlocking]; - var accountMiddlewares = [middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, middleware.exposeUid, middleware.handleBlocking]; + var middlewares = [middleware.checkGlobalPrivacySettings, middleware.exposeUid]; + var accountMiddlewares = [middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, middleware.exposeUid]; setupPageRoute(app, '/me/*', middleware, [], middleware.redirectMeToUserslug); setupPageRoute(app, '/uid/:uid*', middleware, [], middleware.redirectUidToUserslug); diff --git a/src/socket.io/user/profile.js b/src/socket.io/user/profile.js index 821dc77dd6..6cf76be9ee 100644 --- a/src/socket.io/user/profile.js +++ b/src/socket.io/user/profile.js @@ -201,6 +201,8 @@ module.exports = function (SocketUser) { }; SocketUser.toggleBlock = function (socket, data, callback) { + let current; + async.waterfall([ function (next) { user.blocks.can(socket.uid, data.blockerUid, data.blockeeUid, next); @@ -212,8 +214,11 @@ module.exports = function (SocketUser) { user.blocks.is(data.blockeeUid, data.blockerUid, next); }, function (is, next) { + current = is; user.blocks[is ? 'remove' : 'add'](data.blockeeUid, data.blockerUid, next); }, - ], callback); + ], function (err) { + callback(err, !current); + }); }; }; From b88a8de6a159d0b2cd5114e084b38c82c24d5a2a Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 5 Jul 2018 14:20:26 -0400 Subject: [PATCH 27/27] bump themes, closes #6560 --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 2b85e914a8..80dbcd4363 100644 --- a/install/package.json +++ b/install/package.json @@ -75,9 +75,9 @@ "nodebb-plugin-spam-be-gone": "0.5.4", "nodebb-rewards-essentials": "0.0.11", "nodebb-theme-lavender": "5.0.5", - "nodebb-theme-persona": "9.0.18", + "nodebb-theme-persona": "9.0.19", "nodebb-theme-slick": "1.2.6", - "nodebb-theme-vanilla": "10.0.16", + "nodebb-theme-vanilla": "10.0.17", "nodebb-widget-essentials": "4.0.7", "nodemailer": "^4.6.5", "passport": "^0.4.0",

      - + -
      {group.members.icon:text}
      +
      {group.members.icon:text}