From afef79a81e9277c29aa832b4a847b268c1e3d9ee Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 29 Nov 2016 17:16:12 +0300 Subject: [PATCH 01/15] closes #5241 --- package.json | 6 +++--- src/meta/js.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 7bcd0ce3da..bf9fb0049e 100644 --- a/package.json +++ b/package.json @@ -81,9 +81,9 @@ "semver": "^5.1.0", "serve-favicon": "^2.1.5", "sitemap": "^1.4.0", - "socket.io": "^1.4.8", - "socket.io-client": "^1.4.0", - "socket.io-redis": "1.1.1", + "socket.io": "1.7.1", + "socket.io-client": "1.7.1", + "socket.io-redis": "2.0.0", "socketio-wildcard": "~0.3.0", "string": "^3.0.0", "templates.js": "0.3.4", diff --git a/src/meta/js.js b/src/meta/js.js index 72c9813a03..626fa0ecd8 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -16,7 +16,7 @@ module.exports = function (Meta) { scripts: { base: [ './node_modules/jquery/dist/jquery.js', - './node_modules/socket.io-client/socket.io.js', + './node_modules/socket.io-client/dist/socket.io.js', 'public/vendor/jquery/timeago/jquery.timeago.js', 'public/vendor/jquery/js/jquery.form.min.js', 'public/vendor/visibility/visibility.min.js', From f8caed95dbba39812771c5198e4f71ec3b319122 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 29 Nov 2016 20:15:45 +0300 Subject: [PATCH 02/15] don't crash if plugin doesnt set defaultLang --- src/plugins/load.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/plugins/load.js b/src/plugins/load.js index d5ddfa9dd2..2d2a377070 100644 --- a/src/plugins/load.js +++ b/src/plugins/load.js @@ -261,7 +261,7 @@ module.exports = function (Plugins) { } var pathToFolder = path.join(__dirname, '../../node_modules/', pluginData.id, pluginData.languages); - var defaultLang = pluginData.defaultLang.replace('_', '-').replace('@', '-x-'); + var defaultLang = (pluginData.defaultLang || 'en_GB').replace('_', '-').replace('@', '-x-'); utils.walk(pathToFolder, function (err, languages) { if (err) { @@ -346,9 +346,11 @@ module.exports = function (Plugins) { if (err) { return callback(err); } + var pluginData; + var packageData; try { - var pluginData = JSON.parse(results.plugin); - var packageData = JSON.parse(results.package); + pluginData = JSON.parse(results.plugin); + packageData = JSON.parse(results.package); pluginData.id = packageData.name; pluginData.name = packageData.name; @@ -356,16 +358,15 @@ module.exports = function (Plugins) { pluginData.version = packageData.version; pluginData.repository = packageData.repository; pluginData.nbbpm = packageData.nbbpm; - - callback(null, pluginData); } catch(err) { var pluginDir = pluginPath.split(path.sep); pluginDir = pluginDir[pluginDir.length - 1]; winston.error('[plugins/' + pluginDir + '] Error in plugin.json or package.json! ' + err.message); - callback(new Error('[[error:parse-error]]')); + return callback(new Error('[[error:parse-error]]')); } + callback(null, pluginData); }); }; }; From 2291899f4f8adb91cd128de9747dd86d2d6dcb53 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 29 Nov 2016 20:33:33 +0300 Subject: [PATCH 03/15] show chat room title in taskbar --- public/src/modules/chat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 2283695d39..d90dc210d4 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -258,7 +258,7 @@ define('chat', [ Chats.addScrollHandler(chatModal.attr('roomId'), data.uid, chatModal.find('.chat-content')); taskbar.push('chat', chatModal.attr('UUID'), { - title: data.users.length ? data.users[0].username : '', + title: data.roomName || (data.users.length ? data.users[0].username : ''), roomId: data.roomId, icon: 'fa-comment', state: '' From 12f834072a0ae91b0e0a86e896a34576575b748f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 29 Nov 2016 21:20:09 -0500 Subject: [PATCH 04/15] removed comment from Gruntfile --- Gruntfile.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index 08baead7a8..be761a16cf 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -35,7 +35,6 @@ module.exports = function (grunt) { incomplete.push(compiling); } - // @psychobunny, re: #5211, instead of this, just call `node app --build js` or `node app --build css,tpl` updateArgs.push('--build'); updateArgs.push(incomplete.join(',')); From 4cb48c46ab4d2d26f8184eea906fae446f2ad10a Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 30 Nov 2016 16:28:25 +0300 Subject: [PATCH 05/15] closes #5242 --- public/src/overrides.js | 7 ++++++- src/controllers/api.js | 4 +++- src/views/admin/settings/post.tpl | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/public/src/overrides.js b/public/src/overrides.js index 8d48b21f2a..a5216910d2 100644 --- a/public/src/overrides.js +++ b/public/src/overrides.js @@ -150,7 +150,12 @@ if ('undefined' !== typeof window) { overrides.overrideTimeago = function () { var timeagoFn = $.fn.timeago; - $.timeago.settings.cutoff = 1000 * 60 * 60 * 24 * (parseInt(config.timeagoCutoff, 10) || 60); + if (parseInt(config.timeagoCutoff, 10) === 0) { + $.timeago.settings.cutoff = 1; + } else if (parseInt(config.timeagoCutoff, 10) > 0) { + $.timeago.settings.cutoff = 1000 * 60 * 60 * 24 * (parseInt(config.timeagoCutoff, 10) || 30); + } + $.fn.timeago = function () { var els = $(this); diff --git a/src/controllers/api.js b/src/controllers/api.js index f5dcdfa54e..f9e317cee7 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -63,7 +63,9 @@ apiController.getConfig = function (req, res, next) { config.csrf_token = req.csrfToken(); config.searchEnabled = plugins.hasListeners('filter:search.query'); config.bootswatchSkin = 'default'; - config.timeagoCutoff = meta.config.timeagoCutoff; + + var timeagoCutoff = meta.config.timeagoCutoff === undefined ? 30 : meta.config.timeagoCutoff; + config.timeagoCutoff = timeagoCutoff !== '' ? Math.max(0, parseInt(timeagoCutoff, 10)) : timeagoCutoff; config.cookies = { enabled: parseInt(meta.config.cookieConsentEnabled, 10) === 1, diff --git a/src/views/admin/settings/post.tpl b/src/views/admin/settings/post.tpl index 559f7094b0..a9b784957c 100644 --- a/src/views/admin/settings/post.tpl +++ b/src/views/admin/settings/post.tpl @@ -94,7 +94,7 @@

