Merge branch 'master' into flagging-refactor

v1.18.x
Julian Lam 8 years ago
commit 0bf82c0e47

@ -35,7 +35,6 @@ module.exports = function (grunt) {
incomplete.push(compiling); incomplete.push(compiling);
} }
// @psychobunny, re: #5211, instead of this, just call `node app --build js` or `node app --build css,tpl`
updateArgs.push('--build'); updateArgs.push('--build');
updateArgs.push(incomplete.join(',')); updateArgs.push(incomplete.join(','));

@ -81,9 +81,9 @@
"semver": "^5.1.0", "semver": "^5.1.0",
"serve-favicon": "^2.1.5", "serve-favicon": "^2.1.5",
"sitemap": "^1.4.0", "sitemap": "^1.4.0",
"socket.io": "^1.4.8", "socket.io": "1.7.1",
"socket.io-client": "^1.4.0", "socket.io-client": "1.7.1",
"socket.io-redis": "1.1.1", "socket.io-redis": "2.0.0",
"socketio-wildcard": "~0.3.0", "socketio-wildcard": "~0.3.0",
"string": "^3.0.0", "string": "^3.0.0",
"templates.js": "0.3.4", "templates.js": "0.3.4",

@ -27,6 +27,7 @@ define('forum/chats/messages', ['components', 'sounds', 'translator'], function
message: msg message: msg
}, function (err) { }, function (err) {
if (err) { if (err) {
inputEl.val(msg);
if (err.message === '[[error:email-not-confirmed-chat]]') { if (err.message === '[[error:email-not-confirmed-chat]]') {
return app.showEmailConfirmWarning(err); return app.showEmailConfirmWarning(err);
} }
@ -42,6 +43,8 @@ define('forum/chats/messages', ['components', 'sounds', 'translator'], function
message: msg message: msg
}, function (err) { }, function (err) {
if (err) { if (err) {
inputEl.val(msg);
inputEl.attr('data-mid', mid);
return app.alertError(err.message); return app.alertError(err.message);
} }
}); });

