diff --git a/.gitignore b/.gitignore index 25ad8bffae..028f91e53b 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,5 @@ coverage build *.log +test/files/normalise.jpg.png +test/files/normalise-resized.jpg diff --git a/package.json b/package.json index a3b372e18d..f19e975b18 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPL-3.0", "description": "NodeBB Forum", - "version": "1.5.0", + "version": "1.5.1", "homepage": "http://www.nodebb.org", "repository": { "type": "git", @@ -45,6 +45,7 @@ "jquery": "^3.1.0", "json-2-csv": "^2.0.22", "less": "^2.0.0", + "lodash": "^4.17.4", "lodash.padstart": "^4.6.1", "logrotate-stream": "^0.2.3", "lru-cache": "4.0.2", @@ -93,8 +94,6 @@ "templates.js": "0.3.11", "toobusy-js": "^0.5.1", "uglify-js": "^3.0.11", - "underscore": "^1.8.3", - "underscore.deep": "^0.5.1", "validator": "7.0.0", "winston": "^2.1.0", "xml": "^1.0.1", @@ -138,4 +137,4 @@ "url": "https://github.com/barisusakli" } ] -} +} \ No newline at end of file diff --git a/public/src/admin/manage/category.js b/public/src/admin/manage/category.js index 7911bb5b84..1dbd31aaac 100644 --- a/public/src/admin/manage/category.js +++ b/public/src/admin/manage/category.js @@ -12,11 +12,15 @@ define('admin/manage/category', [ var modified_categories = {}; Category.init = function () { - $('.blockclass, form.category select').each(function () { + $('#category-settings select').each(function () { var $this = $(this); $this.val($this.attr('data-value')); }); + $('#category-selector').on('change', function () { + ajaxify.go('admin/manage/categories/' + $(this).val()); + }); + function enableColorPicker(idx, inputEl) { var $inputEl = $(inputEl); var previewEl = $inputEl.parents('[data-cid]').find('.category-preview'); @@ -33,7 +37,7 @@ define('admin/manage/category', [ } - $('form.category input, form.category select').not($('.privilege-table-container input')) + $('#category-settings input, #category-settings select').not($('.privilege-table-container input')) .on('change', function (ev) { modified(ev.target); }) @@ -438,6 +442,5 @@ define('admin/manage/category', [ }); } - return Category; }); diff --git a/src/categories.js b/src/categories.js index 3d5b012f53..787853faa7 100644 --- a/src/categories.js +++ b/src/categories.js @@ -329,22 +329,23 @@ Categories.buildForSelect = function (uid, callback) { recursive(child, categoriesData, ' ' + level); }); } - Categories.getCategoriesByPrivilege('cid:0:children', uid, 'read', function (err, categories) { - if (err) { - return callback(err); - } - - var categoriesData = []; + async.waterfall([ + function (next) { + Categories.getCategoriesByPrivilege('cid:0:children', uid, 'read', next); + }, + function (categories, next) { + var categoriesData = []; - categories = categories.filter(function (category) { - return category && !category.link && !parseInt(category.parentCid, 10); - }); + categories = categories.filter(function (category) { + return category && !category.link && !parseInt(category.parentCid, 10); + }); - categories.forEach(function (category) { - recursive(category, categoriesData, ''); - }); - callback(null, categoriesData); - }); + categories.forEach(function (category) { + recursive(category, categoriesData, ''); + }); + next(null, categoriesData); + }, + ], callback); }; Categories.getIgnorers = function (cid, start, stop, callback) { diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js index 9c36829fd1..38f7f0a087 100644 --- a/src/categories/recentreplies.js +++ b/src/categories/recentreplies.js @@ -2,7 +2,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var db = require('../database'); var posts = require('../posts'); diff --git a/src/controllers/admin/categories.js b/src/controllers/admin/categories.js index 3a3b1a6fa4..3dae05a388 100644 --- a/src/controllers/admin/categories.js +++ b/src/controllers/admin/categories.js @@ -8,34 +8,47 @@ var analytics = require('../../analytics'); var plugins = require('../../plugins'); var translator = require('../../translator'); +var categoriesController = module.exports; -var categoriesController = {}; - -categoriesController.get = function (req, res, next) { - async.parallel({ - category: async.apply(categories.getCategories, [req.params.category_id], req.user.uid), - privileges: async.apply(privileges.categories.list, req.params.category_id), - }, function (err, data) { - if (err) { - return next(err); - } - var category = data.category[0]; - - if (!category) { - return next(); - } - - plugins.fireHook('filter:admin.category.get', { req: req, res: res, category: category, privileges: data.privileges }, function (err, data) { - if (err) { - return next(err); +categoriesController.get = function (req, res, callback) { + async.waterfall([ + function (next) { + async.parallel({ + category: async.apply(categories.getCategories, [req.params.category_id], req.user.uid), + privileges: async.apply(privileges.categories.list, req.params.category_id), + allCategories: async.apply(categories.buildForSelect, req.uid), + }, next); + }, + function (data, next) { + var category = data.category[0]; + + if (!category) { + return callback(); } + + data.allCategories.forEach(function (category) { + if (category) { + category.selected = parseInt(category.cid, 10) === parseInt(req.params.category_id, 10); + } + }); + + plugins.fireHook('filter:admin.category.get', { + req: req, + res: res, + category: category, + privileges: data.privileges, + allCategories: data.allCategories, + }, next); + }, + function (data) { data.category.name = translator.escape(String(data.category.name)); res.render('admin/manage/category', { category: data.category, privileges: data.privileges, + allCategories: data.allCategories, }); - }); - }); + }, + ], callback); }; categoriesController.getAll = function (req, res) { @@ -44,17 +57,15 @@ categoriesController.getAll = function (req, res) { }; categoriesController.getAnalytics = function (req, res, next) { - async.parallel({ - name: async.apply(categories.getCategoryField, req.params.category_id, 'name'), - analytics: async.apply(analytics.getCategoryAnalytics, req.params.category_id), - }, function (err, data) { - if (err) { - return next(err); - } - - res.render('admin/manage/category-analytics', data); - }); + async.waterfall([ + function (next) { + async.parallel({ + name: async.apply(categories.getCategoryField, req.params.category_id, 'name'), + analytics: async.apply(analytics.getCategoryAnalytics, req.params.category_id), + }, next); + }, + function (data) { + res.render('admin/manage/category-analytics', data); + }, + ], next); }; - - -module.exports = categoriesController; diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 210bbf4bf9..5309bdc380 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -5,7 +5,7 @@ var winston = require('winston'); var passport = require('passport'); var nconf = require('nconf'); var validator = require('validator'); -var _ = require('underscore'); +var _ = require('lodash'); var db = require('../database'); var meta = require('../meta'); diff --git a/src/database/mongo.js b/src/database/mongo.js index 507a9c9a86..14dcd330ac 100644 --- a/src/database/mongo.js +++ b/src/database/mongo.js @@ -6,12 +6,10 @@ var winston = require('winston'); var async = require('async'); var nconf = require('nconf'); var session = require('express-session'); -var _ = require('underscore'); +var _ = require('lodash'); var semver = require('semver'); var db; -_.mixin(require('underscore.deep')); - var mongoModule = module.exports; mongoModule.questions = [ @@ -87,7 +85,7 @@ mongoModule.init = function (callback) { autoReconnect: true, }; - connOptions = _.deepExtend(connOptions, nconf.get('mongo:options') || {}); + connOptions = _.merge(connOptions, nconf.get('mongo:options') || {}); mongoClient.connect(connString, connOptions, function (err, _db) { if (err) { diff --git a/src/database/redis.js b/src/database/redis.js index d0d80d0038..75129b6c8b 100644 --- a/src/database/redis.js +++ b/src/database/redis.js @@ -1,6 +1,6 @@ 'use strict'; -var _ = require('underscore'); +var _ = require('lodash'); var async = require('async'); var winston = require('winston'); var nconf = require('nconf'); @@ -9,8 +9,6 @@ var session = require('express-session'); var redis = require('redis'); var redisClient; -_.mixin(require('underscore.deep')); - var redisModule = module.exports; redisModule.questions = [ @@ -78,7 +76,7 @@ redisModule.connect = function (options) { options.auth_pass = nconf.get('redis:password'); } - options = _.deepExtend(options, nconf.get('redis:options') || {}); + options = _.merge(options, nconf.get('redis:options') || {}); if (redis_socket_or_host && redis_socket_or_host.indexOf('/') >= 0) { /* If redis.host contains a path name character, use the unix dom sock connection. ie, /tmp/redis.sock */ diff --git a/src/flags.js b/src/flags.js index 14c6011691..1f6d932de1 100644 --- a/src/flags.js +++ b/src/flags.js @@ -1,6 +1,9 @@ 'use strict'; var async = require('async'); +var _ = require('lodash'); +var S = require('string'); + var db = require('./database'); var user = require('./user'); var groups = require('./groups'); @@ -12,8 +15,6 @@ var posts = require('./posts'); var privileges = require('./privileges'); var plugins = require('./plugins'); var utils = require('../public/src/utils'); -var _ = require('underscore'); -var S = require('string'); var Flags = module.exports; diff --git a/src/groups/membership.js b/src/groups/membership.js index 45f16ea607..1fc06cb5a5 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -2,7 +2,7 @@ var async = require('async'); var winston = require('winston'); -var _ = require('underscore'); +var _ = require('lodash'); var user = require('../user'); var utils = require('../utils'); @@ -458,7 +458,7 @@ module.exports = function (Groups) { }, function (_members, next) { members = _members; - uniqueGroups = _.unique(_.flatten(members)); + uniqueGroups = _.uniq(_.flatten(members)); uniqueGroups = Groups.removeEphemeralGroups(uniqueGroups); Groups.isMemberOfGroups(uid, uniqueGroups, next); diff --git a/src/meta/languages.js b/src/meta/languages.js index 5692533756..06c73ace2e 100644 --- a/src/meta/languages.js +++ b/src/meta/languages.js @@ -6,7 +6,7 @@ var async = require('async'); var fs = require('fs'); var mkdirp = require('mkdirp'); var rimraf = require('rimraf'); -var _ = require('underscore'); +var _ = require('lodash'); var file = require('../file'); var Plugins = require('../plugins'); diff --git a/src/notifications.js b/src/notifications.js index eb9820a952..b11e7ed392 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -5,7 +5,7 @@ var winston = require('winston'); var cron = require('cron').CronJob; var nconf = require('nconf'); var S = require('string'); -var _ = require('underscore'); +var _ = require('lodash'); var db = require('./database'); var User = require('./user'); @@ -247,7 +247,7 @@ Notifications.pushGroups = function (notification, groupNames, callback) { groups.getMembersOfGroups(groupNames, next); }, function (groupMembers, next) { - var members = _.unique(_.flatten(groupMembers)); + var members = _.uniq(_.flatten(groupMembers)); Notifications.push(notification, members, next); }, ], callback); diff --git a/src/pagination.js b/src/pagination.js index 4058e7f8f4..8405fafd50 100644 --- a/src/pagination.js +++ b/src/pagination.js @@ -1,7 +1,7 @@ 'use strict'; var qs = require('querystring'); -var _ = require('underscore'); +var _ = require('lodash'); var pagination = {}; diff --git a/src/plugins/load.js b/src/plugins/load.js index c2456397fe..b077a3ed4e 100644 --- a/src/plugins/load.js +++ b/src/plugins/load.js @@ -5,7 +5,7 @@ var semver = require('semver'); var async = require('async'); var winston = require('winston'); var nconf = require('nconf'); -var _ = require('underscore'); +var _ = require('lodash'); var meta = require('../meta'); diff --git a/src/posts.js b/src/posts.js index 492599e4cd..7c4678830f 100644 --- a/src/posts.js +++ b/src/posts.js @@ -1,7 +1,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var db = require('./database'); var utils = require('./utils'); diff --git a/src/posts/category.js b/src/posts/category.js index 6efbf1ec7d..42319fd6ed 100644 --- a/src/posts/category.js +++ b/src/posts/category.js @@ -2,7 +2,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var db = require('../database'); var topics = require('../topics'); diff --git a/src/posts/create.js b/src/posts/create.js index 8386582eae..cbfd9de214 100644 --- a/src/posts/create.js +++ b/src/posts/create.js @@ -1,7 +1,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var meta = require('../meta'); var db = require('../database'); diff --git a/src/posts/delete.js b/src/posts/delete.js index fe718d327c..9b40f3ede5 100644 --- a/src/posts/delete.js +++ b/src/posts/delete.js @@ -1,7 +1,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var db = require('../database'); var topics = require('../topics'); diff --git a/src/posts/edit.js b/src/posts/edit.js index 4780296594..65ca05fc2f 100644 --- a/src/posts/edit.js +++ b/src/posts/edit.js @@ -2,7 +2,7 @@ var async = require('async'); var validator = require('validator'); -var _ = require('underscore'); +var _ = require('lodash'); var db = require('../database'); var topics = require('../topics'); diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 80c34f44c3..977485e976 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -2,7 +2,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var categories = require('../categories'); var user = require('../user'); @@ -58,7 +58,7 @@ module.exports = function (privileges) { }); }); - var members = _.unique(_.flatten(memberSets)); + var members = _.uniq(_.flatten(memberSets)); user.getUsersFields(members, ['picture', 'username'], next); }, @@ -93,7 +93,7 @@ module.exports = function (privileges) { }, function (results, next) { var memberSets = results.memberSets; - var uniqueGroups = _.unique(_.flatten(memberSets)); + var uniqueGroups = _.uniq(_.flatten(memberSets)); var groupNames = results.groupNames.filter(function (groupName) { return groupName.indexOf(':privileges:') === -1 && uniqueGroups.indexOf(groupName) !== -1; @@ -171,7 +171,7 @@ module.exports = function (privileges) { }, next); }, function (results, next) { - var privData = _.object(privs, results.privileges); + var privData = _.zipObject(privs, results.privileges); var isAdminOrMod = results.isAdministrator || results.isModerator; plugins.fireHook('filter:privileges.categories.get', { diff --git a/src/privileges/topics.js b/src/privileges/topics.js index 1299713ea7..88273800fe 100644 --- a/src/privileges/topics.js +++ b/src/privileges/topics.js @@ -2,7 +2,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var meta = require('../meta'); var topics = require('../topics'); @@ -29,7 +29,7 @@ module.exports = function (privileges) { }, next); }, function (results, next) { - var privData = _.object(privs, results.privileges); + var privData = _.zipObject(privs, results.privileges); var disabled = parseInt(results.disabled, 10) === 1; var locked = parseInt(topic.locked, 10) === 1; var deleted = parseInt(topic.deleted, 10) === 1; diff --git a/src/socket.io/posts/edit.js b/src/socket.io/posts/edit.js index 513f3f55dc..646c51228f 100644 --- a/src/socket.io/posts/edit.js +++ b/src/socket.io/posts/edit.js @@ -2,7 +2,7 @@ var async = require('async'); var validator = require('validator'); -var _ = require('underscore'); +var _ = require('lodash'); var S = require('string'); var posts = require('../../posts'); @@ -69,7 +69,7 @@ module.exports = function (SocketPosts) { ], next); }, function (results, next) { - var uids = _.unique(_.flatten(results).concat(socket.uid.toString())); + var uids = _.uniq(_.flatten(results).concat(socket.uid.toString())); uids.forEach(function (uid) { websockets.in('uid_' + uid).emit('event:post_edited', editResult); }); diff --git a/src/topics.js b/src/topics.js index ca80686bd4..575199d400 100644 --- a/src/topics.js +++ b/src/topics.js @@ -1,7 +1,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var db = require('./database'); var posts = require('./posts'); @@ -135,8 +135,8 @@ Topics.getTopicsByTids = function (tids, uid, callback) { }, next); }, function (results, next) { - var users = _.object(uids, results.users); - var categories = _.object(cids, results.categories); + var users = _.zipObject(uids, results.users); + var categories = _.zipObject(cids, results.categories); for (var i = 0; i < topics.length; i += 1) { if (topics[i]) { diff --git a/src/topics/create.js b/src/topics/create.js index f7ee2e326e..071093e967 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -2,7 +2,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var validator = require('validator'); var S = require('string'); var db = require('../database'); diff --git a/src/topics/posts.js b/src/topics/posts.js index 08b5db8e01..8377215609 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -2,7 +2,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var validator = require('validator'); var db = require('../database'); diff --git a/src/topics/suggested.js b/src/topics/suggested.js index 16548382e3..33153a580c 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -2,7 +2,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var categories = require('../categories'); var search = require('../search'); @@ -51,7 +51,7 @@ module.exports = function (Topics) { }, next); }, function (data, next) { - next(null, _.unique(_.flatten(data))); + next(null, _.uniq(_.flatten(data))); }, ], callback); } diff --git a/src/topics/tags.js b/src/topics/tags.js index d2f2b32694..dbfb092cc1 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -5,7 +5,7 @@ var async = require('async'); var db = require('../database'); var meta = require('../meta'); -var _ = require('underscore'); +var _ = require('lodash'); var plugins = require('../plugins'); var utils = require('../utils'); @@ -247,7 +247,7 @@ module.exports = function (Topics) { tag.score = results.counts[index] ? results.counts[index] : 0; }); - var tagData = _.object(uniqueTopicTags, results.tagData); + var tagData = _.zipObject(uniqueTopicTags, results.tagData); topicTags.forEach(function (tags, index) { if (Array.isArray(tags)) { @@ -444,7 +444,7 @@ module.exports = function (Topics) { }, next); }, function (tids, next) { - tids = _.shuffle(_.unique(_.flatten(tids))).slice(0, maximumTopics); + tids = _.shuffle(_.uniq(_.flatten(tids))).slice(0, maximumTopics); Topics.getTopics(tids, uid, next); }, function (topics, next) { diff --git a/src/topics/tools.js b/src/topics/tools.js index a23bfca3fd..db112e9daa 100644 --- a/src/topics/tools.js +++ b/src/topics/tools.js @@ -1,7 +1,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var db = require('../database'); var categories = require('../categories'); @@ -210,7 +210,7 @@ module.exports = function (Topics) { Topics.getTopicsFields(tids, ['cid'], next); }, function (topicData, next) { - var uniqueCids = _.unique(topicData.map(function (topicData) { + var uniqueCids = _.uniq(topicData.map(function (topicData) { return topicData && parseInt(topicData.cid, 10); })); diff --git a/src/upgrades/1.4.6/delete_sessions.js b/src/upgrades/1.4.6/delete_sessions.js index 571d4e125c..29d11db48a 100644 --- a/src/upgrades/1.4.6/delete_sessions.js +++ b/src/upgrades/1.4.6/delete_sessions.js @@ -1,21 +1,22 @@ 'use strict'; -var db = require('../../database'); var async = require('async'); +var db = require('../../database'); +var batch = require('../../batch'); + module.exports = { name: 'Delete accidentally long-lived sessions', timestamp: Date.UTC(2017, 3, 16), method: function (callback) { - var configJSON = require.main.require('./config.json'); + var configJSON = require('../../../config.json'); var isRedisSessionStore = configJSON.hasOwnProperty('redis'); var progress = this.progress; async.waterfall([ function (next) { if (isRedisSessionStore) { - var rdb = require.main.require('./src/database/redis'); - var batch = require.main.require('./src/batch'); + var rdb = require('../../database/redis'); var client = rdb.connect(); async.waterfall([ function (next) { diff --git a/src/user.js b/src/user.js index d319e930cf..e4ad24283c 100644 --- a/src/user.js +++ b/src/user.js @@ -1,7 +1,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var groups = require('./groups'); var plugins = require('./plugins'); diff --git a/src/user/auth.js b/src/user/auth.js index 2b72ee3c95..0a5c06fcb6 100644 --- a/src/user/auth.js +++ b/src/user/auth.js @@ -154,7 +154,7 @@ module.exports = function (User) { }; User.auth.deleteAllSessions = function (callback) { - var _ = require('underscore'); + var _ = require('lodash'); batch.processSortedSet('users:joindate', function (uids, next) { var sessionKeys = uids.map(function (uid) { return 'uid:' + uid + ':sessions'; diff --git a/src/user/info.js b/src/user/info.js index 20228aa161..e8642989a1 100644 --- a/src/user/info.js +++ b/src/user/info.js @@ -1,7 +1,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var validator = require('validator'); var db = require('../database'); diff --git a/src/user/settings.js b/src/user/settings.js index cf65c37545..bc8797655a 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -2,7 +2,7 @@ 'use strict'; var async = require('async'); -var _ = require('underscore'); +var _ = require('lodash'); var meta = require('../meta'); var db = require('../database'); diff --git a/src/views/admin/manage/category.tpl b/src/views/admin/manage/category.tpl index 4d006ad191..c8be81ab8f 100644 --- a/src/views/admin/manage/category.tpl +++ b/src/views/admin/manage/category.tpl @@ -1,5 +1,12 @@