Dates & times will be shown in a relative manner (e.g. "3 hours ago" / "5 days ago"), and localised into various languages. After a certain point, this text can be switched to display the localised date itself - (e.g. 5 Nov 2016 15:30).
(Default: 30, or one month) + (e.g. 5 Nov 2016 15:30).
(Default: 30, or one month). Set to 0 to always display dates, leave blank to always display relative times.

From a4ebb7f56e391da609d7c8180f92abe99d7632d3 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 30 Nov 2016 18:21:30 +0300 Subject: [PATCH 06/15] test plugin static assets --- test/plugins.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/plugins.js b/test/plugins.js index 9af8224dee..67709bcf49 100644 --- a/test/plugins.js +++ b/test/plugins.js @@ -4,6 +4,7 @@ var assert = require('assert'); var path = require('path'); var nconf = require('nconf'); +var request = require('request'); var db = require('./mocks/databasemock'); var plugins = require('../src/plugins'); @@ -149,6 +150,35 @@ describe('Plugins', function () { }); }); + describe('static assets', function () { + it('should 404 if resource does not exist', function (done) { + request.get(nconf.get('url') + '/plugins/doesnotexist/should404.tpl', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 404); + assert(body); + done(); + }); + }); + + it('should 404 if resource does not exist', function (done) { + request.get(nconf.get('url') + '/plugins/nodebb-plugin-dbsearch/dbsearch/templates/admin/plugins/should404.tpl', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 404); + assert(body); + done(); + }); + }); + + it('should get resource', function (done) { + request.get(nconf.get('url') + '/plugins/nodebb-plugin-dbsearch/dbsearch/templates/admin/plugins/dbsearch.tpl', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + }); + }); From 02aadf79b525d833f1840143a12aef7650225bf7 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 30 Nov 2016 19:13:14 +0300 Subject: [PATCH 07/15] account/posts controller tests --- src/controllers/accounts/posts.js | 95 +++++++++++++++++-------------- test/controllers.js | 85 +++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 44 deletions(-) diff --git a/src/controllers/accounts/posts.js b/src/controllers/accounts/posts.js index 53ff073dad..15cab4f4ca 100644 --- a/src/controllers/accounts/posts.js +++ b/src/controllers/accounts/posts.js @@ -97,56 +97,63 @@ postsController.getTopics = function (req, res, next) { getFromUserSet(data, req, res, next); }; -function getFromUserSet(data, req, res, next) { - async.parallel({ - settings: function (next) { - user.getSettings(req.uid, next); - }, - userData: function (next) { - accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, next); - } - }, function (err, results) { - if (err || !results.userData) { - return next(err); - } - - var userData = results.userData; - - var setName = 'uid:' + userData.uid + ':' + data.set; - - var page = Math.max(1, parseInt(req.query.page, 10) || 1); - var itemsPerPage = (data.template === 'account/topics' || data.template === 'account/watched') ? results.settings.topicsPerPage : results.settings.postsPerPage; - - async.parallel({ - itemCount: function (next) { - if (results.settings.usePagination) { - db.sortedSetCard(setName, next); - } else { - next(null, 0); +function getFromUserSet(data, req, res, callback) { + var userData; + var itemsPerPage; + var page = Math.max(1, parseInt(req.query.page, 10) || 1); + async.waterfall([ + function (next) { + async.parallel({ + settings: function (next) { + user.getSettings(req.uid, next); + }, + userData: function (next) { + accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, next); } - }, - data: function (next) { - var start = (page - 1) * itemsPerPage; - var stop = start + itemsPerPage - 1; - data.method(setName, req.uid, start, stop, next); - } - }, function (err, results) { - if (err) { - return next(err); + }, next); + }, + function (results, next) { + if (!results.userData) { + return callback(); } - userData[data.type] = results.data[data.type]; - userData.nextStart = results.data.nextStart; + userData = results.userData; - var pageCount = Math.ceil(results.itemCount / itemsPerPage); - userData.pagination = pagination.create(page, pageCount); + var setName = 'uid:' + userData.uid + ':' + data.set; - userData.noItemsFoundKey = data.noItemsFoundKey; - userData.title = '[[pages:' + data.template + ', ' + userData.username + ']]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: data.crumb}]); + itemsPerPage = (data.template === 'account/topics' || data.template === 'account/watched') ? results.settings.topicsPerPage : results.settings.postsPerPage; - res.render(data.template, userData); - }); + async.parallel({ + itemCount: function (next) { + if (results.settings.usePagination) { + db.sortedSetCard(setName, next); + } else { + next(null, 0); + } + }, + data: function (next) { + var start = (page - 1) * itemsPerPage; + var stop = start + itemsPerPage - 1; + data.method(setName, req.uid, start, stop, next); + } + }, next); + } + ], function (err, results) { + if (err) { + return callback(err); + } + + userData[data.type] = results.data[data.type]; + userData.nextStart = results.data.nextStart; + + var pageCount = Math.ceil(results.itemCount / itemsPerPage); + userData.pagination = pagination.create(page, pageCount); + + userData.noItemsFoundKey = data.noItemsFoundKey; + userData.title = '[[pages:' + data.template + ', ' + userData.username + ']]'; + userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: data.crumb}]); + + res.render(data.template, userData); }); } diff --git a/test/controllers.js b/test/controllers.js index 04afade0fc..04bbf26c1b 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -703,6 +703,91 @@ describe('Controllers', function () { }); }); + describe('account post pages', function () { + var helpers = require('./helpers'); + var jar; + before(function (done) { + helpers.loginUser('foo', 'barbar', function (err, _jar) { + assert.ifError(err); + jar = _jar; + done(); + }); + }); + + it('should load /user/foo/posts', function (done) { + request(nconf.get('url') + '/api/user/foo/posts', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + + it('should 401 if not logged in', function (done) { + request(nconf.get('url') + '/api/user/foo/bookmarks', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 401); + assert(body); + done(); + }); + }); + + it('should load /user/foo/bookmarks', function (done) { + request(nconf.get('url') + '/api/user/foo/bookmarks', {jar: jar}, function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + + it('should load /user/foo/upvoted', function (done) { + request(nconf.get('url') + '/api/user/foo/upvoted', {jar: jar}, function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + + it('should load /user/foo/downvoted', function (done) { + request(nconf.get('url') + '/api/user/foo/downvoted', {jar: jar}, function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + + it('should load /user/foo/best', function (done) { + request(nconf.get('url') + '/api/user/foo/best', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + + it('should load /user/foo/watched', function (done) { + request(nconf.get('url') + '/api/user/foo/watched', {jar: jar}, function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + + it('should load /user/foo/topics', function (done) { + request(nconf.get('url') + '/api/user/foo/topics', function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert(body); + done(); + }); + }); + + }); + after(function (done) { var analytics = require('../src/analytics'); analytics.writeData(function (err) { From d6c2779ed067d57f2cf4757964e348f1f467b4c8 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 1 Dec 2016 11:31:10 +0300 Subject: [PATCH 08/15] remove placeholder #5242 --- src/views/admin/settings/post.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/admin/settings/post.tpl b/src/views/admin/settings/post.tpl index a9b784957c..95f39c829a 100644 --- a/src/views/admin/settings/post.tpl +++ b/src/views/admin/settings/post.tpl @@ -90,7 +90,7 @@
- +

Dates & times will be shown in a relative manner (e.g. "3 hours ago" / "5 days ago"), and localised into various languages. After a certain point, this text can be switched to display the localised date itself From ea007e2da4ae1ec39afe8cd2a5b5b818ddb5c732 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 1 Dec 2016 11:52:35 +0300 Subject: [PATCH 09/15] closes #5245 --- src/groups/create.js | 2 +- test/groups.js | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/groups/create.js b/src/groups/create.js index 0b38b3ebcc..1d16ea33cf 100644 --- a/src/groups/create.js +++ b/src/groups/create.js @@ -92,7 +92,7 @@ module.exports = function (Groups) { return callback(new Error('[[error:group-name-too-long]]')); } - if (name.indexOf('/') !== -1) { + if (name.indexOf('/') !== -1 || !utils.slugify(name)) { return callback(new Error('[[error:invalid-group-name]]')); } diff --git a/test/groups.js b/test/groups.js index 122645cc2b..35d3c17be6 100644 --- a/test/groups.js +++ b/test/groups.js @@ -184,6 +184,20 @@ describe('Groups', function () { done(); }); }); + + it('should fail to create group if slug is empty', function (done) { + Groups.create({name: '>>>>'}, function (err) { + assert.equal(err.message, '[[error:invalid-group-name]]'); + done(); + }); + }); + + it('should fail if group name is invalid', function (done) { + Groups.create({name: 'not/valid'}, function (err) { + assert.equal(err.message, '[[error:invalid-group-name]]'); + done(); + }); + }); }); describe('.hide()', function () { From 76044bea366e8ca44474fab7414ca516a6cbc21c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 1 Dec 2016 13:51:14 +0300 Subject: [PATCH 10/15] build js in parallel --- build.js | 77 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/build.js b/build.js index 16856f8186..4ae2d34c77 100644 --- a/build.js +++ b/build.js @@ -39,47 +39,58 @@ exports.build = function build(targets, callback) { exports.buildTargets = function (targets, callback) { var meta = require('./src/meta'); buildStart = buildStart || Date.now(); - var startTime; - var step = function (target, next) { - winston.info('[build] => Completed in ' + ((Date.now() - startTime) / 1000) + 's'); + + var step = function (startTime, target, next) { + winston.info('[build] ' + target + ' => Completed in ' + ((Date.now() - startTime) / 1000) + 's'); next(); }; - // eachSeries because it potentially(tm) runs faster on Windows this way - async.eachSeries(targets, function (target, next) { - switch(target) { - case 'js': + + async.parallel([ + function (next) { + if (targets.indexOf('js') !== -1) { winston.info('[build] Building javascript'); - startTime = Date.now(); + var startTime = Date.now(); async.series([ async.apply(meta.js.minify, 'nodebb.min.js'), async.apply(meta.js.minify, 'acp.min.js') - ], step.bind(this, target, next)); - break; - - case 'clientCSS': - winston.info('[build] Building client-side CSS'); - startTime = Date.now(); - meta.css.minify('stylesheet.css', step.bind(this, target, next)); - break; - - case 'acpCSS': - winston.info('[build] Building admin control panel CSS'); - startTime = Date.now(); - meta.css.minify('admin.css', step.bind(this, target, next)); - break; - - case 'tpl': - winston.info('[build] Building templates'); - startTime = Date.now(); - meta.templates.compile(step.bind(this, target, next)); - break; - - default: - winston.warn('[build] Unknown build target: \'' + target + '\''); + ], step.bind(this, startTime, 'js', next)); + } else { setImmediate(next); - break; + } + }, + function (next) { + async.eachSeries(targets, function (target, next) { + var startTime; + switch(target) { + case 'js': + setImmediate(next); + break; + case 'clientCSS': + winston.info('[build] Building client-side CSS'); + startTime = Date.now(); + meta.css.minify('stylesheet.css', step.bind(this, startTime, target, next)); + break; + + case 'acpCSS': + winston.info('[build] Building admin control panel CSS'); + startTime = Date.now(); + meta.css.minify('admin.css', step.bind(this, startTime, target, next)); + break; + + case 'tpl': + winston.info('[build] Building templates'); + startTime = Date.now(); + meta.templates.compile(step.bind(this, startTime, target, next)); + break; + + default: + winston.warn('[build] Unknown build target: \'' + target + '\''); + setImmediate(next); + break; + } + }, next); } - }, function (err) { + ], function (err) { if (err) { winston.error('[build] Encountered error during build step: ' + err.message); return process.exit(1); From 9ba93d8be93f885a9ba0ba688e9c931ad8b99795 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 1 Dec 2016 17:21:09 +0300 Subject: [PATCH 11/15] group search tests --- src/groups/search.js | 4 --- src/socket.io/groups.js | 2 +- test/groups.js | 56 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/groups/search.js b/src/groups/search.js index 55bf5e5789..4826579f6c 100644 --- a/src/groups/search.js +++ b/src/groups/search.js @@ -66,10 +66,6 @@ module.exports = function (Groups) { Groups.searchMembers = function (data, callback) { function findUids(query, searchBy, callback) { - if (!query) { - return Groups.getMembers(data.groupName, 0, -1, callback); - } - query = query.toLowerCase(); async.waterfall([ diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index 64e568f919..858d9bdeff 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -237,7 +237,7 @@ SocketGroups.search = function (socket, data, callback) { return; } - groups.search(data.query, data.options || {}, callback); + groups.search(data.query, data.options, callback); }; SocketGroups.loadMore = function (socket, data, callback) { diff --git a/test/groups.js b/test/groups.js index 35d3c17be6..c2b30b9d94 100644 --- a/test/groups.js +++ b/test/groups.js @@ -93,14 +93,68 @@ describe('Groups', function () { }); describe('.search()', function () { + var socketGroups = require('../src/socket.io/groups'); + + it('should return the groups when search query is empty', function (done) { + socketGroups.search({uid: adminUid}, {query: ''}, function (err, groups) { + assert.ifError(err); + assert.equal(3, groups.length); + done(); + }); + }); + it('should return the "Test" group when searched for', function (done) { - Groups.search('test', {}, function (err, groups) { + socketGroups.search({uid: adminUid}, {query: 'test'}, function (err, groups) { assert.ifError(err); assert.equal(1, groups.length); assert.strictEqual('Test', groups[0].name); done(); }); }); + + it('should return the "Test" group when searched for and sort by member count', function (done) { + Groups.search('test', {filterHidden: true, sort: 'count'}, function (err, groups) { + assert.ifError(err); + assert.equal(1, groups.length); + assert.strictEqual('Test', groups[0].name); + done(); + }); + }); + + it('should return the "Test" group when searched for and sort by creation time', function (done) { + Groups.search('test', {filterHidden: true, sort: 'date'}, function (err, groups) { + assert.ifError(err); + assert.equal(1, groups.length); + assert.strictEqual('Test', groups[0].name); + done(); + }); + }); + + it('should return all users if no query', function (done) { + User.create({ + username: 'newuser', + email: 'newuser@b.com' + }, function (err, uid) { + assert.ifError(err); + Groups.join('Test', uid, function (err) { + assert.ifError(err); + socketGroups.searchMembers({uid: adminUid}, {groupName: 'Test', query: ''}, function (err, data) { + assert.ifError(err); + assert.equal(data.users.length, 2); + done(); + }); + }); + }); + }); + + it('should search group members', function (done) { + socketGroups.searchMembers({uid: adminUid}, {groupName: 'Test', query: 'test'}, function (err, data) { + assert.ifError(err); + assert.strictEqual('testuser', data.users[0].username); + done(); + }); + }); + }); describe('.isMember()', function () { From 5cf80066406a20db687ea2558c9d3e4d628f8457 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 1 Dec 2016 18:05:48 +0300 Subject: [PATCH 12/15] fix style --- src/groups/search.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/groups/search.js b/src/groups/search.js index 4826579f6c..3b6bfab9cd 100644 --- a/src/groups/search.js +++ b/src/groups/search.js @@ -1,10 +1,10 @@ 'use strict'; -var async = require('async'), +var async = require('async'); + +var user = require('../user'); +var db = require('./../database'); - user = require('../user'), - db = require('./../database'), - groups = module.parent.exports; module.exports = function (Groups) { @@ -17,7 +17,7 @@ module.exports = function (Groups) { async.apply(db.getObjectValues, 'groupslug:groupname'), function (groupNames, next) { // Ephemeral groups and the registered-users groups are searchable - groupNames = groups.getEphemeralGroups().concat(groupNames).concat('registered-users'); + groupNames = Groups.getEphemeralGroups().concat(groupNames).concat('registered-users'); groupNames = groupNames.filter(function (name) { return name.toLowerCase().indexOf(query) !== -1 && name !== 'administrators' && !Groups.isPrivilegeGroup(name); }); From c3980d0c2ef4baf802d9a36c9d17c50498503d26 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 1 Dec 2016 18:36:43 +0300 Subject: [PATCH 13/15] follow tests --- src/user/follow.js | 39 ++++++++++++++++++--------------------- test/controllers.js | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/src/user/follow.js b/src/user/follow.js index 0812c1004d..e6c9624018 100644 --- a/src/user/follow.js +++ b/src/user/follow.js @@ -1,9 +1,9 @@ 'use strict'; -var async = require('async'), - plugins = require('../plugins'), - db = require('../database'); +var async = require('async'); +var plugins = require('../plugins'); +var db = require('../database'); module.exports = function (User) { @@ -73,25 +73,22 @@ module.exports = function (User) { if (!parseInt(uid, 10)) { return callback(null, []); } - - db.getSortedSetRevRange(type + ':' + uid, start, stop, function (err, uids) { - if (err) { - return callback(err); + async.waterfall([ + function (next) { + db.getSortedSetRevRange(type + ':' + uid, start, stop, next); + }, + function (uids, next) { + plugins.fireHook('filter:user.' + type, { + uids: uids, + uid: uid, + start: start, + stop: stop + }, next); + }, + function (data, next) { + User.getUsers(data.uids, uid, next); } - - plugins.fireHook('filter:user.' + type, { - uids: uids, - uid: uid, - start: start, - stop: stop - }, function (err, data) { - if (err) { - return callback(err); - } - - User.getUsers(data.uids, uid, callback); - }); - }); + ], callback); } User.isFollowing = function (uid, theirid, callback) { diff --git a/test/controllers.js b/test/controllers.js index 04bbf26c1b..03d7d38e11 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -785,7 +785,47 @@ describe('Controllers', function () { done(); }); }); + }); + describe('account follow page', function () { + var uid; + before(function (done) { + user.create({username: 'follower'}, function (err, _uid) { + assert.ifError(err); + uid = _uid; + user.follow(uid, fooUid, done); + }); + }); + + it('should get followers page', function (done) { + request(nconf.get('url') + '/api/user/foo/followers', {json: true}, function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert.equal(body.users[0].username, 'follower'); + done(); + }); + }); + + it('should get following page', function (done) { + request(nconf.get('url') + '/api/user/follower/following', {json: true}, function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert.equal(body.users[0].username, 'foo'); + done(); + }); + }); + + it('should return empty after unfollow', function (done ) { + user.unfollow(uid, fooUid, function (err) { + assert.ifError(err); + request(nconf.get('url') + '/api/user/foo/followers', {json: true}, function (err, res, body) { + assert.ifError(err); + assert.equal(res.statusCode, 200); + assert.equal(body.users.length, 0); + done(); + }); + }); + }); }); after(function (done) { From 7f90e31a3876cfa14c371b1a55738ae55f63bd04 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 1 Dec 2016 18:59:24 +0300 Subject: [PATCH 14/15] more socket user tests --- src/socket.io/user.js | 2 +- test/controllers.js | 5 +++-- test/user.js | 48 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 41c2e9c2c5..69b229b4b1 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -46,7 +46,7 @@ SocketUser.deleteAccount = function (socket, data, callback) { user.deleteAccount(socket.uid, next); }, function (next) { - socket.broadcast.emit('event:user_status_change', {uid: socket.uid, status: 'offline'}); + require('./index').server.sockets.emit('event:user_status_change', {uid: socket.uid, status: 'offline'}); events.log({ type: 'user-delete', diff --git a/test/controllers.js b/test/controllers.js index 03d7d38e11..cd08039557 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -788,12 +788,13 @@ describe('Controllers', function () { }); describe('account follow page', function () { + var socketUser = require('../src/socket.io/user'); var uid; before(function (done) { user.create({username: 'follower'}, function (err, _uid) { assert.ifError(err); uid = _uid; - user.follow(uid, fooUid, done); + socketUser.follow({uid: uid}, {uid: fooUid}, done); }); }); @@ -816,7 +817,7 @@ describe('Controllers', function () { }); it('should return empty after unfollow', function (done ) { - user.unfollow(uid, fooUid, function (err) { + socketUser.unfollow({uid: uid}, {uid: fooUid}, function (err) { assert.ifError(err); request(nconf.get('url') + '/api/user/foo/followers', {json: true}, function (err, res, body) { assert.ifError(err); diff --git a/test/user.js b/test/user.js index 114c4dfdc3..c2f67ef709 100644 --- a/test/user.js +++ b/test/user.js @@ -610,7 +610,55 @@ describe('User', function () { }); }); }); + }); + describe('socket methods', function () { + var socketUser = require('../src/socket.io/user'); + + it('should fail with invalid data', function (done) { + socketUser.exists({uid: testUid}, null, function (err) { + assert.equal(err.message, '[[error:invalid-data]]'); + done(); + }); + }); + + it('should return true if user/group exists', function (done) { + socketUser.exists({uid: testUid}, {username: 'registered-users'}, function (err, exists) { + assert.ifError(err); + assert(exists); + done(); + }); + }); + + it('should return true if user/group exists', function (done) { + socketUser.exists({uid: testUid}, {username: 'John Smith'}, function (err, exists) { + assert.ifError(err); + assert(exists); + done(); + }); + }); + + it('should return false if user/group does not exists', function (done) { + socketUser.exists({uid: testUid}, {username: 'doesnot exist'}, function (err, exists) { + assert.ifError(err); + assert(!exists); + done(); + }); + }); + + it('should delete user', function (done) { + User.create({username: 'tobedeleted'}, function (err, _uid) { + assert.ifError(err); + socketUser.deleteAccount({uid: _uid}, {}, function (err) { + assert.ifError(err); + socketUser.exists({uid: testUid}, {username: 'doesnot exist'}, function (err, exists) { + assert.ifError(err); + assert(!exists); + done(); + }); + }); + }); + }); }); From fb42b83e1ba41df755de365ff9b9ef1b1152155b Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 1 Dec 2016 18:59:50 +0300 Subject: [PATCH 15/15] remove hardcoded value @pichalite --- src/views/admin/settings/post.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/admin/settings/post.tpl b/src/views/admin/settings/post.tpl index 95f39c829a..0a58e3a3cf 100644 --- a/src/views/admin/settings/post.tpl +++ b/src/views/admin/settings/post.tpl @@ -90,7 +90,7 @@

- +

Dates & times will be shown in a relative manner (e.g. "3 hours ago" / "5 days ago"), and localised into various languages. After a certain point, this text can be switched to display the localised date itself