@ -258,7 +258,7 @@ define('chat', [
Chats.addScrollHandler(chatModal.attr('roomId'), data.uid, chatModal.find('.chat-content')); Chats.addScrollHandler(chatModal.attr('roomId'), data.uid, chatModal.find('.chat-content'));
taskbar.push('chat', chatModal.attr('UUID'), { taskbar.push('chat', chatModal.attr('UUID'), {
title: data.users.length ? data.users[0].username : '', title: data.roomName || (data.users.length ? data.users[0].username : ''),
roomId: data.roomId, roomId: data.roomId,
icon: 'fa-comment', icon: 'fa-comment',
state: '' state: ''

@ -33,6 +33,9 @@ module.exports = function (Categories) {
}; };
Categories.markAsUnreadForAll = function (cid, callback) { Categories.markAsUnreadForAll = function (cid, callback) {
if (!parseInt(cid, 10)) {
return callback();
}
callback = callback || function () {}; callback = callback || function () {};
db.delete('cid:' + cid + ':read_by_uid', callback); db.delete('cid:' + cid + ':read_by_uid', callback);
}; };

@ -105,9 +105,9 @@ topicsController.get = function (req, res, callback) {
} else if (!req.query.page) { } else if (!req.query.page) {
var index; var index;
if (reverse) { if (reverse) {
index = Math.max(0, postCount - (req.params.post_index || postCount)); index = Math.max(0, postCount - (req.params.post_index || postCount) + 2);
} else { } else {
index = Math.max(0, req.params.post_index - 1) || 0; index = Math.max(0, req.params.post_index) || 0;
} }
currentPage = Math.max(1, Math.ceil(index / settings.postsPerPage)); currentPage = Math.max(1, Math.ceil(index / settings.postsPerPage));

@ -12,48 +12,57 @@ module.exports = function (Groups) {
Groups.update = function (groupName, values, callback) { Groups.update = function (groupName, values, callback) {
callback = callback || function () {}; callback = callback || function () {};
db.exists('group:' + groupName, function (err, exists) {
if (err || !exists) {
return callback(err || new Error('[[error:no-group]]'));
}
plugins.fireHook('filter:group.update', { async.waterfall([
groupName: groupName, function (next) {
values: values db.exists('group:' + groupName, next);
}, function (err) { },
if (err) { function (exists, next) {
return callback(err); if (!exists) {
return next(new Error('[[error:no-group]]'));
} }
plugins.fireHook('filter:group.update', {
groupName: groupName,
values: values
}, next);
},
function (result, next) {
values = result.values;
var payload = { var payload = {
description: values.description || '', description: values.description || '',
icon: values.icon || '', icon: values.icon || '',
labelColor: values.labelColor || '#000000' labelColor: values.labelColor || '#000000'
}; };
if (values.hasOwnProperty('userTitle')) { if (values.hasOwnProperty('userTitle')) {
payload.userTitle = values.userTitle || ''; payload.userTitle = values.userTitle || '';
} }
if (values.hasOwnProperty('userTitleEnabled')) { if (values.hasOwnProperty('userTitleEnabled')) {
payload.userTitleEnabled = values.userTitleEnabled ? '1' : '0'; payload.userTitleEnabled = values.userTitleEnabled ? '1' : '0';
} }
if (values.hasOwnProperty('hidden')) { if (values.hasOwnProperty('hidden')) {
payload.hidden = values.hidden ? '1' : '0'; payload.hidden = values.hidden ? '1' : '0';
} }
if (values.hasOwnProperty('private')) { if (values.hasOwnProperty('private')) {
payload.private = values.private ? '1' : '0'; payload.private = values.private ? '1' : '0';
} }
if (values.hasOwnProperty('disableJoinRequests')) { if (values.hasOwnProperty('disableJoinRequests')) {
payload.disableJoinRequests = values.disableJoinRequests ? '1' : '0'; payload.disableJoinRequests = values.disableJoinRequests ? '1' : '0';
} }
async.series([ async.series([
async.apply(checkNameChange, groupName, values.name), async.apply(checkNameChange, groupName, values.name),
async.apply(updatePrivacy, groupName, values.private), function (next) {
if (values.hasOwnProperty('private')) {
updatePrivacy(groupName, values.private, next);
} else {
next();
}
},
function (next) { function (next) {
if (values.hasOwnProperty('hidden')) { if (values.hasOwnProperty('hidden')) {
updateVisibility(groupName, values.hidden, next); updateVisibility(groupName, values.hidden, next);
@ -63,19 +72,16 @@ module.exports = function (Groups) {
}, },
async.apply(db.setObject, 'group:' + groupName, payload), async.apply(db.setObject, 'group:' + groupName, payload),
async.apply(renameGroup, groupName, values.name) async.apply(renameGroup, groupName, values.name)
], function (err) { ], next);
if (err) { },
return callback(err); function (result, next) {
} plugins.fireHook('action:group.update', {
name: groupName,
plugins.fireHook('action:group.update', { values: values
name: groupName,
values: values
});
callback();
}); });
}); next();
}); }
], callback);
}; };
function updateVisibility(groupName, hidden, callback) { function updateVisibility(groupName, hidden, callback) {
@ -118,35 +124,33 @@ module.exports = function (Groups) {
}); });
} }
function updatePrivacy(groupName, newValue, callback) { function updatePrivacy(groupName, isPrivate, callback) {
if (!newValue) { async.waterfall([
return callback(); function (next) {
} Groups.getGroupFields(groupName, ['private'], next);
},
function (currentValue, next) {
var currentlyPrivate = parseInt(currentValue.private, 10) === 1;
if (!currentlyPrivate || currentlyPrivate === isPrivate) {
return callback();
}
db.getSetMembers('group:' + groupName + ':pending', next);
},
function (uids, next) {
if (!uids.length) {
return callback();
}
var now = Date.now();
var scores = uids.map(function () { return now; });
Groups.getGroupFields(groupName, ['private'], function (err, currentValue) { winston.verbose('[groups.update] Group is now public, automatically adding ' + uids.length + ' new members, who were pending prior.');
if (err) { async.series([
return callback(err); async.apply(db.sortedSetAdd, 'group:' + groupName + ':members', scores, uids),
} async.apply(db.delete, 'group:' + groupName + ':pending')
currentValue = currentValue.private === '1'; ], next);
if (currentValue !== newValue && currentValue === true) {
// Group is now public, so all pending users are automatically considered members
db.getSetMembers('group:' + groupName + ':pending', function (err, uids) {
if (err) { return callback(err); }
else if (!uids) { return callback(); } // No pending users, we're good to go
var now = Date.now(),
scores = uids.map(function () { return now; }); // There's probably a better way to initialise an Array of size x with the same value...
winston.verbose('[groups.update] Group is now public, automatically adding ' + uids.length + ' new members, who were pending prior.');
async.series([
async.apply(db.sortedSetAdd, 'group:' + groupName + ':members', scores, uids),
async.apply(db.delete, 'group:' + groupName + ':pending')
], callback);
});
} else {
callback();
} }
], function (err) {
callback(err);
}); });
} }

@ -16,7 +16,7 @@ module.exports = function (Meta) {
scripts: { scripts: {
base: [ base: [
'./node_modules/jquery/dist/jquery.js', './node_modules/jquery/dist/jquery.js',
'./node_modules/socket.io-client/socket.io.js', './node_modules/socket.io-client/dist/socket.io.js',
'public/vendor/jquery/timeago/jquery.timeago.js', 'public/vendor/jquery/timeago/jquery.timeago.js',
'public/vendor/jquery/js/jquery.form.min.js', 'public/vendor/jquery/js/jquery.form.min.js',
'public/vendor/visibility/visibility.min.js', 'public/vendor/visibility/visibility.min.js',

@ -352,7 +352,9 @@ var utils = require('../public/src/utils');
function (next) { function (next) {
db.sortedSetAdd('uid:' + uid + ':notifications:read', datetimes, nids, next); db.sortedSetAdd('uid:' + uid + ':notifications:read', datetimes, nids, next);
} }
], callback); ], function (err) {
callback(err);
});
}); });
}; };

@ -261,7 +261,7 @@ module.exports = function (Plugins) {
} }
var pathToFolder = path.join(__dirname, '../../node_modules/', pluginData.id, pluginData.languages); var pathToFolder = path.join(__dirname, '../../node_modules/', pluginData.id, pluginData.languages);
var defaultLang = pluginData.defaultLang.replace('_', '-').replace('@', '-x-'); var defaultLang = (pluginData.defaultLang || 'en_GB').replace('_', '-').replace('@', '-x-');
utils.walk(pathToFolder, function (err, languages) { utils.walk(pathToFolder, function (err, languages) {
if (err) { if (err) {
@ -346,9 +346,11 @@ module.exports = function (Plugins) {
if (err) { if (err) {
return callback(err); return callback(err);
} }
var pluginData;
var packageData;
try { try {
var pluginData = JSON.parse(results.plugin); pluginData = JSON.parse(results.plugin);
var packageData = JSON.parse(results.package); packageData = JSON.parse(results.package);
pluginData.id = packageData.name; pluginData.id = packageData.name;
pluginData.name = packageData.name; pluginData.name = packageData.name;
@ -356,16 +358,15 @@ module.exports = function (Plugins) {
pluginData.version = packageData.version; pluginData.version = packageData.version;
pluginData.repository = packageData.repository; pluginData.repository = packageData.repository;
pluginData.nbbpm = packageData.nbbpm; pluginData.nbbpm = packageData.nbbpm;
callback(null, pluginData);
} catch(err) { } catch(err) {
var pluginDir = pluginPath.split(path.sep); var pluginDir = pluginPath.split(path.sep);
pluginDir = pluginDir[pluginDir.length - 1]; pluginDir = pluginDir[pluginDir.length - 1];
winston.error('[plugins/' + pluginDir + '] Error in plugin.json or package.json! ' + err.message); winston.error('[plugins/' + pluginDir + '] Error in plugin.json or package.json! ' + err.message);
callback(new Error('[[error:parse-error]]')); return callback(new Error('[[error:parse-error]]'));
} }
callback(null, pluginData);
}); });
}; };
}; };

@ -9,13 +9,14 @@ var categories = require('./categories');
var topics = require('./topics'); var topics = require('./topics');
var privileges = require('./privileges'); var privileges = require('./privileges');
var meta = require('./meta'); var meta = require('./meta');
var plugins = require('./plugins');
var utils = require('../public/src/utils'); var utils = require('../public/src/utils');
var sitemap = { var sitemap = {
maps: { maps: {
topics: [] topics: []
} }
}; };
sitemap.render = function (callback) { sitemap.render = function (callback) {
var numTopics = parseInt(meta.config.sitemapTopics, 10) || 500; var numTopics = parseInt(meta.config.sitemapTopics, 10) || 500;
@ -71,13 +72,18 @@ sitemap.getPages = function (callback) {
priority: 0.4 priority: 0.4
}]; }];
sitemap.maps.pages = sm.createSitemap({ plugins.fireHook('filter:sitemap.getPages', {urls: urls}, function (err, data) {
hostname: nconf.get('url'), if (err) {
cacheTime: 1000 * 60 * 60 * 24, // Cached for 24 hours return callback(err);
urls: urls }
}); sitemap.maps.pages = sm.createSitemap({
hostname: nconf.get('url'),
cacheTime: 1000 * 60 * 60 * 24, // Cached for 24 hours
urls: data.urls
});
sitemap.maps.pages.toXML(callback); sitemap.maps.pages.toXML(callback);
});
}; };
sitemap.getCategories = function (callback) { sitemap.getCategories = function (callback) {

@ -44,7 +44,7 @@ SocketPosts.reply = function (socket, data, callback) {
callback(null, postData); callback(null, postData);
socket.emit('event:new_post', result); websockets.in('uid_' + socket.uid).emit('event:new_post', result);
user.updateOnlineUsers(socket.uid); user.updateOnlineUsers(socket.uid);

@ -11,61 +11,67 @@ module.exports = function (SocketTopics) {
if (!Array.isArray(tids) || !socket.uid) { if (!Array.isArray(tids) || !socket.uid) {
return callback(new Error('[[error:invalid-data]]')); return callback(new Error('[[error:invalid-data]]'));
} }
async.waterfall([
topics.markAsRead(tids, socket.uid, function (err) { function (next) {
if (err) { topics.markAsRead(tids, socket.uid, next);
return callback(err); },
function (hasMarked, next) {
if (hasMarked) {
topics.pushUnreadCount(socket.uid);
topics.markTopicNotificationsRead(tids, socket.uid);
}
next();
} }
], callback);
topics.pushUnreadCount(socket.uid);
topics.markTopicNotificationsRead(tids, socket.uid);
callback();
});
}; };
SocketTopics.markTopicNotificationsRead = function (socket, tids, callback) { SocketTopics.markTopicNotificationsRead = function (socket, tids, callback) {
if (!Array.isArray(tids) || !socket.uid) { if (!Array.isArray(tids) || !socket.uid) {
return callback(new Error('[[error:invalid-data]]')); return callback(new Error('[[error:invalid-data]]'));
} }
topics.markTopicNotificationsRead(tids, socket.uid); topics.markTopicNotificationsRead(tids, socket.uid, callback);
}; };
SocketTopics.markAllRead = function (socket, data, callback) { SocketTopics.markAllRead = function (socket, data, callback) {
topics.markAllRead(socket.uid, function (err) { if (!socket.uid) {
if (err) { return callback(new Error('[[error:invalid-uid]]'));
return callback(err); }
async.waterfall([
function (next) {
topics.markAllRead(socket.uid, next);
},
function (next) {
topics.pushUnreadCount(socket.uid);
next();
} }
], callback);
topics.pushUnreadCount(socket.uid);
callback();
});
}; };
SocketTopics.markCategoryTopicsRead = function (socket, cid, callback) { SocketTopics.markCategoryTopicsRead = function (socket, cid, callback) {
topics.getUnreadTids(cid, socket.uid, '', function (err, tids) { async.waterfall([
if (err) { function (next) {
return callback(err); topics.getUnreadTids(cid, socket.uid, '', next);
},
function (tids, next) {
SocketTopics.markAsRead(socket, tids, next);
} }
], callback);
SocketTopics.markAsRead(socket, tids, callback);
});
}; };
SocketTopics.markUnread = function (socket, tid, callback) { SocketTopics.markUnread = function (socket, tid, callback) {
if (!tid || !socket.uid) { if (!tid || !socket.uid) {
return callback(new Error('[[error:invalid-data]]')); return callback(new Error('[[error:invalid-data]]'));
} }
topics.markUnread(tid, socket.uid, function (err) { async.waterfall([
if (err) { function (next) {
return callback(err); topics.markUnread(tid, socket.uid, next);
},
function (next) {
topics.pushUnreadCount(socket.uid);
next();
} }
], callback);
topics.pushUnreadCount(socket.uid);
callback();
});
}; };
SocketTopics.markAsUnreadForAll = function (socket, tids, callback) { SocketTopics.markAsUnreadForAll = function (socket, tids, callback) {
@ -77,42 +83,41 @@ module.exports = function (SocketTopics) {
return callback(new Error('[[error:no-privileges]]')); return callback(new Error('[[error:no-privileges]]'));
} }
user.isAdministrator(socket.uid, function (err, isAdmin) { async.waterfall([
if (err) { function (next) {
return callback(err); user.isAdministrator(socket.uid, next);
} },
function (isAdmin, next) {
async.each(tids, function (tid, next) { async.each(tids, function (tid, next) {
async.waterfall([ async.waterfall([
function (next) { function (next) {
topics.exists(tid, next); topics.exists(tid, next);
}, },
function (exists, next) { function (exists, next) {
if (!exists) { if (!exists) {
return next(new Error('[[error:invalid-tid]]')); return next(new Error('[[error:no-topic]]'));
} }
topics.getTopicField(tid, 'cid', next); topics.getTopicField(tid, 'cid', next);
}, },
function (cid, next) { function (cid, next) {
user.isModerator(socket.uid, cid, next); user.isModerator(socket.uid, cid, next);
}, },
function (isMod, next) { function (isMod, next) {
if (!isAdmin && !isMod) { if (!isAdmin && !isMod) {
return next(new Error('[[error:no-privileges]]')); return next(new Error('[[error:no-privileges]]'));
}
topics.markAsUnreadForAll(tid, next);
},
function (next) {
topics.updateRecent(tid, Date.now(), next);
} }
topics.markAsUnreadForAll(tid, next); ], next);
}, }, next);
function (next) { },
topics.updateRecent(tid, Date.now(), next); function (next) {
}
], next);
}, function (err) {
if (err) {
return callback(err);
}
topics.pushUnreadCount(socket.uid); topics.pushUnreadCount(socket.uid);
callback(); next();
}); }
}); ], callback);
}; };
}; };

