mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-12 08:55:47 +01:00
closes #6912
- on category setParent dialog do not show children of current category - break recursion if category parentCid is equal to child cid to prevent infinite loop - dont allow setting the parentCid of a category to one of it's children
This commit is contained in:
@@ -240,8 +240,13 @@ define('admin/manage/category', [
|
|||||||
}
|
}
|
||||||
|
|
||||||
Category.launchParentSelector = function () {
|
Category.launchParentSelector = function () {
|
||||||
|
var parents = [parseInt(ajaxify.data.category.cid, 10)];
|
||||||
var categories = ajaxify.data.allCategories.filter(function (category) {
|
var categories = ajaxify.data.allCategories.filter(function (category) {
|
||||||
return category && !category.disabled && parseInt(category.cid, 10) !== parseInt(ajaxify.data.category.cid, 10);
|
var isChild = parents.includes(parseInt(category.parentCid, 10));
|
||||||
|
if (isChild) {
|
||||||
|
parents.push(parseInt(category.cid, 10));
|
||||||
|
}
|
||||||
|
return category && !category.disabled && parseInt(category.cid, 10) !== parseInt(ajaxify.data.category.cid, 10) && !isChild;
|
||||||
});
|
});
|
||||||
|
|
||||||
categorySelector.modal(categories, function (parentCid) {
|
categorySelector.modal(categories, function (parentCid) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
var db = require('../database');
|
var db = require('../database');
|
||||||
var user = require('../user');
|
var user = require('../user');
|
||||||
@@ -219,7 +220,13 @@ Categories.getChildren = function (cids, uid, callback) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async.each(categories, function (category, next) {
|
async.each(categories, function (category, next) {
|
||||||
|
Categories.getCategoryField(category.cid, 'parentCid', function (err, parentCid) {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
category.parentCid = parentCid;
|
||||||
getChildrenRecursive(category, uid, next);
|
getChildrenRecursive(category, uid, next);
|
||||||
|
});
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
callback(err, categories.map(function (c) {
|
callback(err, categories.map(function (c) {
|
||||||
return c && c.children;
|
return c && c.children;
|
||||||
@@ -263,12 +270,37 @@ function getChildrenRecursive(category, uid, callback) {
|
|||||||
},
|
},
|
||||||
function (next) {
|
function (next) {
|
||||||
async.each(category.children, function (child, next) {
|
async.each(category.children, function (child, next) {
|
||||||
|
if (parseInt(category.parentCid, 10) === parseInt(child.cid, 10)) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
getChildrenRecursive(child, uid, next);
|
getChildrenRecursive(child, uid, next);
|
||||||
}, next);
|
}, next);
|
||||||
},
|
},
|
||||||
], callback);
|
], callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Categories.getChildrenCids = function (rootCid, callback) {
|
||||||
|
function recursive(currentCid, callback) {
|
||||||
|
db.getSortedSetRange('cid:' + currentCid + ':children', 0, -1, function (err, childrenCids) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!childrenCids.length) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
async.eachSeries(childrenCids, function (childCid, next) {
|
||||||
|
allCids.push(parseInt(childCid, 10));
|
||||||
|
recursive(childCid, next);
|
||||||
|
}, callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var allCids = [];
|
||||||
|
recursive(rootCid, function (err) {
|
||||||
|
callback(err, _.uniq(allCids));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Categories.flattenCategories = function (allCategories, categoryData) {
|
Categories.flattenCategories = function (allCategories, categoryData) {
|
||||||
categoryData.forEach(function (category) {
|
categoryData.forEach(function (category) {
|
||||||
if (category) {
|
if (category) {
|
||||||
|
|||||||
@@ -92,6 +92,12 @@ module.exports = function (Categories) {
|
|||||||
}
|
}
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
|
Categories.getChildrenCids(cid, next);
|
||||||
|
},
|
||||||
|
function (childrenCids, next) {
|
||||||
|
if (childrenCids.includes(parseInt(newParent, 10))) {
|
||||||
|
return next(new Error('[[error:cant-set-child-as-parent]]'));
|
||||||
|
}
|
||||||
Categories.getCategoryField(cid, 'parentCid', next);
|
Categories.getCategoryField(cid, 'parentCid', next);
|
||||||
},
|
},
|
||||||
function (oldParent, next) {
|
function (oldParent, next) {
|
||||||
|
|||||||
@@ -338,6 +338,31 @@ describe('Categories', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should error if you try to set child as parent', function (done) {
|
||||||
|
var child1Cid;
|
||||||
|
var parentCid;
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
Categories.create({ name: 'parent 1', description: 'poor parent' }, next);
|
||||||
|
},
|
||||||
|
function (category, next) {
|
||||||
|
parentCid = category.cid;
|
||||||
|
Categories.create({ name: 'child1', description: 'wanna be parent', parentCid: parentCid }, next);
|
||||||
|
},
|
||||||
|
function (category, next) {
|
||||||
|
child1Cid = category.cid;
|
||||||
|
var updateData = {};
|
||||||
|
updateData[parentCid] = {
|
||||||
|
parentCid: child1Cid,
|
||||||
|
};
|
||||||
|
socketCategories.update({ uid: adminUid }, updateData, function (err) {
|
||||||
|
assert.equal(err.message, '[[error:cant-set-child-as-parent]]');
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
], done);
|
||||||
|
});
|
||||||
|
|
||||||
it('should update category data', function (done) {
|
it('should update category data', function (done) {
|
||||||
var updateData = {};
|
var updateData = {};
|
||||||
updateData[cid] = {
|
updateData[cid] = {
|
||||||
|
|||||||
Reference in New Issue
Block a user