diff --git a/public/src/admin/manage/category.js b/public/src/admin/manage/category.js index 57dc7be563..b58d3295b9 100644 --- a/public/src/admin/manage/category.js +++ b/public/src/admin/manage/category.js @@ -316,7 +316,7 @@ define('admin/manage/category', [ autocomplete.user(inputEl, function(ev, ui) { socket.emit('admin.categories.setPrivilege', { cid: ajaxify.data.category.cid, - privilege: ['find', 'read'], + privilege: ['find', 'read', 'topics:read'], set: true, member: ui.item.user.uid }, function(err) { @@ -344,7 +344,7 @@ define('admin/manage/category', [ autocomplete.group(inputEl, function(ev, ui) { socket.emit('admin.categories.setPrivilege', { cid: ajaxify.data.category.cid, - privilege: ['groups:find', 'groups:read'], + privilege: ['groups:find', 'groups:read', 'groups:topics:read'], set: true, member: ui.item.group.name }, function(err) { diff --git a/src/categories/create.js b/src/categories/create.js index 82a317270b..ccd1fc0b53 100644 --- a/src/categories/create.js +++ b/src/categories/create.js @@ -48,7 +48,7 @@ module.exports = function(Categories) { function(data, next) { category = data.category; - var defaultPrivileges = ['find', 'read', 'topics:create', 'topics:reply']; + var defaultPrivileges = ['find', 'read', 'topics:read', 'topics:create', 'topics:reply']; async.series([ async.apply(db.setObject, 'category:' + category.cid, category), @@ -57,7 +57,7 @@ module.exports = function(Categories) { async.apply(db.sortedSetAdd, 'cid:' + parentCid + ':children', category.order, category.cid), async.apply(privileges.categories.give, defaultPrivileges, category.cid, 'administrators'), async.apply(privileges.categories.give, defaultPrivileges, category.cid, 'registered-users'), - async.apply(privileges.categories.give, ['find', 'read'], category.cid, 'guests') + async.apply(privileges.categories.give, ['find', 'read', 'topics:read'], category.cid, 'guests') ], next); }, function(results, next) { @@ -133,7 +133,7 @@ module.exports = function(Categories) { Categories.copyPrivilegesFrom = function(fromCid, toCid, callback) { var privilegeList = [ - 'find', 'read', 'topics:create', 'topics:reply', 'purge', 'mods', + 'find', 'read', 'topics:create', 'topics:read', 'topics:reply', 'purge', 'mods', 'groups:find', 'groups:read', 'groups:topics:create', 'groups:topics:reply', 'groups:purge', 'groups:moderate' ]; diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 750622b4b4..f36c1d5ed0 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -50,7 +50,7 @@ topicsController.get = function(req, res, callback) { userPrivileges = results.privileges; - if (!userPrivileges.read || (parseInt(results.topic.deleted, 10) && !userPrivileges.view_deleted)) { + if (!userPrivileges.read || !userPrivileges['topics:read'] || (parseInt(results.topic.deleted, 10) && !userPrivileges.view_deleted)) { return helpers.notAllowed(req, res); } diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 7d0043859b..9ccc6b3b03 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -18,8 +18,9 @@ module.exports = function(privileges) { // Method used in admin/category controller to show all users/groups with privs in that given cid var privilegeLabels = [ - {name: 'Find category'}, - {name: 'Access & Read'}, + {name: 'Find Category'}, + {name: 'Access Category'}, + {name: 'Access Topics'}, {name: 'Create Topics'}, {name: 'Reply to Topics'}, {name: 'Purge'}, @@ -27,10 +28,10 @@ module.exports = function(privileges) { ]; var userPrivilegeList = [ - 'find', 'read', 'topics:create', 'topics:reply', 'purge', 'mods' + 'find', 'read', 'topics:read', 'topics:create', 'topics:reply', 'purge', 'mods' ]; var groupPrivilegeList = [ - 'groups:find', 'groups:read', 'groups:topics:create', 'groups:topics:reply', 'groups:purge', 'groups:moderate' + 'groups:find', 'groups:read', 'groups:topics:read', 'groups:topics:create', 'groups:topics:reply', 'groups:purge', 'groups:moderate' ]; async.parallel({ @@ -162,6 +163,9 @@ module.exports = function(privileges) { 'topics:create': function(next) { helpers.isUserAllowedTo('topics:create', uid, [cid], next); }, + 'topics:read': function(next) { + helpers.isUserAllowedTo('topics:read', uid, [cid], next); + }, read: function(next) { helpers.isUserAllowedTo('read', uid, [cid], next); }, @@ -182,6 +186,7 @@ module.exports = function(privileges) { cid: cid, uid: uid, 'topics:create': results['topics:create'][0] || isAdminOrMod, + 'topics:read': results['topics:read'][0] || isAdminOrMod, editable: isAdminOrMod, view_deleted: isAdminOrMod, read: results.read[0] || isAdminOrMod, @@ -356,6 +361,9 @@ module.exports = function(privileges) { 'topics:create': function(next) { groups.isMember(uid, 'cid:' + cid + ':privileges:topics:create', next); }, + 'topics:read': function(next) { + groups.isMember(uid, 'cid:' + cid + ':privileges:topics:read', next); + }, 'topics:reply': function(next) { groups.isMember(uid, 'cid:' + cid + ':privileges:topics:reply', next); }, @@ -376,6 +384,9 @@ module.exports = function(privileges) { }, 'groups:topics:reply': function(next) { groups.isMember(groupName, 'cid:' + cid + ':privileges:groups:topics:reply', next); + }, + 'groups:topics:read': function(next) { + groups.isMember(groupName, 'cid:' + cid + ':privileges:groups:topics:read', next); } }, callback); }; diff --git a/src/privileges/topics.js b/src/privileges/topics.js index 8a02800544..d1c8958045 100644 --- a/src/privileges/topics.js +++ b/src/privileges/topics.js @@ -21,6 +21,7 @@ module.exports = function(privileges) { topic = _topic; async.parallel({ 'topics:reply': async.apply(helpers.isUserAllowedTo, 'topics:reply', uid, [topic.cid]), + 'topics:read': async.apply(helpers.isUserAllowedTo, 'topics:read', uid, [topic.cid]), read: async.apply(helpers.isUserAllowedTo, 'read', uid, [topic.cid]), isOwner: function(next) { next(null, !!parseInt(uid, 10) && parseInt(uid, 10) === parseInt(topic.uid, 10)); @@ -44,6 +45,7 @@ module.exports = function(privileges) { plugins.fireHook('filter:privileges.topics.get', { 'topics:reply': (results['topics:reply'][0] && !locked) || isAdminOrMod, read: results.read[0] || isAdminOrMod, + 'topics:read': results['topics:read'][0] || isAdminOrMod, view_thread_tools: editable || deletable, editable: editable, deletable: deletable, diff --git a/src/routes/feeds.js b/src/routes/feeds.js index 09f3f1826e..3ceefbb4d6 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -38,7 +38,7 @@ function generateForTopic(req, res, callback) { if (parseInt(results.topic.deleted, 10) && !results.privileges.view_deleted) { return callback(); } - if (!results.privileges.read) { + if (!results.privileges.read || !results.privileges['topics:read']) { return helpers.notAllowed(req, res); } userPrivileges = results.privileges; diff --git a/src/upgrade.js b/src/upgrade.js index 1874db129e..0f863c757c 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -10,7 +10,7 @@ var db = require('./database'), schemaDate, thisSchemaDate, // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema - latestSchema = Date.UTC(2016, 3, 29); + latestSchema = Date.UTC(2016, 4, 28); Upgrade.check = function(callback) { db.get('schemaDate', function(err, value) { @@ -494,6 +494,75 @@ Upgrade.upgrade = function(callback) { winston.info('[2016/04/29] Dismiss flags from deleted topics skipped!'); next(); } + }, + function(next) { + thisSchemaDate = Date.UTC(2016, 4, 28); + + if (schemaDate < thisSchemaDate) { + updatesMade = true; + winston.info('[2016/05/28] Giving topics:read privs to any group that was previously allowed to Find & Access Category'); + + var groupsAPI = require('./groups'); + var privilegesAPI = require('./privileges'); + + db.getSortedSetRange('categories:cid', 0, -1, function(err, cids) { + async.eachSeries(cids, function(cid, next) { + privilegesAPI.categories.list(cid, function(err, data) { + var groups = data.groups; + var users = data.users; + + async.waterfall([ + function(next) { + async.eachSeries(groups, function(group, next) { + if (group.privileges['groups:read']) { + return groupsAPI.join('cid:' + cid + ':privileges:groups:topics:read', group.name, function(err) { + if (!err) { + winston.info('cid:' + cid + ':privileges:groups:topics:read granted to gid: ' + group.name); + } + + return next(err); + }); + } + + next(null); + }, next); + }, + function(next) { + async.eachSeries(users, function(user, next) { + if (user.privileges['read']) { + return groupsAPI.join('cid:' + cid + ':privileges:topics:read', user.uid, function(err) { + if (!err) { + winston.info('cid:' + cid + ':privileges:topics:read granted to uid: ' + user.uid); + } + + return next(err); + }); + } + + next(null); + }, next); + } + ], function(err) { + if (!err) { + winston.info('-- cid ' + cid + ' upgraded'); + } + + next(err); + }); + }); + }, function(err) { + if (err) { + return next(err); + } + + winston.info('[2016/05/28] Giving topics:read privs to any group that was previously allowed to Find & Access Category - done'); + Upgrade.update(thisSchemaDate, next); + }); + }); + } else { + winston.info('[2016/05/28] Giving topics:read privs to any group that was previously allowed to Find & Access Category - skipped!'); + next(); + } } // Add new schema updates here // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 24!!! diff --git a/src/views/admin/partials/categories/groups.tpl b/src/views/admin/partials/categories/groups.tpl index aa2da68cfc..eb432bfd27 100644 --- a/src/views/admin/partials/categories/groups.tpl +++ b/src/views/admin/partials/categories/groups.tpl @@ -5,8 +5,9 @@ Privileges diff --git a/src/views/admin/partials/categories/users.tpl b/src/views/admin/partials/categories/users.tpl index 40991fcf3a..9ec7c262fd 100644 --- a/src/views/admin/partials/categories/users.tpl +++ b/src/views/admin/partials/categories/users.tpl @@ -5,8 +5,9 @@ Privileges