Merge remote-tracking branch 'origin/master' into flagging-refactor

v1.18.x
Julian Lam 8 years ago
commit dde3d2b135

@ -52,7 +52,7 @@
"morgan": "^1.3.2",
"mousetrap": "^1.5.3",
"nconf": "~0.8.2",
"nodebb-plugin-composer-default": "4.3.0",
"nodebb-plugin-composer-default": "4.3.1",
"nodebb-plugin-dbsearch": "1.0.4",
"nodebb-plugin-emoji-extended": "1.1.1",
"nodebb-plugin-emoji-one": "1.1.5",

@ -107,6 +107,7 @@ helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) {
userData.isModerator = isModerator;
userData.isAdminOrGlobalModerator = isAdmin || isGlobalModerator;
userData.isAdminOrGlobalModeratorOrModerator = isAdmin || isGlobalModerator || isModerator;
userData.isSelfOrAdminOrGlobalModerator = isSelf || isAdmin || isGlobalModerator;
userData.canEdit = isAdmin || (isGlobalModerator && !results.isTargetAdmin);
userData.canBan = isAdmin || (isGlobalModerator && !results.isTargetAdmin);
userData.canChangePassword = isAdmin || (isSelf && parseInt(meta.config['password:disableEdit'], 10) !== 1);

@ -13,13 +13,9 @@ sessionController.revoke = function (req, res, next) {
}
var _id;
var uid;
var uid = res.locals.uid;
async.waterfall([
function (next) {
user.getUidByUserslug(req.params.userslug, next);
},
function (_uid, next) {
uid = _uid;
if (!uid) {
return next(new Error('[[error:no-session-found]]'));
}

@ -162,14 +162,24 @@ groupsController.members = function (req, res, callback) {
groupsController.uploadCover = function (req, res, next) {
var params = JSON.parse(req.body.params);
groups.updateCover(req.uid, {
file: req.files.files[0].path,
groupName: params.groupName
}, function (err, image) {
async.waterfall([
function (next) {
groups.ownership.isOwner(req.uid, params.groupName, next);
},
function (isOwner, next) {
if (!isOwner) {
return next(new Error('[[error:no-privileges]]'));
}
groups.updateCover(req.uid, {
file: req.files.files[0].path,
groupName: params.groupName
}, next);
}
], function (err, image) {
if (err) {
return next(err);
}
res.json([{url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url}]);
});
};

@ -26,13 +26,15 @@ helpers.notAllowed = function (req, res, error) {
if (res.locals.isAPI) {
res.status(403).json({
path: req.path.replace(/^\/api/, ''),
loggedIn: !!req.uid, error: error,
loggedIn: !!req.uid,
error: error,
title: '[[global:403.title]]'
});
} else {
res.status(403).render('403', {
path: req.path,
loggedIn: !!req.uid, error: error,
loggedIn: !!req.uid,
error: error,
title: '[[global:403.title]]'
});
}

@ -132,7 +132,12 @@ var fallbackTransport;
delete data.from_name;
winston.verbose('[emailer] Sending email to uid ' + data.uid);
fallbackTransport.sendMail(data, callback);
fallbackTransport.sendMail(data, function (err) {
if (err) {
winston.error(err);
}
callback();
});
};
function render(tpl, params, next) {

@ -10,7 +10,6 @@ var mime = require('mime');
var winston = require('winston');
var db = require('../database');
var file = require('../file');
var uploadsController = require('../controllers/uploads');
module.exports = function (Groups) {
@ -25,7 +24,7 @@ module.exports = function (Groups) {
Groups.updateCover = function (uid, data, callback) {
// Position only? That's fine
if (!data.imageData && data.position) {
if (!data.imageData && !data.file && data.position) {
return Groups.updateCoverPosition(data.groupName, data.position, callback);
}
@ -66,26 +65,19 @@ module.exports = function (Groups) {
Groups.setGroupField(data.groupName, 'cover:thumb:url', uploadData.url, next);
},
function (next) {
fs.unlink(tempPath, next); // Delete temporary file
if (data.position) {
Groups.updateCoverPosition(data.groupName, data.position, next);
} else {
next(null);
}
}
], function (err) {
if (err) {
return fs.unlink(tempPath, function (unlinkErr) {
if (unlinkErr) {
winston.error(unlinkErr);
}
callback(err); // send back original error
});
}
if (data.position) {
Groups.updateCoverPosition(data.groupName, data.position, function (err) {
callback(err, {url: url});
});
} else {
fs.unlink(tempPath, function (unlinkErr) {
if (unlinkErr) {
winston.error(unlinkErr);
}
callback(err, {url: url});
}
});
});
};

@ -49,6 +49,30 @@ middleware.authenticate = function (req, res, next) {
controllers.helpers.notAllowed(req, res);
};
middleware.ensureSelfOrGlobalPrivilege = function (req, res, next) {
/*
The "self" part of this middleware hinges on you having used
middleware.exposeUid prior to invoking this middleware.
*/
if (req.user) {
if (req.user.uid === res.locals.uid) {
return next();
}
user.isAdminOrGlobalMod(req.uid, function (err, ok) {
if (err) {
return next(err);
} else if (ok) {
return next();
} else {
controllers.helpers.notAllowed(req, res);
}
});
} else {
controllers.helpers.notAllowed(req, res);
}
};
middleware.pageView = function (req, res, next) {
analytics.pageView({
ip: req.ip,

@ -187,39 +187,37 @@ var plugins = require('./plugins');
return callback(null, []);
}
user.getSettings(uid, function (err, settings) {
if (err) {
return callback(err);
}
var byVotes = settings.topicPostSort === 'most_votes';
var sets = posts.map(function (post) {
return byVotes ? 'tid:' + post.tid + ':posts:votes' : 'tid:' + post.tid + ':posts';
});
var uniqueSets = _.uniq(sets);
var method = 'sortedSetsRanks';
if (uniqueSets.length === 1) {
method = 'sortedSetRanks';
sets = uniqueSets[0];
}
var pids = posts.map(function (post) {
return post.pid;
});
db[method](sets, pids, function (err, indices) {
if (err) {
return callback(err);
async.waterfall([
function (next) {
user.getSettings(uid, next);
},
function (settings, next) {
var byVotes = settings.topicPostSort === 'most_votes';
var sets = posts.map(function (post) {
return byVotes ? 'tid:' + post.tid + ':posts:votes' : 'tid:' + post.tid + ':posts';
});
var uniqueSets = _.uniq(sets);
var method = 'sortedSetsRanks';
if (uniqueSets.length === 1) {
method = 'sortedSetRanks';
sets = uniqueSets[0];
}
var pids = posts.map(function (post) {
return post.pid;
});
db[method](sets, pids, next);
},
function (indices, next) {
for (var i = 0; i < indices.length; ++i) {
indices[i] = utils.isNumber(indices[i]) ? parseInt(indices[i], 10) + 1 : 0;
}
callback(null, indices);
});
});
next(null, indices);
}
], callback);
};
Posts.updatePostVoteCount = function (postData, callback) {

@ -28,7 +28,7 @@ module.exports = function (app, middleware, controllers) {
setupPageRoute(app, '/user/:userslug/info', middleware, accountMiddlewares, controllers.accounts.info.get);
setupPageRoute(app, '/user/:userslug/settings', middleware, accountMiddlewares, controllers.accounts.settings.get);
app.delete('/api/user/:userslug/session/:uuid', [middleware.requireUser], controllers.accounts.session.revoke);
app.delete('/api/user/:userslug/session/:uuid', [middleware.exposeUid, middleware.ensureSelfOrGlobalPrivilege], controllers.accounts.session.revoke);
setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.notifications.get);
setupPageRoute(app, '/user/:userslug/chats/:roomid?', middleware, middlewares, controllers.accounts.chats.get);

@ -104,19 +104,20 @@ User.sendValidationEmail = function (socket, uids, callback) {
return callback(new Error('[[error:email-confirmations-are-disabled]]'));
}
user.getUsersFields(uids, ['uid', 'email'], function (err, usersData) {
if (err) {
return callback(err);
async.waterfall([
function (next) {
user.getUsersFields(uids, ['uid', 'email'], next);
},
function (usersData, next) {
async.eachLimit(usersData, 50, function (userData, next) {
if (userData.email && userData.uid) {
user.email.sendValidationEmail(userData.uid, userData.email, next);
} else {
next();
}
}, next);
}
async.eachLimit(usersData, 50, function (userData, next) {
if (userData.email && userData.uid) {
user.email.sendValidationEmail(userData.uid, userData.email, next);
} else {
next();
}
}, callback);
});
], callback);
};
User.sendPasswordResetEmail = function (socket, uids, callback) {
@ -220,33 +221,37 @@ User.deleteInvitation = function (socket, data, callback) {
};
User.acceptRegistration = function (socket, data, callback) {
user.acceptRegistration(data.username, function (err, uid) {
if (err) {
return callback(err);
async.waterfall([
function (next) {
user.acceptRegistration(data.username, next);
},
function (uid, next) {
events.log({
type: 'registration-approved',
uid: socket.uid,
ip: socket.ip,
targetUid: uid
});
next(null, uid);
}
events.log({
type: 'registration-approved',
uid: socket.uid,
ip: socket.ip,
targetUid: uid,
});
callback();
});
], callback);
};
User.rejectRegistration = function (socket, data, callback) {
user.rejectRegistration(data.username, function (err) {
if (err) {
return callback(err);
async.waterfall([
function (next) {
user.rejectRegistration(data.username, next);
},
function (next) {
events.log({
type: 'registration-rejected',
uid: socket.uid,
ip: socket.ip,
username: data.username,
});
next();
}
events.log({
type: 'registration-rejected',
uid: socket.uid,
ip: socket.ip,
username: data.username,
});
callback();
});
], callback);
};
User.restartJobs = function (socket, data, callback) {

@ -277,13 +277,18 @@ SocketGroups.cover.update = function (socket, data, callback) {
return callback(new Error('[[error:no-privileges]]'));
}
groups.ownership.isOwner(socket.uid, data.groupName, function (err, isOwner) {
if (err || !isOwner) {
return callback(err || new Error('[[error:no-privileges]]'));
}
async.waterfall([
function (next) {
groups.ownership.isOwner(socket.uid, data.groupName, next);
},
function (isOwner, next) {
if (!isOwner) {
return next(new Error('[[error:no-privileges]]'));
}
groups.updateCover(socket.uid, data, callback);
});
groups.updateCover(socket.uid, data, next);
}
], callback);
};
SocketGroups.cover.remove = function (socket, data, callback) {
@ -291,13 +296,18 @@ SocketGroups.cover.remove = function (socket, data, callback) {
return callback(new Error('[[error:no-privileges]]'));
}
groups.ownership.isOwner(socket.uid, data.groupName, function (err, isOwner) {
if (err || !isOwner) {
return callback(err || new Error('[[error:no-privileges]]'));
}
async.waterfall([
function (next) {
groups.ownership.isOwner(socket.uid, data.groupName, next);
},
function (isOwner, next) {
if (!isOwner) {
return next(new Error('[[error:no-privileges]]'));
}
groups.removeCover(data, callback);
});
groups.removeCover(data, next);
}
], callback);
};
module.exports = SocketGroups;

@ -72,15 +72,21 @@ SocketUser.emailConfirm = function (socket, data, callback) {
}
if (parseInt(meta.config.requireEmailConfirmation, 10) !== 1) {
callback();
return callback(new Error('[[error:email-confirmations-are-disabled]]'));
}
user.getUserField(socket.uid, 'email', function (err, email) {
if (err || !email) {
return callback(err);
}
user.email.sendValidationEmail(socket.uid, email, callback);
});
async.waterfall([
function (next) {
user.getUserField(socket.uid, 'email', next);
},
function (email, next) {
if (!email) {
return callback();
}
user.email.sendValidationEmail(socket.uid, email, next);
}
], callback);
};
@ -109,39 +115,37 @@ SocketUser.reset.commit = function (socket, data, callback) {
if (!data || !data.code || !data.password) {
return callback(new Error('[[error:invalid-data]]'));
}
var uid;
async.waterfall([
function (next) {
async.parallel({
uid: async.apply(db.getObjectField, 'reset:uid', data.code),
reset: async.apply(user.reset.commit, data.code, data.password)
}, next);
},
function (results, next) {
uid = results.uid;
events.log({
type: 'password-reset',
uid: uid,
ip: socket.ip
});
async.parallel({
uid: async.apply(db.getObjectField, 'reset:uid', data.code),
reset: async.apply(user.reset.commit, data.code, data.password)
}, function (err, results) {
if (err) {
return callback(err);
}
var uid = results.uid;
var now = new Date();
var parsedDate = now.getFullYear() + '/' + (now.getMonth() + 1) + '/' + now.getDate();
user.getUserField(uid, 'username', function (err, username) {
if (err) {
return callback(err);
}
user.getUserField(uid, 'username', next);
},
function (username, next) {
var now = new Date();
var parsedDate = now.getFullYear() + '/' + (now.getMonth() + 1) + '/' + now.getDate();
emailer.send('reset_notify', uid, {
username: username,
date: parsedDate,
site_title: meta.config.title || 'NodeBB',
subject: '[[email:reset.notify.subject]]'
});
});
events.log({
type: 'password-reset',
uid: uid,
ip: socket.ip
});
callback();
});
next();
}
], callback);
};
SocketUser.isFollowing = function (socket, data, callback) {
@ -224,16 +228,10 @@ SocketUser.saveSettings = function (socket, data, callback) {
};
SocketUser.setTopicSort = function (socket, sort, callback) {
if (!socket.uid) {
return callback();
}
user.setSetting(socket.uid, 'topicPostSort', sort, callback);
};
SocketUser.setCategorySort = function (socket, sort, callback) {
if (!socket.uid) {
return callback();
}
user.setSetting(socket.uid, 'categoryTopicSort', sort, callback);
};

@ -46,18 +46,19 @@ module.exports = function (User) {
};
function sendNotificationToAdmins(username, callback) {
notifications.create({
bodyShort: '[[notifications:new_register, ' + username + ']]',
nid: 'new_register:' + username,
path: '/admin/manage/registration',
mergeId: 'new_register'
}, function (err, notification) {
if (err || !notification) {
return callback(err);
async.waterfall([
function (next) {
notifications.create({
bodyShort: '[[notifications:new_register, ' + username + ']]',
nid: 'new_register:' + username,
path: '/admin/manage/registration',
mergeId: 'new_register'
}, next);
},
function (notification, next) {
notifications.pushGroup(notification, 'administrators', next);
}
notifications.pushGroup(notification, 'administrators', callback);
});
], callback);
}
User.acceptRegistration = function (username, callback) {
@ -78,6 +79,12 @@ module.exports = function (User) {
uid = _uid;
User.setUserField(uid, 'password', userData.hashedPassword, next);
},
function (next) {
removeFromQueue(username, next);
},
function (next) {
markNotificationRead(username, next);
},
function (next) {
var title = meta.config.title || meta.config.browserTitle || 'NodeBB';
translator.translate('[[email:welcome-to, ' + title + ']]', meta.config.defaultLang, function (subject) {
@ -92,12 +99,6 @@ module.exports = function (User) {
emailer.send('registration_accepted', uid, data, next);
});
},
function (next) {
removeFromQueue(username, next);
},
function (next) {
markNotificationRead(username, next);
},
function (next) {
next(null, uid);
}
@ -153,13 +154,11 @@ module.exports = function (User) {
},
function (users, next) {
users = users.map(function (user, index) {
if (!user) {
return null;
if (user) {
user.timestampISO = utils.toISOString(data[index].score);
delete user.hashedPassword;
}
user.timestampISO = utils.toISOString(data[index].score);
delete user.hashedPassword;
return user;
}).filter(Boolean);

@ -160,6 +160,9 @@ module.exports = function (User) {
};
User.setSetting = function (uid, key, value, callback) {
if (!parseInt(uid, 10)) {
return callback();
}
db.setObjectField('user:' + uid + ':settings', key, value, callback);
};
};

@ -12,6 +12,7 @@ var Categories = require('../src/categories');
var Topics = require('../src/topics');
var User = require('../src/user');
var groups = require('../src/groups');
var privileges = require('../src/privileges');
describe('Categories', function () {
var categoryObj;
@ -312,7 +313,7 @@ describe('Categories', function () {
var socketCategories = require('../src/socket.io/admin/categories');
var cid;
before(function (done) {
Categories.create({
socketCategories.create({uid: adminUid}, {
name: 'update name',
description: 'update description',
parentCid: categoryObj.cid,
@ -388,9 +389,160 @@ describe('Categories', function () {
});
});
it('should get all categories', function (done) {
socketCategories.getAll({uid: adminUid}, {}, function (err, data) {
assert.ifError(err);
done();
});
});
it('should get all category names', function (done) {
socketCategories.getNames({uid: adminUid}, {}, function (err, data) {
assert.ifError(err);
assert(Array.isArray(data));
done();
});
});
it('should give privilege', function (done) {
socketCategories.setPrivilege({uid: adminUid}, {cid: categoryObj.cid, privilege: ['groups:topics:delete'], set: true, member: 'registered-users'}, function (err) {
assert.ifError(err);
privileges.categories.can('topics:delete', categoryObj.cid, posterUid, function (err, canDeleteTopcis) {
assert.ifError(err);
assert(canDeleteTopcis);
done();
});
});
});
it('should remove privilege', function (done) {
socketCategories.setPrivilege({uid: adminUid}, {cid: categoryObj.cid, privilege: 'groups:topics:delete', set: false, member: 'registered-users'}, function (err) {
assert.ifError(err);
privileges.categories.can('topics:delete', categoryObj.cid, posterUid, function (err, canDeleteTopcis) {
assert.ifError(err);
assert(!canDeleteTopcis);
done();
});
});
});
it('should get privilege settings', function (done) {
socketCategories.getPrivilegeSettings({uid: adminUid}, categoryObj.cid, function (err, data) {
assert.ifError(err);
assert(data);
done();
});
});
it('should copy privileges to children', function (done) {
var parentCid;
var child1Cid;
var child2Cid;
async.waterfall([
function (next) {
Categories.create({name: 'parent'}, next);
},
function (category, next) {
parentCid = category.cid;
Categories.create({name: 'child1', parentCid: parentCid}, next);
},
function (category, next) {
child1Cid = category.cid;
Categories.create({name: 'child2', parentCid: child1Cid}, next);
},
function (category, next) {
child2Cid = category.cid;
socketCategories.setPrivilege({uid: adminUid}, {cid: parentCid, privilege: 'groups:topics:delete', set: true, member: 'registered-users'}, next);
},
function (next) {
socketCategories.copyPrivilegesToChildren({uid: adminUid}, parentCid, next);
},
function (next) {
privileges.categories.can('topics:delete', child2Cid, posterUid, next);
},
function (canDelete, next) {
assert(canDelete);
next();
}
], done);
});
it('should copy settings from', function (done) {
var child1Cid;
var parentCid;
async.waterfall([
function (next) {
Categories.create({name: 'parent', description: 'copy me'}, next);
},
function (category, next) {
parentCid = category.cid;
Categories.create({name: 'child1'}, next);
},
function (category, next) {
child1Cid = category.cid;
socketCategories.copySettingsFrom({uid: adminUid}, {fromCid: parentCid, toCid: child1Cid}, next);
},
function (canDelete, next) {
Categories.getCategoryField(child1Cid, 'description', next);
},
function (description, next) {
assert.equal(description, 'copy me');
next();
}
], done);
});
it('should copy privileges from', function (done) {
var child1Cid;
var parentCid;
async.waterfall([
function (next) {
Categories.create({name: 'parent', description: 'copy me'}, next);
},
function (category, next) {
parentCid = category.cid;
Categories.create({name: 'child1'}, next);
},
function (category, next) {
child1Cid = category.cid;
socketCategories.setPrivilege({uid: adminUid}, {cid: parentCid, privilege: 'groups:topics:delete', set: true, member: 'registered-users'}, next);
},
function (next) {
socketCategories.copyPrivilegesFrom({uid: adminUid}, {fromCid: parentCid, toCid: child1Cid}, next);
},
function (next) {
privileges.categories.can('topics:delete', child1Cid, posterUid, next);
},
function (canDelete, next) {
assert(canDelete);
next();
}
], done);
});
});
it('should get active users', function (done) {
Categories.create({
name: 'test'
}, function (err, category) {
assert.ifError(err);
Topics.post({
uid: posterUid,
cid: category.cid,
title: 'Test Topic Title',
content: 'The content of test topic'
}, function (err) {
assert.ifError(err);
Categories.getActiveUsers(category.cid, function (err, uids) {
assert.ifError(err);
assert.equal(uids[0], posterUid);
done();
});
});
});
});
after(function (done) {

@ -533,8 +533,8 @@ describe('Controllers', function () {
}
}, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 500);
assert.equal(body, '[[error:no-session-found]]');
assert.equal(res.statusCode, 403);
assert.equal(body, '{"path":"/user/doesnotexist/session/1112233","loggedIn":true,"title":"[[global:403.title]]"}');
done();
});
});
@ -794,7 +794,14 @@ describe('Controllers', function () {
user.create({username: 'follower'}, function (err, _uid) {
assert.ifError(err);
uid = _uid;
socketUser.follow({uid: uid}, {uid: fooUid}, done);
socketUser.follow({uid: uid}, {uid: fooUid}, function (err) {
assert.ifError(err);
socketUser.isFollowing({uid: uid}, {uid: fooUid}, function (err, isFollowing) {
assert.ifError(err);
assert(isFollowing);
done();
});
});
});
});
@ -829,6 +836,25 @@ describe('Controllers', function () {
});
});
describe('post redirect', function () {
it('should 404 for invalid pid', function (done) {
request(nconf.get('url') + '/post/fail', function (err, res) {
assert.ifError(err);
assert.equal(res.statusCode, 404);
done();
});
});
it('should return correct post path', function (done) {
request(nconf.get('url') + '/api/post/' + pid, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 308);
assert.equal(body, '"/topic/1/test-topic-title/1"');
done();
});
});
});
after(function (done) {
var analytics = require('../src/analytics');
analytics.writeData(function (err) {

File diff suppressed because one or more lines are too long

@ -112,4 +112,58 @@ helpers.uploadFile = function (uploadEndPoint, filePath, body, jar, csrf_token,
}
callback(err, res, body);
});
};
helpers.registerUser = function (data, callback) {
var jar = request.jar();
request({
url: nconf.get('url') + '/api/config',
json: true,
jar: jar
}, function (err, response, body) {
if (err) {
return callback(err);
}
request.post(nconf.get('url') + '/register', {
form: data,
json: true,
jar: jar,
headers: {
'x-csrf-token': body.csrf_token
}
}, function (err, res, body) {
if (err) {
return callback(err);
}
callback(null, jar);
});
});
};
//http://stackoverflow.com/a/14387791/583363
helpers.copyFile = function (source, target, callback) {
var cbCalled = false;
var rd = fs.createReadStream(source);
rd.on("error", function (err) {
done(err);
});
var wr = fs.createWriteStream(target);
wr.on("error", function (err) {
done(err);
});
wr.on("close", function () {
done();
});
rd.pipe(wr);
function done(err) {
if (!cbCalled) {
callback(err);
cbCalled = true;
}
}
};

@ -138,7 +138,7 @@
nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates'));
nconf.set('theme_templates_path', meta.config['theme:templates'] ? path.join(nconf.get('themes_path'), meta.config['theme:id'], meta.config['theme:templates']) : nconf.get('base_templates_path'));
nconf.set('theme_config', path.join(nconf.get('themes_path'), 'nodebb-theme-persona', 'theme.json'));
nconf.set('bcrypt_rounds', 4);
nconf.set('bcrypt_rounds', 1);
require('../../build').buildTargets(['js', 'clientCSS', 'acpCSS', 'tpl'], next);
},

@ -343,6 +343,55 @@ describe('Post\'s', function () {
});
});
describe('move', function () {
var replyPid;
var tid;
var moveTid;
var socketPosts = require('../src/socket.io/posts');
before(function (done) {
async.waterfall([
function (next) {
topics.post({
uid: voterUid,
cid: cid,
title: 'topic 1',
content: 'some content'
}, next);
},
function (data, next) {
tid = data.topicData.tid;
topics.post({
uid: voterUid,
cid: cid,
title: 'topic 2',
content: 'some content'
}, next);
},
function (data, next) {
moveTid = data.topicData.tid;
topics.reply({
uid: voterUid,
tid: tid,
timestamp: Date.now(),
content: 'A reply to move'
}, function (err, data) {
assert.ifError(err);
replyPid = data.pid;
socketPosts.movePost({uid: globalModUid}, {pid: replyPid, tid: moveTid}, next);
});
},
function (next) {
posts.getPostField(replyPid, 'tid', next);
},
function (tid, next) {
assert(tid, moveTid);
next();
}
], done);
});
});
describe('flagging a post', function () {
var meta = require('../src/meta');
var socketPosts = require('../src/socket.io/posts');

@ -253,13 +253,45 @@ describe('socket.io', function () {
});
});
it('should validate emails', function (done) {
describe('validation emails', function () {
var socketAdmin = require('../src/socket.io/admin');
socketAdmin.user.validateEmail({uid: adminUid}, [regularUid], function (err) {
assert.ifError(err);
user.getUserField(regularUid, 'email:confirmed', function (err, emailConfirmed) {
var meta = require('../src/meta');
it('should validate emails', function (done) {
socketAdmin.user.validateEmail({uid: adminUid}, [regularUid], function (err) {
assert.ifError(err);
user.getUserField(regularUid, 'email:confirmed', function (err, emailConfirmed) {
assert.ifError(err);
assert.equal(parseInt(emailConfirmed, 10), 1);
done();
});
});
});
it('should error with invalid uids', function (done) {
var socketAdmin = require('../src/socket.io/admin');
socketAdmin.user.sendValidationEmail({uid: adminUid}, null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should error if email validation is not required', function (done) {
var socketAdmin = require('../src/socket.io/admin');
socketAdmin.user.sendValidationEmail({uid: adminUid}, [regularUid], function (err) {
assert.equal(err.message, '[[error:email-confirmations-are-disabled]]');
done();
});
});
it('should send validation email', function (done) {
var socketAdmin = require('../src/socket.io/admin');
meta.config.requireEmailConfirmation = 1;
socketAdmin.user.sendValidationEmail({uid: adminUid}, [regularUid], function (err) {
assert.ifError(err);
assert.equal(parseInt(emailConfirmed, 10), 1);
meta.config.requireEmailConfirmation = 0;
done();
});
});

@ -170,6 +170,7 @@ describe('User', function () {
});
describe('.search()', function () {
var socketUser = require('../src/socket.io/user');
it('should return an object containing an array of matching users', function (done) {
User.search({query: 'john'}, function (err, searchData) {
assert.ifError(err);
@ -178,6 +179,30 @@ describe('User', function () {
done();
});
});
it('should search user', function (done) {
socketUser.search({uid: testUid}, {query: 'john'}, function (err, searchData) {
assert.ifError(err);
assert.equal(searchData.users[0].username, 'John Smith');
done();
});
});
it('should error for guest', function (done) {
Meta.config.allowGuestUserSearching = 0;
socketUser.search({uid: 0}, {query: 'john'}, function (err) {
assert.equal(err.message, '[[error:not-logged-in]]');
Meta.config.allowGuestUserSearching = 1;
done();
});
});
it('should error with invalid data', function (done) {
socketUser.search({uid: testUid}, null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
});
describe('.delete()', function () {
@ -659,6 +684,199 @@ describe('User', function () {
});
});
});
it('should fail if data is invalid', function (done) {
socketUser.emailExists({uid: testUid}, null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should return true if email exists', function (done) {
socketUser.emailExists({uid: testUid}, {email: 'john@example.com'}, function (err, exists) {
assert.ifError(err);
assert(exists);
done();
});
});
it('should return false if email does not exist', function (done) {
socketUser.emailExists({uid: testUid}, {email: 'does@not.exist'}, function (err, exists) {
assert.ifError(err);
assert(!exists);
done();
});
});
it('should error if requireEmailConfirmation is disabled', function (done) {
socketUser.emailConfirm({uid: testUid}, {}, function (err) {
assert.equal(err.message, '[[error:email-confirmations-are-disabled]]');
done();
});
});
it('should send email confirm', function (done) {
Meta.config.requireEmailConfirmation = 1;
socketUser.emailConfirm({uid: testUid}, {}, function (err) {
assert.ifError(err);
Meta.config.requireEmailConfirmation = 0;
done();
});
});
it('should send reset email', function (done) {
socketUser.reset.send({uid: 0}, 'john@example.com', function (err) {
assert.ifError(err);
done();
});
});
it('should return invalid-data error', function (done) {
socketUser.reset.send({uid: 0}, null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should not error', function (done) {
socketUser.reset.send({uid: 0}, 'doestnot@exist.com', function (err) {
assert.ifError(err);
done();
});
});
it('should commit reset', function (done) {
db.getObject('reset:uid', function (err, data) {
assert.ifError(err);
var code = Object.keys(data)[0];
socketUser.reset.commit({uid: 0}, {code: code, password: 'swordfish'}, function (err) {
assert.ifError(err);
done();
});
});
});
it('should save user settings', function (done) {
var data = {
uid: 1,
settings: {
bootswatchSkin: 'default',
homePageRoute: 'none',
homePageCustom: '',
openOutgoingLinksInNewTab: 0,
scrollToMyPost: 1,
delayImageLoading: 1,
userLang: 'en-GB',
usePagination: 1,
topicsPerPage: '10',
postsPerPage: '5',
showemail: 1,
showfullname: 1,
restrictChat: 0,
followTopicsOnCreate: 1,
followTopicsOnReply: 1,
notificationSound: '',
incomingChatSound: '',
outgoingChatSound: ''
}
};
socketUser.saveSettings({uid: testUid}, data, function (err) {
assert.ifError(err);
done();
});
});
it('should set moderation note', function (done) {
User.create({username: 'noteadmin'}, function (err, adminUid) {
assert.ifError(err);
groups.join('administrators', adminUid, function (err) {
assert.ifError(err);
socketUser.setModerationNote({uid: adminUid}, {uid: testUid, note: 'this is a test user'}, function (err) {
assert.ifError(err);
User.getUserField(testUid, 'moderationNote', function (err, note) {
assert.ifError(err);
assert.equal(note, 'this is a test user');
done();
});
});
});
});
});
});
describe('approval queue', function () {
var socketAdmin = require('../src/socket.io/admin');
var oldRegistrationType;
var adminUid;
before(function (done) {
oldRegistrationType = Meta.config.registrationType;
Meta.config.registrationType = 'admin-approval';
User.create({username: 'admin', password: '123456'}, function (err, uid) {
assert.ifError(err);
adminUid = uid;
groups.join('administrators', uid, done);
});
});
after(function (done) {
Meta.config.registrationType = oldRegistrationType;
done();
});
it('should add user to approval queue', function (done) {
helpers.registerUser({
username: 'rejectme',
password: '123456',
email: 'reject@me.com'
}, function (err) {
assert.ifError(err);
helpers.loginUser('admin', '123456', function (err, jar) {
assert.ifError(err);
request(nconf.get('url') + '/api/admin/manage/registration', {jar: jar, json: true}, function (err, res, body) {
assert.ifError(err);
assert.equal(body.users[0].username, 'rejectme');
assert.equal(body.users[0].email, 'reject@me.com');
done();
});
});
});
});
it('should reject user registration', function (done) {
socketAdmin.user.rejectRegistration({uid: adminUid}, {username: 'rejectme'}, function (err) {
assert.ifError(err);
User.getRegistrationQueue(0, -1, function (err, users) {
assert.ifError(err);
assert.equal(users.length, 0);
done();
});
});
});
it('should accept user registration', function (done) {
helpers.registerUser({
username: 'acceptme',
password: '123456',
email: 'accept@me.com'
}, function (err) {
assert.ifError(err);
socketAdmin.user.acceptRegistration({uid: adminUid}, {username: 'acceptme'}, function (err, uid) {
assert.ifError(err);
User.exists(uid, function (err, exists) {
assert.ifError(err);
assert(exists);
User.getRegistrationQueue(0, -1, function (err, users) {
assert.ifError(err);
assert.equal(users.length, 0);
done();
});
});
});
});
});
});

Loading…
Cancel
Save