mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-03 04:25:55 +01:00
Merge remote-tracking branch 'origin/master' into flagging-refactor
This commit is contained in:
@@ -52,7 +52,7 @@
|
|||||||
"morgan": "^1.3.2",
|
"morgan": "^1.3.2",
|
||||||
"mousetrap": "^1.5.3",
|
"mousetrap": "^1.5.3",
|
||||||
"nconf": "~0.8.2",
|
"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-dbsearch": "1.0.4",
|
||||||
"nodebb-plugin-emoji-extended": "1.1.1",
|
"nodebb-plugin-emoji-extended": "1.1.1",
|
||||||
"nodebb-plugin-emoji-one": "1.1.5",
|
"nodebb-plugin-emoji-one": "1.1.5",
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) {
|
|||||||
userData.isModerator = isModerator;
|
userData.isModerator = isModerator;
|
||||||
userData.isAdminOrGlobalModerator = isAdmin || isGlobalModerator;
|
userData.isAdminOrGlobalModerator = isAdmin || isGlobalModerator;
|
||||||
userData.isAdminOrGlobalModeratorOrModerator = isAdmin || isGlobalModerator || isModerator;
|
userData.isAdminOrGlobalModeratorOrModerator = isAdmin || isGlobalModerator || isModerator;
|
||||||
|
userData.isSelfOrAdminOrGlobalModerator = isSelf || isAdmin || isGlobalModerator;
|
||||||
userData.canEdit = isAdmin || (isGlobalModerator && !results.isTargetAdmin);
|
userData.canEdit = isAdmin || (isGlobalModerator && !results.isTargetAdmin);
|
||||||
userData.canBan = isAdmin || (isGlobalModerator && !results.isTargetAdmin);
|
userData.canBan = isAdmin || (isGlobalModerator && !results.isTargetAdmin);
|
||||||
userData.canChangePassword = isAdmin || (isSelf && parseInt(meta.config['password:disableEdit'], 10) !== 1);
|
userData.canChangePassword = isAdmin || (isSelf && parseInt(meta.config['password:disableEdit'], 10) !== 1);
|
||||||
|
|||||||
@@ -13,13 +13,9 @@ sessionController.revoke = function (req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _id;
|
var _id;
|
||||||
var uid;
|
var uid = res.locals.uid;
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
user.getUidByUserslug(req.params.userslug, next);
|
|
||||||
},
|
|
||||||
function (_uid, next) {
|
|
||||||
uid = _uid;
|
|
||||||
if (!uid) {
|
if (!uid) {
|
||||||
return next(new Error('[[error:no-session-found]]'));
|
return next(new Error('[[error:no-session-found]]'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,14 +162,24 @@ groupsController.members = function (req, res, callback) {
|
|||||||
groupsController.uploadCover = function (req, res, next) {
|
groupsController.uploadCover = function (req, res, next) {
|
||||||
var params = JSON.parse(req.body.params);
|
var params = JSON.parse(req.body.params);
|
||||||
|
|
||||||
groups.updateCover(req.uid, {
|
async.waterfall([
|
||||||
file: req.files.files[0].path,
|
function (next) {
|
||||||
groupName: params.groupName
|
groups.ownership.isOwner(req.uid, params.groupName, next);
|
||||||
}, function (err, image) {
|
},
|
||||||
|
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) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json([{url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url}]);
|
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) {
|
if (res.locals.isAPI) {
|
||||||
res.status(403).json({
|
res.status(403).json({
|
||||||
path: req.path.replace(/^\/api/, ''),
|
path: req.path.replace(/^\/api/, ''),
|
||||||
loggedIn: !!req.uid, error: error,
|
loggedIn: !!req.uid,
|
||||||
|
error: error,
|
||||||
title: '[[global:403.title]]'
|
title: '[[global:403.title]]'
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(403).render('403', {
|
res.status(403).render('403', {
|
||||||
path: req.path,
|
path: req.path,
|
||||||
loggedIn: !!req.uid, error: error,
|
loggedIn: !!req.uid,
|
||||||
|
error: error,
|
||||||
title: '[[global:403.title]]'
|
title: '[[global:403.title]]'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,12 @@ var fallbackTransport;
|
|||||||
delete data.from_name;
|
delete data.from_name;
|
||||||
|
|
||||||
winston.verbose('[emailer] Sending email to uid ' + data.uid);
|
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) {
|
function render(tpl, params, next) {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ var mime = require('mime');
|
|||||||
var winston = require('winston');
|
var winston = require('winston');
|
||||||
|
|
||||||
var db = require('../database');
|
var db = require('../database');
|
||||||
var file = require('../file');
|
|
||||||
var uploadsController = require('../controllers/uploads');
|
var uploadsController = require('../controllers/uploads');
|
||||||
|
|
||||||
module.exports = function (Groups) {
|
module.exports = function (Groups) {
|
||||||
@@ -25,7 +24,7 @@ module.exports = function (Groups) {
|
|||||||
Groups.updateCover = function (uid, data, callback) {
|
Groups.updateCover = function (uid, data, callback) {
|
||||||
|
|
||||||
// Position only? That's fine
|
// 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);
|
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);
|
Groups.setGroupField(data.groupName, 'cover:thumb:url', uploadData.url, next);
|
||||||
},
|
},
|
||||||
function (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) {
|
], function (err) {
|
||||||
if (err) {
|
fs.unlink(tempPath, function (unlinkErr) {
|
||||||
return fs.unlink(tempPath, function (unlinkErr) {
|
if (unlinkErr) {
|
||||||
if (unlinkErr) {
|
winston.error(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 {
|
|
||||||
callback(err, {url: url});
|
callback(err, {url: url});
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,30 @@ middleware.authenticate = function (req, res, next) {
|
|||||||
controllers.helpers.notAllowed(req, res);
|
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) {
|
middleware.pageView = function (req, res, next) {
|
||||||
analytics.pageView({
|
analytics.pageView({
|
||||||
ip: req.ip,
|
ip: req.ip,
|
||||||
|
|||||||
50
src/posts.js
50
src/posts.js
@@ -187,39 +187,37 @@ var plugins = require('./plugins');
|
|||||||
return callback(null, []);
|
return callback(null, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
user.getSettings(uid, function (err, settings) {
|
async.waterfall([
|
||||||
if (err) {
|
function (next) {
|
||||||
return callback(err);
|
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 byVotes = settings.topicPostSort === 'most_votes';
|
var uniqueSets = _.uniq(sets);
|
||||||
var sets = posts.map(function (post) {
|
var method = 'sortedSetsRanks';
|
||||||
return byVotes ? 'tid:' + post.tid + ':posts:votes' : 'tid:' + post.tid + ':posts';
|
if (uniqueSets.length === 1) {
|
||||||
});
|
method = 'sortedSetRanks';
|
||||||
|
sets = uniqueSets[0];
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
for (var i = 0; i < indices.length; ++i) {
|
||||||
indices[i] = utils.isNumber(indices[i]) ? parseInt(indices[i], 10) + 1 : 0;
|
indices[i] = utils.isNumber(indices[i]) ? parseInt(indices[i], 10) + 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(null, indices);
|
next(null, indices);
|
||||||
});
|
}
|
||||||
});
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Posts.updatePostVoteCount = function (postData, 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/info', middleware, accountMiddlewares, controllers.accounts.info.get);
|
||||||
setupPageRoute(app, '/user/:userslug/settings', middleware, accountMiddlewares, controllers.accounts.settings.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, '/notifications', middleware, [middleware.authenticate], controllers.accounts.notifications.get);
|
||||||
setupPageRoute(app, '/user/:userslug/chats/:roomid?', middleware, middlewares, controllers.accounts.chats.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]]'));
|
return callback(new Error('[[error:email-confirmations-are-disabled]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
user.getUsersFields(uids, ['uid', 'email'], function (err, usersData) {
|
async.waterfall([
|
||||||
if (err) {
|
function (next) {
|
||||||
return callback(err);
|
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);
|
||||||
}
|
}
|
||||||
|
], callback);
|
||||||
async.eachLimit(usersData, 50, function (userData, next) {
|
|
||||||
if (userData.email && userData.uid) {
|
|
||||||
user.email.sendValidationEmail(userData.uid, userData.email, next);
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
}, callback);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
User.sendPasswordResetEmail = function (socket, uids, 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 = function (socket, data, callback) {
|
||||||
user.acceptRegistration(data.username, function (err, uid) {
|
async.waterfall([
|
||||||
if (err) {
|
function (next) {
|
||||||
return callback(err);
|
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({
|
], callback);
|
||||||
type: 'registration-approved',
|
|
||||||
uid: socket.uid,
|
|
||||||
ip: socket.ip,
|
|
||||||
targetUid: uid,
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
User.rejectRegistration = function (socket, data, callback) {
|
User.rejectRegistration = function (socket, data, callback) {
|
||||||
user.rejectRegistration(data.username, function (err) {
|
async.waterfall([
|
||||||
if (err) {
|
function (next) {
|
||||||
return callback(err);
|
user.rejectRegistration(data.username, next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
events.log({
|
||||||
|
type: 'registration-rejected',
|
||||||
|
uid: socket.uid,
|
||||||
|
ip: socket.ip,
|
||||||
|
username: data.username,
|
||||||
|
});
|
||||||
|
next();
|
||||||
}
|
}
|
||||||
events.log({
|
], callback);
|
||||||
type: 'registration-rejected',
|
|
||||||
uid: socket.uid,
|
|
||||||
ip: socket.ip,
|
|
||||||
username: data.username,
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
User.restartJobs = function (socket, data, 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]]'));
|
return callback(new Error('[[error:no-privileges]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
groups.ownership.isOwner(socket.uid, data.groupName, function (err, isOwner) {
|
async.waterfall([
|
||||||
if (err || !isOwner) {
|
function (next) {
|
||||||
return callback(err || new Error('[[error:no-privileges]]'));
|
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) {
|
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]]'));
|
return callback(new Error('[[error:no-privileges]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
groups.ownership.isOwner(socket.uid, data.groupName, function (err, isOwner) {
|
async.waterfall([
|
||||||
if (err || !isOwner) {
|
function (next) {
|
||||||
return callback(err || new Error('[[error:no-privileges]]'));
|
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;
|
module.exports = SocketGroups;
|
||||||
|
|||||||
@@ -72,15 +72,21 @@ SocketUser.emailConfirm = function (socket, data, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parseInt(meta.config.requireEmailConfirmation, 10) !== 1) {
|
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) {
|
if (!data || !data.code || !data.password) {
|
||||||
return callback(new Error('[[error:invalid-data]]'));
|
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({
|
user.getUserField(uid, 'username', next);
|
||||||
uid: async.apply(db.getObjectField, 'reset:uid', data.code),
|
},
|
||||||
reset: async.apply(user.reset.commit, data.code, data.password)
|
function (username, next) {
|
||||||
}, function (err, results) {
|
var now = new Date();
|
||||||
if (err) {
|
var parsedDate = now.getFullYear() + '/' + (now.getMonth() + 1) + '/' + now.getDate();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
emailer.send('reset_notify', uid, {
|
emailer.send('reset_notify', uid, {
|
||||||
username: username,
|
username: username,
|
||||||
date: parsedDate,
|
date: parsedDate,
|
||||||
site_title: meta.config.title || 'NodeBB',
|
site_title: meta.config.title || 'NodeBB',
|
||||||
subject: '[[email:reset.notify.subject]]'
|
subject: '[[email:reset.notify.subject]]'
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
events.log({
|
next();
|
||||||
type: 'password-reset',
|
}
|
||||||
uid: uid,
|
], callback);
|
||||||
ip: socket.ip
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SocketUser.isFollowing = function (socket, data, callback) {
|
SocketUser.isFollowing = function (socket, data, callback) {
|
||||||
@@ -224,16 +228,10 @@ SocketUser.saveSettings = function (socket, data, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
SocketUser.setTopicSort = function (socket, sort, callback) {
|
SocketUser.setTopicSort = function (socket, sort, callback) {
|
||||||
if (!socket.uid) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
user.setSetting(socket.uid, 'topicPostSort', sort, callback);
|
user.setSetting(socket.uid, 'topicPostSort', sort, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
SocketUser.setCategorySort = function (socket, sort, callback) {
|
SocketUser.setCategorySort = function (socket, sort, callback) {
|
||||||
if (!socket.uid) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
user.setSetting(socket.uid, 'categoryTopicSort', sort, callback);
|
user.setSetting(socket.uid, 'categoryTopicSort', sort, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -46,18 +46,19 @@ module.exports = function (User) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function sendNotificationToAdmins(username, callback) {
|
function sendNotificationToAdmins(username, callback) {
|
||||||
notifications.create({
|
async.waterfall([
|
||||||
bodyShort: '[[notifications:new_register, ' + username + ']]',
|
function (next) {
|
||||||
nid: 'new_register:' + username,
|
notifications.create({
|
||||||
path: '/admin/manage/registration',
|
bodyShort: '[[notifications:new_register, ' + username + ']]',
|
||||||
mergeId: 'new_register'
|
nid: 'new_register:' + username,
|
||||||
}, function (err, notification) {
|
path: '/admin/manage/registration',
|
||||||
if (err || !notification) {
|
mergeId: 'new_register'
|
||||||
return callback(err);
|
}, next);
|
||||||
|
},
|
||||||
|
function (notification, next) {
|
||||||
|
notifications.pushGroup(notification, 'administrators', next);
|
||||||
}
|
}
|
||||||
|
], callback);
|
||||||
notifications.pushGroup(notification, 'administrators', callback);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
User.acceptRegistration = function (username, callback) {
|
User.acceptRegistration = function (username, callback) {
|
||||||
@@ -78,6 +79,12 @@ module.exports = function (User) {
|
|||||||
uid = _uid;
|
uid = _uid;
|
||||||
User.setUserField(uid, 'password', userData.hashedPassword, next);
|
User.setUserField(uid, 'password', userData.hashedPassword, next);
|
||||||
},
|
},
|
||||||
|
function (next) {
|
||||||
|
removeFromQueue(username, next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
markNotificationRead(username, next);
|
||||||
|
},
|
||||||
function (next) {
|
function (next) {
|
||||||
var title = meta.config.title || meta.config.browserTitle || 'NodeBB';
|
var title = meta.config.title || meta.config.browserTitle || 'NodeBB';
|
||||||
translator.translate('[[email:welcome-to, ' + title + ']]', meta.config.defaultLang, function (subject) {
|
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);
|
emailer.send('registration_accepted', uid, data, next);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function (next) {
|
|
||||||
removeFromQueue(username, next);
|
|
||||||
},
|
|
||||||
function (next) {
|
|
||||||
markNotificationRead(username, next);
|
|
||||||
},
|
|
||||||
function (next) {
|
function (next) {
|
||||||
next(null, uid);
|
next(null, uid);
|
||||||
}
|
}
|
||||||
@@ -153,13 +154,11 @@ module.exports = function (User) {
|
|||||||
},
|
},
|
||||||
function (users, next) {
|
function (users, next) {
|
||||||
users = users.map(function (user, index) {
|
users = users.map(function (user, index) {
|
||||||
if (!user) {
|
if (user) {
|
||||||
return null;
|
user.timestampISO = utils.toISOString(data[index].score);
|
||||||
|
delete user.hashedPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.timestampISO = utils.toISOString(data[index].score);
|
|
||||||
delete user.hashedPassword;
|
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
}).filter(Boolean);
|
}).filter(Boolean);
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,9 @@ module.exports = function (User) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
User.setSetting = function (uid, key, value, callback) {
|
User.setSetting = function (uid, key, value, callback) {
|
||||||
|
if (!parseInt(uid, 10)) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
db.setObjectField('user:' + uid + ':settings', key, value, callback);
|
db.setObjectField('user:' + uid + ':settings', key, value, callback);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ var Categories = require('../src/categories');
|
|||||||
var Topics = require('../src/topics');
|
var Topics = require('../src/topics');
|
||||||
var User = require('../src/user');
|
var User = require('../src/user');
|
||||||
var groups = require('../src/groups');
|
var groups = require('../src/groups');
|
||||||
|
var privileges = require('../src/privileges');
|
||||||
|
|
||||||
describe('Categories', function () {
|
describe('Categories', function () {
|
||||||
var categoryObj;
|
var categoryObj;
|
||||||
@@ -312,7 +313,7 @@ describe('Categories', function () {
|
|||||||
var socketCategories = require('../src/socket.io/admin/categories');
|
var socketCategories = require('../src/socket.io/admin/categories');
|
||||||
var cid;
|
var cid;
|
||||||
before(function (done) {
|
before(function (done) {
|
||||||
Categories.create({
|
socketCategories.create({uid: adminUid}, {
|
||||||
name: 'update name',
|
name: 'update name',
|
||||||
description: 'update description',
|
description: 'update description',
|
||||||
parentCid: categoryObj.cid,
|
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) {
|
after(function (done) {
|
||||||
|
|||||||
@@ -533,8 +533,8 @@ describe('Controllers', function () {
|
|||||||
}
|
}
|
||||||
}, function (err, res, body) {
|
}, function (err, res, body) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(res.statusCode, 500);
|
assert.equal(res.statusCode, 403);
|
||||||
assert.equal(body, '[[error:no-session-found]]');
|
assert.equal(body, '{"path":"/user/doesnotexist/session/1112233","loggedIn":true,"title":"[[global:403.title]]"}');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -794,7 +794,14 @@ describe('Controllers', function () {
|
|||||||
user.create({username: 'follower'}, function (err, _uid) {
|
user.create({username: 'follower'}, function (err, _uid) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
uid = _uid;
|
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) {
|
after(function (done) {
|
||||||
var analytics = require('../src/analytics');
|
var analytics = require('../src/analytics');
|
||||||
analytics.writeData(function (err) {
|
analytics.writeData(function (err) {
|
||||||
|
|||||||
139
test/groups.js
139
test/groups.js
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);
|
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('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_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('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);
|
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 () {
|
describe('flagging a post', function () {
|
||||||
var meta = require('../src/meta');
|
var meta = require('../src/meta');
|
||||||
var socketPosts = require('../src/socket.io/posts');
|
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');
|
var socketAdmin = require('../src/socket.io/admin');
|
||||||
socketAdmin.user.validateEmail({uid: adminUid}, [regularUid], function (err) {
|
var meta = require('../src/meta');
|
||||||
assert.ifError(err);
|
|
||||||
user.getUserField(regularUid, 'email:confirmed', function (err, emailConfirmed) {
|
it('should validate emails', function (done) {
|
||||||
|
socketAdmin.user.validateEmail({uid: adminUid}, [regularUid], function (err) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(parseInt(emailConfirmed, 10), 1);
|
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);
|
||||||
|
meta.config.requireEmailConfirmation = 0;
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
218
test/user.js
218
test/user.js
@@ -170,6 +170,7 @@ describe('User', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('.search()', function () {
|
describe('.search()', function () {
|
||||||
|
var socketUser = require('../src/socket.io/user');
|
||||||
it('should return an object containing an array of matching users', function (done) {
|
it('should return an object containing an array of matching users', function (done) {
|
||||||
User.search({query: 'john'}, function (err, searchData) {
|
User.search({query: 'john'}, function (err, searchData) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
@@ -178,6 +179,30 @@ describe('User', function () {
|
|||||||
done();
|
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 () {
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user