@ -74,7 +74,10 @@ module.exports = function (Topics) {
function (next) { function (next) {
method2(tid, uid, next); method2(tid, uid, next);
}, },
async.apply(plugins.fireHook, hook, {uid: uid, tid: tid}) function (next) {
plugins.fireHook(hook, {uid: uid, tid: tid});
next();
}
], callback); ], callback);
} }

@ -2,7 +2,6 @@
'use strict'; 'use strict';
var async = require('async'); var async = require('async');
var winston = require('winston');
var db = require('../database'); var db = require('../database');
var user = require('../user'); var user = require('../user');
@ -277,9 +276,10 @@ module.exports = function (Topics) {
], callback); ], callback);
}; };
Topics.markTopicNotificationsRead = function (tids, uid) { Topics.markTopicNotificationsRead = function (tids, uid, callback) {
callback = callback || function () {};
if (!Array.isArray(tids) || !tids.length) { if (!Array.isArray(tids) || !tids.length) {
return; return callback();
} }
async.waterfall([ async.waterfall([
@ -288,23 +288,23 @@ module.exports = function (Topics) {
}, },
function (nids, next) { function (nids, next) {
notifications.markReadMultiple(nids, uid, next); notifications.markReadMultiple(nids, uid, next);
},
function (next) {
user.notifications.pushCount(uid);
next();
} }
], function (err) { ], callback);
if (err) {
return winston.error(err);
}
user.notifications.pushCount(uid);
});
}; };
Topics.markCategoryUnreadForAll = function (tid, callback) { Topics.markCategoryUnreadForAll = function (tid, callback) {
Topics.getTopicField(tid, 'cid', function (err, cid) { async.waterfall([
if(err) { function (next) {
return callback(err); Topics.getTopicField(tid, 'cid', next);
},
function (cid, next) {
categories.markAsUnreadForAll(cid, next);
} }
], callback);
categories.markAsUnreadForAll(cid, callback);
});
}; };
Topics.hasReadTopics = function (tids, uid, callback) { Topics.hasReadTopics = function (tids, uid, callback) {

@ -504,6 +504,128 @@ describe('Groups', function () {
}); });
describe('admin socket methods', function () {
var socketGroups = require('../src/socket.io/admin/groups');
it('should fail to create group with invalid data', function (done) {
socketGroups.create({uid: adminUid}, null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should fail to create group if group name is privilege group', function (done) {
socketGroups.create({uid: adminUid}, {name: 'cid:1:privileges:read'}, function (err) {
assert.equal(err.message, '[[error:invalid-group-name]]');
done();
});
});
it('should create a group', function (done) {
socketGroups.create({uid: adminUid}, {name: 'newgroup', description: 'group created by admin'}, function (err, groupData) {
assert.ifError(err);
assert.equal(groupData.name, 'newgroup');
assert.equal(groupData.description, 'group created by admin');
assert.equal(groupData.ownerUid, adminUid);
assert.equal(groupData.private, true);
assert.equal(groupData.memberCount, 1);
done();
});
});
it('should fail to join with invalid data', function (done) {
socketGroups.join({uid: adminUid}, null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should add user to group', function (done) {
socketGroups.join({uid: adminUid}, {uid: testUid, groupName: 'newgroup'}, function (err) {
assert.ifError(err);
Groups.isMember(testUid, 'newgroup', function (err, isMember) {
assert.ifError(err);
assert(isMember);
done();
});
});
});
it('should fail to if user is already member', function (done) {
socketGroups.join({uid: adminUid}, {uid: testUid, groupName: 'newgroup'}, function (err) {
assert.equal(err.message, '[[error:group-already-member]]');
done();
});
});
it('it should fail with invalid data', function (done) {
socketGroups.leave({uid: adminUid}, null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('it should fail if admin tries to remove self', function (done) {
socketGroups.leave({uid: adminUid}, {uid: adminUid, groupName: 'administrators'}, function (err) {
assert.equal(err.message, '[[error:cant-remove-self-as-admin]]');
done();
});
});
it('should fail if user is not member', function (done) {
socketGroups.leave({uid: adminUid}, {uid: 3, groupName: 'newgroup'}, function (err) {
assert.equal(err.message, '[[error:group-not-member]]');
done();
});
});
it('should remove user from group', function (done) {
socketGroups.leave({uid: adminUid}, {uid: testUid, groupName: 'newgroup'}, function (err) {
assert.ifError(err);
Groups.isMember(testUid, 'newgroup', function (err, isMember) {
assert.ifError(err);
assert(!isMember);
done();
});
});
});
it('should fail with invalid data', function (done) {
socketGroups.update({uid: adminUid}, null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should update group', function (done) {
var data = {
groupName: 'newgroup',
values: {
name: 'renamedgroup',
description: 'cat group',
userTitle: 'cats',
userTitleEnabled: 1,
disableJoinRequests: 1,
hidden: 1,
private: 0
}
};
socketGroups.update({uid: adminUid}, data, function (err) {
assert.ifError(err);
Groups.get('renamedgroup', {}, function (err, groupData) {
assert.ifError(err);
assert.equal(groupData.name, 'renamedgroup');
assert.equal(groupData.userTitle, 'cats');
assert.equal(groupData.description, 'cat group');
assert.equal(groupData.hidden, true);
assert.equal(groupData.disableJoinRequests, true);
assert.equal(groupData.private, false);
done();
});
});
});
});
after(function (done) { after(function (done) {
db.emptydb(done); db.emptydb(done);
}); });

@ -100,6 +100,9 @@
function (next) { function (next) {
meta.configs.init(next); meta.configs.init(next);
}, },
function (next) {
meta.dependencies.check(next);
},
function (next) { function (next) {
meta.config.postDelay = 0; meta.config.postDelay = 0;
meta.config.initialPostDelay = 0; meta.config.initialPostDelay = 0;
@ -107,6 +110,12 @@
enableDefaultPlugins(next); enableDefaultPlugins(next);
}, },
function (next) {
meta.themes.set({
type: 'local',
id: 'nodebb-theme-persona'
}, next);
},
function (next) { function (next) {
// nconf defaults, if not set in config // nconf defaults, if not set in config
if (!nconf.get('upload_path')) { if (!nconf.get('upload_path')) {

@ -683,6 +683,200 @@ describe('Topic\'s', function () {
}); });
}); });
describe('unread', function () {
var socketTopics = require('../src/socket.io/topics');
var tid;
var mainPid;
var uid;
before(function (done) {
async.parallel({
topic: function (next) {
topics.post({uid: topic.userId, title: 'unread topic', content: 'unread topic content', cid: topic.categoryId}, next);
},
user: function (next) {
User.create({username: 'regularJoe'}, next);
}
}, function (err, results) {
assert.ifError(err);
tid = results.topic.topicData.tid;
mainPid = results.topic.postData.pid;
uid = results.user;
done();
});
});
it('should fail with invalid data', function (done) {
socketTopics.markUnread({uid: adminUid}, null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should fail if topic does not exist', function (done) {
socketTopics.markUnread({uid: adminUid}, 1231082, function (err) {
assert.equal(err.message, '[[error:no-topic]]');
done();
});
});
it('should mark topic unread', function (done) {
socketTopics.markUnread({uid: adminUid}, tid, function (err) {
assert.ifError(err);
topics.hasReadTopic(tid, adminUid, function (err, hasRead) {
assert.ifError(err);
assert.equal(hasRead, false);
done();
});
});
});
it('should fail with invalid data', function (done) {
socketTopics.markAsRead({uid: 0}, null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should mark topic read', function (done) {
socketTopics.markAsRead({uid: adminUid}, [tid], function (err) {
assert.ifError(err);
topics.hasReadTopic(tid, adminUid, function (err, hasRead) {
assert.ifError(err);
assert(hasRead);
done();
});
});
});
it('should fail with invalid data', function (done) {
socketTopics.markTopicNotificationsRead({uid: 0}, null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should mark topic notifications read', function (done) {
var socketPosts = require('../src/socket.io/posts');
async.waterfall([
function (next) {
socketTopics.follow({uid: adminUid}, tid, next);
},
function (next) {
socketPosts.reply({uid: uid}, {content: 'some content', tid: tid}, next);
},
function (data, next) {
setTimeout(next, 2500);
},
function (next) {
User.notifications.getUnreadCount(adminUid, next);
},
function (count, next) {
assert.equal(count, 1);
socketTopics.markTopicNotificationsRead({uid: adminUid}, [tid], next);
},
function (next) {
User.notifications.getUnreadCount(adminUid, next);
},
function (count, next) {
assert.equal(count, 0);
next();
}
], function (err) {
assert.ifError(err);
done();
});
});
it('should fail with invalid data', function (done) {
socketTopics.markAllRead({uid: 0}, null, function (err) {
assert.equal(err.message, '[[error:invalid-uid]]');
done();
});
});
it('should mark all read', function (done) {
socketTopics.markUnread({uid: adminUid}, tid, function (err) {
assert.ifError(err);
socketTopics.markAllRead({uid: adminUid}, {}, function (err) {
assert.ifError(err);
topics.hasReadTopic(tid, adminUid, function (err, hasRead) {
assert.ifError(err);
assert(hasRead);
done();
});
});
});
});
it('should mark all read', function (done) {
socketTopics.markUnread({uid: adminUid}, tid, function (err) {
assert.ifError(err);
socketTopics.markCategoryTopicsRead({uid: adminUid}, topic.categoryId, function (err) {
assert.ifError(err);
topics.hasReadTopic(tid, adminUid, function (err, hasRead) {
assert.ifError(err);
assert(hasRead);
done();
});
});
});
});
it('should fail with invalid data', function (done) {
socketTopics.markAsUnreadForAll({uid: adminUid}, null, function (err) {
assert.equal(err.message, '[[error:invalid-tid]]');
done();
});
});
it('should fail with invalid data', function (done) {
socketTopics.markAsUnreadForAll({uid: 0}, [tid], function (err) {
assert.equal(err.message, '[[error:no-privileges]]');
done();
});
});
it('should fail if user is not admin', function (done) {
socketTopics.markAsUnreadForAll({uid: uid}, [tid], function (err) {
assert.equal(err.message, '[[error:no-privileges]]');
done();
});
});
it('should fail if topic does not exist', function (done) {
socketTopics.markAsUnreadForAll({uid: uid}, [12312313], function (err) {
assert.equal(err.message, '[[error:no-topic]]');
done();
});
});
it('should mark topic unread for everyone', function (done) {
socketTopics.markAsUnreadForAll({uid: adminUid}, [tid], function (err) {
assert.ifError(err);
async.parallel({
adminRead: function (next) {
topics.hasReadTopic(tid, adminUid, next);
},
regularRead: function (next) {
topics.hasReadTopic(tid, uid, next);
}
}, function (err, results) {
assert.ifError(err);
assert.equal(results.adminRead, false);
assert.equal(results.regularRead, false);
done();
});
});
});
});
after(function (done) { after(function (done) {

Loading…
Cancel
Save