mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 03:26:04 +01:00
closes #5127
This commit is contained in:
@@ -55,7 +55,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.4.13",
|
"nodebb-plugin-composer-default": "4.4.14",
|
||||||
"nodebb-plugin-dbsearch": "2.0.4",
|
"nodebb-plugin-dbsearch": "2.0.4",
|
||||||
"nodebb-plugin-emoji-extended": "1.1.1",
|
"nodebb-plugin-emoji-extended": "1.1.1",
|
||||||
"nodebb-plugin-emoji-one": "1.2.1",
|
"nodebb-plugin-emoji-one": "1.2.1",
|
||||||
|
|||||||
@@ -52,7 +52,18 @@ module.exports = function (Categories) {
|
|||||||
function (data, next) {
|
function (data, next) {
|
||||||
category = data.category;
|
category = data.category;
|
||||||
|
|
||||||
var defaultPrivileges = ['find', 'read', 'topics:read', 'topics:create', 'topics:reply', 'posts:edit', 'posts:delete', 'topics:delete', 'upload:post:image'];
|
var defaultPrivileges = [
|
||||||
|
'find',
|
||||||
|
'read',
|
||||||
|
'topics:read',
|
||||||
|
'topics:create',
|
||||||
|
'topics:reply',
|
||||||
|
'topics:tag',
|
||||||
|
'posts:edit',
|
||||||
|
'posts:delete',
|
||||||
|
'topics:delete',
|
||||||
|
'upload:post:image',
|
||||||
|
];
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
async.apply(db.setObject, 'category:' + category.cid, category),
|
async.apply(db.setObject, 'category:' + category.cid, category),
|
||||||
|
|||||||
@@ -48,9 +48,7 @@ module.exports = function (Posts) {
|
|||||||
},
|
},
|
||||||
function (result, next) {
|
function (result, next) {
|
||||||
postData = result.post;
|
postData = result.post;
|
||||||
Posts.setPostFields(data.pid, postData, next);
|
|
||||||
},
|
|
||||||
function (next) {
|
|
||||||
async.parallel({
|
async.parallel({
|
||||||
editor: function (next) {
|
editor: function (next) {
|
||||||
user.getUserFields(data.uid, ['username', 'userslug'], next);
|
user.getUserFields(data.uid, ['username', 'userslug'], next);
|
||||||
@@ -62,7 +60,9 @@ module.exports = function (Posts) {
|
|||||||
},
|
},
|
||||||
function (_results, next) {
|
function (_results, next) {
|
||||||
results = _results;
|
results = _results;
|
||||||
|
Posts.setPostFields(data.pid, postData, next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
postData.cid = results.topic.cid;
|
postData.cid = results.topic.cid;
|
||||||
postData.topic = results.topic;
|
postData.topic = results.topic;
|
||||||
plugins.fireHook('action:post.edit', { post: _.clone(postData), uid: data.uid });
|
plugins.fireHook('action:post.edit', { post: _.clone(postData), uid: data.uid });
|
||||||
@@ -123,6 +123,17 @@ module.exports = function (Posts) {
|
|||||||
|
|
||||||
data.tags = data.tags || [];
|
data.tags = data.tags || [];
|
||||||
|
|
||||||
|
if (!data.tags.length) {
|
||||||
|
return next(null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
privileges.categories.can('topics:tag', topicData.cid, data.uid, next);
|
||||||
|
},
|
||||||
|
function (canTag, next) {
|
||||||
|
if (!canTag) {
|
||||||
|
return next(new Error('[[error:no-privileges]]'));
|
||||||
|
}
|
||||||
|
|
||||||
plugins.fireHook('filter:topic.edit', { req: data.req, topic: topicData, data: data }, next);
|
plugins.fireHook('filter:topic.edit', { req: data.req, topic: topicData, data: data }, next);
|
||||||
},
|
},
|
||||||
function (results, next) {
|
function (results, next) {
|
||||||
|
|||||||
@@ -2,12 +2,29 @@
|
|||||||
|
|
||||||
var privileges = module.exports;
|
var privileges = module.exports;
|
||||||
|
|
||||||
|
privileges.privilegeLabels = [
|
||||||
|
{ name: 'Find Category' },
|
||||||
|
{ name: 'Access Category' },
|
||||||
|
{ name: 'Access Topics' },
|
||||||
|
{ name: 'Create Topics' },
|
||||||
|
{ name: 'Reply to Topics' },
|
||||||
|
{ name: 'Tag Topics' },
|
||||||
|
{ name: 'Edit Posts' },
|
||||||
|
{ name: 'Delete Posts' },
|
||||||
|
{ name: 'Delete Topics' },
|
||||||
|
{ name: 'Upload Images' },
|
||||||
|
{ name: 'Upload Files' },
|
||||||
|
{ name: 'Purge' },
|
||||||
|
{ name: 'Moderate' },
|
||||||
|
];
|
||||||
|
|
||||||
privileges.userPrivilegeList = [
|
privileges.userPrivilegeList = [
|
||||||
'find',
|
'find',
|
||||||
'read',
|
'read',
|
||||||
'topics:read',
|
'topics:read',
|
||||||
'topics:create',
|
'topics:create',
|
||||||
'topics:reply',
|
'topics:reply',
|
||||||
|
'topics:tag',
|
||||||
'posts:edit',
|
'posts:edit',
|
||||||
'posts:delete',
|
'posts:delete',
|
||||||
'topics:delete',
|
'topics:delete',
|
||||||
|
|||||||
@@ -16,28 +16,13 @@ module.exports = function (privileges) {
|
|||||||
privileges.categories.list = function (cid, callback) {
|
privileges.categories.list = function (cid, callback) {
|
||||||
// Method used in admin/category controller to show all users/groups with privs in that given cid
|
// Method used in admin/category controller to show all users/groups with privs in that given cid
|
||||||
|
|
||||||
var privilegeLabels = [
|
|
||||||
{ name: 'Find Category' },
|
|
||||||
{ name: 'Access Category' },
|
|
||||||
{ name: 'Access Topics' },
|
|
||||||
{ name: 'Create Topics' },
|
|
||||||
{ name: 'Reply to Topics' },
|
|
||||||
{ name: 'Edit Posts' },
|
|
||||||
{ name: 'Delete Posts' },
|
|
||||||
{ name: 'Delete Topics' },
|
|
||||||
{ name: 'Upload Images' },
|
|
||||||
{ name: 'Upload Files' },
|
|
||||||
{ name: 'Purge' },
|
|
||||||
{ name: 'Moderate' },
|
|
||||||
];
|
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
async.parallel({
|
async.parallel({
|
||||||
labels: function (next) {
|
labels: function (next) {
|
||||||
async.parallel({
|
async.parallel({
|
||||||
users: async.apply(plugins.fireHook, 'filter:privileges.list_human', privilegeLabels),
|
users: async.apply(plugins.fireHook, 'filter:privileges.list_human', privileges.privilegeLabels),
|
||||||
groups: async.apply(plugins.fireHook, 'filter:privileges.groups.list_human', privilegeLabels),
|
groups: async.apply(plugins.fireHook, 'filter:privileges.groups.list_human', privileges.privilegeLabels),
|
||||||
}, next);
|
}, next);
|
||||||
},
|
},
|
||||||
users: function (next) {
|
users: function (next) {
|
||||||
@@ -155,7 +140,7 @@ module.exports = function (privileges) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
privileges.categories.get = function (cid, uid, callback) {
|
privileges.categories.get = function (cid, uid, callback) {
|
||||||
var privs = ['topics:create', 'topics:read', 'read'];
|
var privs = ['topics:create', 'topics:read', 'topics:tag', 'read'];
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
async.parallel({
|
async.parallel({
|
||||||
@@ -177,6 +162,7 @@ module.exports = function (privileges) {
|
|||||||
plugins.fireHook('filter:privileges.categories.get', {
|
plugins.fireHook('filter:privileges.categories.get', {
|
||||||
'topics:create': privData['topics:create'] || isAdminOrMod,
|
'topics:create': privData['topics:create'] || isAdminOrMod,
|
||||||
'topics:read': privData['topics:read'] || isAdminOrMod,
|
'topics:read': privData['topics:read'] || isAdminOrMod,
|
||||||
|
'topics:tag': privData['topics:tag'] || isAdminOrMod,
|
||||||
read: privData.read || isAdminOrMod,
|
read: privData.read || isAdminOrMod,
|
||||||
cid: cid,
|
cid: cid,
|
||||||
uid: uid,
|
uid: uid,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ module.exports = function (privileges) {
|
|||||||
|
|
||||||
privileges.topics.get = function (tid, uid, callback) {
|
privileges.topics.get = function (tid, uid, callback) {
|
||||||
var topic;
|
var topic;
|
||||||
var privs = ['topics:reply', 'topics:read', 'topics:delete', 'posts:edit', 'posts:delete', 'read'];
|
var privs = ['topics:reply', 'topics:read', 'topics:tag', 'topics:delete', 'posts:edit', 'posts:delete', 'read'];
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
async.apply(topics.getTopicFields, tid, ['cid', 'uid', 'locked', 'deleted']),
|
async.apply(topics.getTopicFields, tid, ['cid', 'uid', 'locked', 'deleted']),
|
||||||
function (_topic, next) {
|
function (_topic, next) {
|
||||||
@@ -41,6 +41,7 @@ module.exports = function (privileges) {
|
|||||||
plugins.fireHook('filter:privileges.topics.get', {
|
plugins.fireHook('filter:privileges.topics.get', {
|
||||||
'topics:reply': (privData['topics:reply'] && !locked && !deleted) || isAdminOrMod,
|
'topics:reply': (privData['topics:reply'] && !locked && !deleted) || isAdminOrMod,
|
||||||
'topics:read': privData['topics:read'] || isAdminOrMod,
|
'topics:read': privData['topics:read'] || isAdminOrMod,
|
||||||
|
'topics:tag': privData['topics:tag'] || isAdminOrMod,
|
||||||
'topics:delete': (isOwner && privData['topics:delete']) || isAdminOrMod,
|
'topics:delete': (isOwner && privData['topics:delete']) || isAdminOrMod,
|
||||||
'posts:edit': (privData['posts:edit'] && !locked) || isAdminOrMod,
|
'posts:edit': (privData['posts:edit'] && !locked) || isAdminOrMod,
|
||||||
'posts:delete': (privData['posts:delete'] && !locked) || isAdminOrMod,
|
'posts:delete': (privData['posts:delete'] && !locked) || isAdminOrMod,
|
||||||
|
|||||||
@@ -107,18 +107,30 @@ module.exports = function (Topics) {
|
|||||||
check(data.content, meta.config.minimumPostLength, meta.config.maximumPostLength, 'content-too-short', 'content-too-long', next);
|
check(data.content, meta.config.minimumPostLength, meta.config.maximumPostLength, 'content-too-short', 'content-too-long', next);
|
||||||
},
|
},
|
||||||
function (next) {
|
function (next) {
|
||||||
categories.exists(data.cid, next);
|
async.parallel({
|
||||||
|
categoryExists: function (next) {
|
||||||
|
categories.exists(data.cid, next);
|
||||||
|
},
|
||||||
|
canCreate: function (next) {
|
||||||
|
privileges.categories.can('topics:create', data.cid, data.uid, next);
|
||||||
|
},
|
||||||
|
canTag: function (next) {
|
||||||
|
if (!data.tags.length) {
|
||||||
|
return next(null, true);
|
||||||
|
}
|
||||||
|
privileges.categories.can('topics:tag', data.cid, data.uid, next);
|
||||||
|
},
|
||||||
|
}, next);
|
||||||
},
|
},
|
||||||
function (categoryExists, next) {
|
function (results, next) {
|
||||||
if (!categoryExists) {
|
if (!results.categoryExists) {
|
||||||
return next(new Error('[[error:no-category]]'));
|
return next(new Error('[[error:no-category]]'));
|
||||||
}
|
}
|
||||||
privileges.categories.can('topics:create', data.cid, data.uid, next);
|
|
||||||
},
|
if (!results.canCreate || !results.canTag) {
|
||||||
function (canCreate, next) {
|
|
||||||
if (!canCreate) {
|
|
||||||
return next(new Error('[[error:no-privileges]]'));
|
return next(new Error('[[error:no-privileges]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
guestHandleValid(data, next);
|
guestHandleValid(data, next);
|
||||||
},
|
},
|
||||||
function (next) {
|
function (next) {
|
||||||
|
|||||||
22
src/upgrades/1.5.2/tags_privilege.js
Normal file
22
src/upgrades/1.5.2/tags_privilege.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
|
|
||||||
|
var batch = require('../../batch');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'Give tag privilege to registered-users on all categories',
|
||||||
|
timestamp: Date.UTC(2017, 5, 16),
|
||||||
|
method: function (callback) {
|
||||||
|
var progress = this.progress;
|
||||||
|
var privileges = require('../../privileges');
|
||||||
|
batch.processSortedSet('categories:cid', function (cids, next) {
|
||||||
|
async.eachSeries(cids, function (cid, next) {
|
||||||
|
progress.incr();
|
||||||
|
privileges.categories.give(['topics:tag'], cid, 'registered-users', next);
|
||||||
|
}, next);
|
||||||
|
}, {
|
||||||
|
progress: progress,
|
||||||
|
}, callback);
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -645,6 +645,7 @@ describe('Categories', function () {
|
|||||||
'topics:reply': false,
|
'topics:reply': false,
|
||||||
'topics:read': false,
|
'topics:read': false,
|
||||||
'topics:create': false,
|
'topics:create': false,
|
||||||
|
'topics:tag': false,
|
||||||
'topics:delete': false,
|
'topics:delete': false,
|
||||||
'posts:edit': false,
|
'posts:edit': false,
|
||||||
'upload:post:file': false,
|
'upload:post:file': false,
|
||||||
@@ -666,6 +667,7 @@ describe('Categories', function () {
|
|||||||
'groups:topics:delete': false,
|
'groups:topics:delete': false,
|
||||||
'groups:topics:create': true,
|
'groups:topics:create': true,
|
||||||
'groups:topics:reply': true,
|
'groups:topics:reply': true,
|
||||||
|
'groups:topics:tag': true,
|
||||||
'groups:posts:delete': true,
|
'groups:posts:delete': true,
|
||||||
'groups:read': true,
|
'groups:read': true,
|
||||||
'groups:topics:read': true,
|
'groups:topics:read': true,
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ var nconf = require('nconf');
|
|||||||
|
|
||||||
var db = require('./mocks/databasemock');
|
var db = require('./mocks/databasemock');
|
||||||
var topics = require('../src/topics');
|
var topics = require('../src/topics');
|
||||||
|
var posts = require('../src/posts');
|
||||||
var categories = require('../src/categories');
|
var categories = require('../src/categories');
|
||||||
|
var privileges = require('../src/privileges');
|
||||||
var meta = require('../src/meta');
|
var meta = require('../src/meta');
|
||||||
var User = require('../src/user');
|
var User = require('../src/user');
|
||||||
var groups = require('../src/groups');
|
var groups = require('../src/groups');
|
||||||
@@ -825,7 +827,7 @@ describe('Topic\'s', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should 404 if tid is not a number', function (done) {
|
it('should 404 if tid is not a number', function (done) {
|
||||||
request(nconf.get('url') + '/api/topic/teaser/nan', { json: true }, function (err, response, body) {
|
request(nconf.get('url') + '/api/topic/teaser/nan', { json: true }, function (err, response) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(response.statusCode, 404);
|
assert.equal(response.statusCode, 404);
|
||||||
done();
|
done();
|
||||||
@@ -858,7 +860,7 @@ describe('Topic\'s', function () {
|
|||||||
|
|
||||||
|
|
||||||
it('should 404 if tid is not a number', function (done) {
|
it('should 404 if tid is not a number', function (done) {
|
||||||
request(nconf.get('url') + '/api/topic/pagination/nan', { json: true }, function (err, response, body) {
|
request(nconf.get('url') + '/api/topic/pagination/nan', { json: true }, function (err, response) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(response.statusCode, 404);
|
assert.equal(response.statusCode, 404);
|
||||||
done();
|
done();
|
||||||
@@ -866,7 +868,7 @@ describe('Topic\'s', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should 404 if tid does not exist', function (done) {
|
it('should 404 if tid does not exist', function (done) {
|
||||||
request(nconf.get('url') + '/api/topic/pagination/1231231', { json: true }, function (err, response, body) {
|
request(nconf.get('url') + '/api/topic/pagination/1231231', { json: true }, function (err, response) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(response.statusCode, 404);
|
assert.equal(response.statusCode, 404);
|
||||||
done();
|
done();
|
||||||
@@ -1643,4 +1645,61 @@ describe('Topic\'s', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('tag privilege', function () {
|
||||||
|
var uid;
|
||||||
|
var cid;
|
||||||
|
before(function (done) {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
User.create({ username: 'tag_poster' }, next);
|
||||||
|
},
|
||||||
|
function (_uid, next) {
|
||||||
|
uid = _uid;
|
||||||
|
categories.create({ name: 'tag category' }, next);
|
||||||
|
},
|
||||||
|
function (categoryObj, next) {
|
||||||
|
cid = categoryObj.cid;
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
], done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail to post if user does not have tag privilege', function (done) {
|
||||||
|
privileges.categories.rescind(['topics:tag'], cid, 'registered-users', function (err) {
|
||||||
|
assert.ifError(err);
|
||||||
|
topics.post({ uid: uid, cid: cid, tags: ['tag1'], title: 'topic with tags', content: 'some content here' }, function (err) {
|
||||||
|
assert.equal(err.message, '[[error:no-privileges]]');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail to edit if user does not have tag privilege', function (done) {
|
||||||
|
topics.post({ uid: uid, cid: cid, title: 'topic with tags', content: 'some content here' }, function (err, result) {
|
||||||
|
assert.ifError(err);
|
||||||
|
var pid = result.postData.pid;
|
||||||
|
posts.edit({ pid: pid, uid: uid, content: 'edited content', tags: ['tag2'] }, function (err) {
|
||||||
|
assert.equal(err.message, '[[error:no-privileges]]');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to edit topic and add tags if allowed', function (done) {
|
||||||
|
privileges.categories.give(['topics:tag'], cid, 'registered-users', function (err) {
|
||||||
|
assert.ifError(err);
|
||||||
|
topics.post({ uid: uid, cid: cid, tags: ['tag1'], title: 'topic with tags', content: 'some content here' }, function (err, result) {
|
||||||
|
assert.ifError(err);
|
||||||
|
posts.edit({ pid: result.postData.pid, uid: uid, content: 'edited content', tags: ['tag1', 'tag2'] }, function (err, result) {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.deepEqual(result.topic.tags.map(function (tag) {
|
||||||
|
return tag.value;
|
||||||
|
}), ['tag1', 'tag2']);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user