category whitelist for replying to posts, lots of refactoring, too

v1.18.x
Julian Lam 11 years ago
parent 182659d0e1
commit 5ee5c8179a

@ -171,28 +171,6 @@ var RDB = require('./redis.js'),
}); });
}; };
Categories.privileges = function(cid, uid, callback) {
function isModerator(next) {
user.isModerator(uid, cid, function(isMod) {
next(null, isMod);
});
}
function isAdministrator(next) {
user.isAdministrator(uid, function(isAdmin) {
next(null, isAdmin);
});
}
async.parallel([isModerator, isAdministrator], function(err, results) {
callback({
editable: results.indexOf(true) !== -1 ? true : false,
view_deleted: results.indexOf(true) !== -1 ? true : false
});
});
};
Categories.isTopicsRead = function(cid, uid, callback) { Categories.isTopicsRead = function(cid, uid, callback) {
RDB.zrange('categories:' + cid + ':tid', 0, -1, function(err, tids) { RDB.zrange('categories:' + cid + ':tid', 0, -1, function(err, tids) {

@ -0,0 +1,32 @@
var Groups = require('./groups'),
User = require('./user'),
async = require('async'),
CategoryTools = {};
CategoryTools.privileges = function(cid, uid, callback) {
async.parallel({
"+r": function(next) {
Groups.isMemberByGroupName(uid, 'cid:' + cid + ':privileges:+r', next);
},
"+w": function(next) {
Groups.isMemberByGroupName(uid, 'cid:' + cid + ':privileges:+w', next);
},
moderator: function(next) {
User.isModerator(uid, cid, next);
},
admin: function(next) {
User.isAdministrator(uid, next);
}
}, function(err, privileges) {
callback(err, !privileges ? null : {
read: privileges['+r'] || privileges.moderator || privileges.admin,
write: privileges['+w'] || privileges.moderator || privileges.admin,
editable: privileges.moderator || privileges.admin,
view_deleted: privileges.moderator || privileges.admin
});
});
};
module.exports = CategoryTools;

@ -108,8 +108,6 @@
}; };
Feed.updateRecent = function(callback) { Feed.updateRecent = function(callback) {
console.log('entered');
if (process.env.NODE_ENV === 'development') winston.info('[rss] Updating Recent Posts RSS feed');
topics.getLatestTopics(0, 0, 19, undefined, function (err, recentData) { topics.getLatestTopics(0, 0, 19, undefined, function (err, recentData) {
var feed = new rss({ var feed = new rss({
title: 'Recently Active Topics', title: 'Recently Active Topics',

@ -36,9 +36,7 @@ var RDB = require('./redis'),
function getThreadPrivileges(next) { function getThreadPrivileges(next) {
posts.getPostField(pid, 'tid', function(err, tid) { posts.getPostField(pid, 'tid', function(err, tid) {
threadTools.privileges(tid, uid, function(privileges) { threadTools.privileges(tid, uid, next);
next(null, privileges);
});
}); });
} }

@ -1,19 +1,20 @@
var RDB = require('./redis.js'), var RDB = require('./redis'),
utils = require('./../public/src/utils.js'), utils = require('./../public/src/utils'),
user = require('./user.js'), user = require('./user'),
topics = require('./topics.js'), topics = require('./topics'),
categories = require('./categories.js'), categories = require('./categories'),
favourites = require('./favourites.js'), favourites = require('./favourites'),
threadTools = require('./threadTools.js'), threadTools = require('./threadTools'),
postTools = require('./postTools'), postTools = require('./postTools'),
categories = require('./categories'), categories = require('./categories'),
feed = require('./feed.js'), feed = require('./feed'),
async = require('async'),
plugins = require('./plugins'), plugins = require('./plugins'),
meta = require('./meta'),
async = require('async'),
reds = require('reds'), reds = require('reds'),
postSearch = reds.createSearch('nodebbpostsearch'), postSearch = reds.createSearch('nodebbpostsearch'),
nconf = require('nconf'), nconf = require('nconf'),
meta = require('./meta.js'),
validator = require('validator'), validator = require('validator'),
winston = require('winston'); winston = require('winston');
@ -125,13 +126,15 @@ var RDB = require('./redis.js'),
}; };
Posts.reply = function(tid, uid, content, callback) { Posts.reply = function(tid, uid, content, callback) {
threadTools.privileges(tid, uid, function(err, privileges) {
if (content) { if (content) {
content = content.trim(); content = content.trim();
} }
if (!content || content.length < meta.config.minimumPostLength) { if (!content || content.length < meta.config.minimumPostLength) {
callback(new Error('content-too-short'), null); return callback(new Error('content-too-short'));
return; } else if (!privileges.write) {
return callback(new Error('no-privileges'));
} }
Posts.create(uid, tid, content, function(err, postData) { Posts.create(uid, tid, content, function(err, postData) {
@ -181,6 +184,7 @@ var RDB = require('./redis.js'),
callback(null, postData); callback(null, postData);
}); });
}); });
});
} }
Posts.getPostsByTid = function(tid, start, end, callback) { Posts.getPostsByTid = function(tid, start, end, callback) {

@ -130,7 +130,7 @@ var user = require('./../user.js'),
var uid = (req.user) ? req.user.uid : 0; var uid = (req.user) ? req.user.uid : 0;
// Category Whitelisting (support for "-r" to come later) // Category Whitelisting (support for "-r" to come later)
var whitelistReadKey = 'cid:' + req.params.id + ':permissions:+r', var whitelistReadKey = 'cid:' + req.params.id + ':privileges:+r',
success = function() { success = function() {
categories.getCategoryById(req.params.id, uid, function (err, data) { categories.getCategoryById(req.params.id, uid, function (err, data) {
if (!err && data && data.disabled === "0") if (!err && data && data.disabled === "0")

@ -55,15 +55,6 @@ var DebugRoute = function(app) {
}); });
}); });
app.get('/prune', function(req, res) {
var Notifications = require('../notifications');
Notifications.prune(new Date(), function() {
console.log('done');
});
res.send();
});
app.get('/uuidtest', function(req, res) { app.get('/uuidtest', function(req, res) {
var Utils = require('../../public/src/utils.js'); var Utils = require('../../public/src/utils.js');

@ -1,16 +1,18 @@
var RDB = require('./redis.js'), var RDB = require('./redis'),
topics = require('./topics.js'), topics = require('./topics'),
categories = require('./categories.js'), categories = require('./categories'),
user = require('./user.js'), CategoryTools = require('./categoryTools'),
user = require('./user'),
async = require('async'), async = require('async'),
notifications = require('./notifications.js'), notifications = require('./notifications'),
posts = require('./posts'), posts = require('./posts'),
meta = require('./meta'),
websockets = require('./websockets');
reds = require('reds'), reds = require('reds'),
topicSearch = reds.createSearch('nodebbtopicsearch'), topicSearch = reds.createSearch('nodebbtopicsearch'),
winston = require('winston'), winston = require('winston'),
meta = require('./meta'),
nconf = require('nconf'), nconf = require('nconf'),
websockets = require('./websockets');
(function(ThreadTools) { (function(ThreadTools) {
@ -22,28 +24,24 @@ var RDB = require('./redis.js'),
} }
ThreadTools.privileges = function(tid, uid, callback) { ThreadTools.privileges = function(tid, uid, callback) {
//todo: break early if one condition is true async.parallel({
categoryPrivs: function(next) {
function getCategoryPrivileges(next) {
topics.getTopicField(tid, 'cid', function(err, cid) { topics.getTopicField(tid, 'cid', function(err, cid) {
categories.privileges(cid, uid, function(privileges) { CategoryTools.privileges(cid, uid, next);
next(null, privileges);
});
}); });
} },
hasEnoughRep: function(next) {
function hasEnoughRep(next) {
user.getUserField(uid, 'reputation', function(err, reputation) { user.getUserField(uid, 'reputation', function(err, reputation) {
if (err) return next(null, false); if (err) return next(null, false);
next(null, parseInt(reputation, 10) >= parseInt(meta.config['privileges:manage_topic'], 10)); next(null, parseInt(reputation, 10) >= parseInt(meta.config['privileges:manage_topic'], 10));
}); });
} }
}, function(err, results) {
callback(err, !results ? undefined : {
async.parallel([getCategoryPrivileges, hasEnoughRep], function(err, results) { read: results.categoryPrivs.read,
callback({ write: results.categoryPrivs.write,
editable: results[0].editable || results[1], editable: results.categoryPrivs.editable || results.hasEnoughRep,
view_deleted: results[0].view_deleted || results[1] view_deleted: results.categoryPrivs.view_deleted || results.hasEnoughRep
}); });
}); });
} }

@ -2,16 +2,17 @@ var RDB = require('./redis'),
posts = require('./posts'), posts = require('./posts'),
utils = require('./../public/src/utils'), utils = require('./../public/src/utils'),
user = require('./user'), user = require('./user'),
Groups = require('./groups')
categories = require('./categories'), categories = require('./categories'),
CategoryTools = require('./categoryTools'),
posts = require('./posts'), posts = require('./posts'),
threadTools = require('./threadTools'), threadTools = require('./threadTools'),
postTools = require('./postTools'), postTools = require('./postTools'),
notifications = require('./notifications'), notifications = require('./notifications'),
async = require('async'),
feed = require('./feed'), feed = require('./feed'),
favourites = require('./favourites'), favourites = require('./favourites'),
meta = require('./meta'), meta = require('./meta'),
async = require('async'),
reds = require('reds'), reds = require('reds'),
topicSearch = reds.createSearch('nodebbtopicsearch'), topicSearch = reds.createSearch('nodebbtopicsearch'),
nconf = require('nconf'), nconf = require('nconf'),
@ -20,6 +21,8 @@ var RDB = require('./redis'),
(function(Topics) { (function(Topics) {
Topics.post = function(uid, title, content, category_id, callback) { Topics.post = function(uid, title, content, category_id, callback) {
CategoryTools.privileges(category_id, uid, function(err, privileges) {
if (privileges.write) {
if (!category_id) if (!category_id)
throw new Error('Attempted to post without a category_id'); throw new Error('Attempted to post without a category_id');
@ -113,6 +116,10 @@ var RDB = require('./redis'),
}); });
}); });
}); });
} else {
callback(new Error('no-privileges'));
}
});
}; };
Topics.getTopicData = function(tid, callback) { Topics.getTopicData = function(tid, callback) {
@ -403,7 +410,7 @@ var RDB = require('./redis'),
// temporary. I don't think this call should belong here // temporary. I don't think this call should belong here
function getPrivileges(next) { function getPrivileges(next) {
categories.privileges(category_id, current_user, function(user_privs) { CategoryTools.privileges(category_id, current_user, function(user_privs) {
next(null, user_privs); next(null, user_privs);
}); });
} }
@ -486,27 +493,25 @@ var RDB = require('./redis'),
function getTopicData(next) { function getTopicData(next) {
Topics.getTopicData(tid, next); Topics.getTopicData(tid, next);
} };
function getTopicPosts(next) { function getTopicPosts(next) {
Topics.getTopicPosts(tid, start, end, current_user, function(topicPosts, privileges) { Topics.getTopicPosts(tid, start, end, current_user, function(topicPosts) {
next(null, topicPosts); next(null, topicPosts);
}); });
} };
function getPrivileges(next) { function getPrivileges(next) {
threadTools.privileges(tid, current_user, function(privData) { threadTools.privileges(tid, current_user, next);
next(null, privData); };
});
}
function getCategoryData(next) { function getCategoryData(next) {
Topics.getCategoryData(tid, next); Topics.getCategoryData(tid, next);
} };
async.parallel([getTopicData, getTopicPosts, getPrivileges, getCategoryData], function(err, results) { async.parallel([getTopicData, getTopicPosts, getPrivileges, getCategoryData], function(err, results) {
if (err) { if (err) {
console.log(err.message); winston.error('[Topics.getTopicWithPosts] Could not retrieve topic data: ', err.message);
callback(err, null); callback(err, null);
return; return;
} }

@ -723,14 +723,14 @@ var bcrypt = require('bcrypt'),
User.isModerator = function(uid, cid, callback) { User.isModerator = function(uid, cid, callback) {
RDB.sismember('cid:' + cid + ':moderators', uid, function(err, exists) { RDB.sismember('cid:' + cid + ':moderators', uid, function(err, exists) {
RDB.handle(err); RDB.handle(err);
callback( !! exists); callback(err, !! exists);
}); });
}; };
User.isAdministrator = function(uid, callback) { User.isAdministrator = function(uid, callback) {
Groups.getGidFromName('Administrators', function(err, gid) { Groups.getGidFromName('Administrators', function(err, gid) {
Groups.isMember(uid, gid, function(err, isAdmin) { Groups.isMember(uid, gid, function(err, isAdmin) {
callback( !! isAdmin); callback(err, !! isAdmin);
}); });
}); });
}; };

@ -364,6 +364,13 @@ module.exports.init = function(io) {
posts.emitContentTooShortAlert(socket); posts.emitContentTooShortAlert(socket);
} else if (err.message === 'too-many-posts') { } else if (err.message === 'too-many-posts') {
posts.emitTooManyPostsAlert(socket); posts.emitTooManyPostsAlert(socket);
} else if (err.message === 'no-privileges') {
socket.emit('event:alert', {
title: 'Unable to post',
message: 'You do not have posting privileges in this category.',
type: 'danger',
timeout: 7500
});
} else { } else {
socket.emit('event:alert', { socket.emit('event:alert', {
title: 'Error', title: 'Error',
@ -423,7 +430,6 @@ module.exports.init = function(io) {
posts.reply(data.topic_id, uid, data.content, function(err, postData) { posts.reply(data.topic_id, uid, data.content, function(err, postData) {
if(err) { if(err) {
if (err.message === 'content-too-short') { if (err.message === 'content-too-short') {
posts.emitContentTooShortAlert(socket); posts.emitContentTooShortAlert(socket);
} else if (err.message === 'too-many-posts') { } else if (err.message === 'too-many-posts') {
@ -435,6 +441,13 @@ module.exports.init = function(io) {
type: 'warning', type: 'warning',
timeout: 2000 timeout: 2000
}); });
} else if (err.message === 'no-privileges') {
socket.emit('event:alert', {
title: 'Unable to post',
message: 'You do not have posting privileges in this category.',
type: 'danger',
timeout: 7500
});
} }
return; return;
} }
@ -495,8 +508,8 @@ module.exports.init = function(io) {
}); });
socket.on('api:topic.delete', function(data) { socket.on('api:topic.delete', function(data) {
threadTools.privileges(data.tid, uid, function(privileges) { threadTools.privileges(data.tid, uid, function(err, privileges) {
if (privileges.editable) { if (!err && privileges.editable) {
threadTools.delete(data.tid, function(err) { threadTools.delete(data.tid, function(err) {
if (!err) { if (!err) {
emitTopicPostStats(); emitTopicPostStats();
@ -511,8 +524,8 @@ module.exports.init = function(io) {
}); });
socket.on('api:topic.restore', function(data) { socket.on('api:topic.restore', function(data) {
threadTools.privileges(data.tid, uid, function(privileges) { threadTools.privileges(data.tid, uid, function(err, privileges) {
if (privileges.editable) { if (!err && privileges.editable) {
threadTools.restore(data.tid, socket, function(err) { threadTools.restore(data.tid, socket, function(err) {
emitTopicPostStats(); emitTopicPostStats();
@ -526,32 +539,32 @@ module.exports.init = function(io) {
}); });
socket.on('api:topic.lock', function(data) { socket.on('api:topic.lock', function(data) {
threadTools.privileges(data.tid, uid, function(privileges) { threadTools.privileges(data.tid, uid, function(err, privileges) {
if (privileges.editable) { if (!err && privileges.editable) {
threadTools.lock(data.tid, socket); threadTools.lock(data.tid, socket);
} }
}); });
}); });
socket.on('api:topic.unlock', function(data) { socket.on('api:topic.unlock', function(data) {
threadTools.privileges(data.tid, uid, function(privileges) { threadTools.privileges(data.tid, uid, function(err, privileges) {
if (privileges.editable) { if (!err && privileges.editable) {
threadTools.unlock(data.tid, socket); threadTools.unlock(data.tid, socket);
} }
}); });
}); });
socket.on('api:topic.pin', function(data) { socket.on('api:topic.pin', function(data) {
threadTools.privileges(data.tid, uid, function(privileges) { threadTools.privileges(data.tid, uid, function(err, privileges) {
if (privileges.editable) { if (!err && privileges.editable) {
threadTools.pin(data.tid, socket); threadTools.pin(data.tid, socket);
} }
}); });
}); });
socket.on('api:topic.unpin', function(data) { socket.on('api:topic.unpin', function(data) {
threadTools.privileges(data.tid, uid, function(privileges) { threadTools.privileges(data.tid, uid, function(err, privileges) {
if (privileges.editable) { if (!err && privileges.editable) {
threadTools.unpin(data.tid, socket); threadTools.unpin(data.tid, socket);
} }
}); });

Loading…
Cancel
Save