mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-01-06 15:42:52 +01:00
Merge remote-tracking branch 'origin/master' into flagging-refactor
This commit is contained in:
77
build.js
77
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]]'));
|
||||
}
|
||||
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -90,11 +90,11 @@
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label for="timeagoCutoff">Date cut-off (in days)</label>
|
||||
<input type="number" class="form-control" id="timeagoCutoff" data-field="timeagoCutoff" placeholder="30" value="30" />
|
||||
<input type="number" class="form-control" id="timeagoCutoff" data-field="timeagoCutoff" value="30" />
|
||||
<p class="help-block">
|
||||
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).<br /><em>(Default: <code>30</code>, or one month)</em>
|
||||
(e.g. 5 Nov 2016 15:30).<br /><em>(Default: <code>30</code>, or one month). Set to 0 to always display dates, leave blank to always display relative times.</em>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 () {
|
||||
@@ -184,6 +238,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 () {
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user